]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/opengl/vertexsetup_backend.cpp
Move all OpenGL-specific code to a separate directory
[libs/gl.git] / source / backends / opengl / vertexsetup_backend.cpp
diff --git a/source/backends/opengl/vertexsetup_backend.cpp b/source/backends/opengl/vertexsetup_backend.cpp
new file mode 100644 (file)
index 0000000..90189db
--- /dev/null
@@ -0,0 +1,153 @@
+#include <algorithm>
+#include <msp/gl/extensions/arb_direct_state_access.h>
+#include <msp/gl/extensions/arb_instanced_arrays.h>
+#include <msp/gl/extensions/arb_vertex_array_object.h>
+#include <msp/gl/extensions/arb_vertex_attrib_binding.h>
+#include <msp/gl/extensions/arb_vertex_buffer_object.h>
+#include <msp/gl/extensions/arb_vertex_shader.h>
+#include <msp/gl/extensions/ext_gpu_shader4.h>
+#include <msp/gl/extensions/khr_debug.h>
+#include "buffer.h"
+#include "vertexarray.h"
+#include "vertexformat.h"
+#include "vertexsetup.h"
+#include "vertexsetup_backend.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+OpenGLVertexSetup::OpenGLVertexSetup()
+{
+       static Require req(ARB_vertex_array_object);
+       if(ARB_direct_state_access)
+               glCreateVertexArrays(1, &id);
+       else
+               glGenVertexArrays(1, &id);
+}
+
+OpenGLVertexSetup::~OpenGLVertexSetup()
+{
+       glDeleteVertexArrays(1, &id);
+}
+
+void OpenGLVertexSetup::require_format(const VertexFormat &fmt, bool instanced)
+{
+       if(any_of(fmt.begin(), fmt.end(), is_integer_attribute))
+               static Require _req(EXT_gpu_shader4);
+       if(instanced)
+               static Require req(ARB_instanced_arrays);
+}
+
+void OpenGLVertexSetup::update(unsigned mask) const
+{
+       static bool direct = ARB_direct_state_access && ARB_vertex_attrib_binding;
+
+       if(mask&VertexSetup::VERTEX_ARRAY)
+               update_vertex_array(*static_cast<const VertexSetup *>(this)->vertex_array, 0, 0, direct);
+
+       if(mask&VertexSetup::INSTANCE_ARRAY)
+               update_vertex_array(*static_cast<const VertexSetup *>(this)->inst_array, 1, 1, direct);
+
+       if(mask&VertexSetup::INDEX_BUFFER)
+       {
+               unsigned buf_id = static_cast<const VertexSetup *>(this)->index_buffer->id;
+               if(direct)
+                       glVertexArrayElementBuffer(id, buf_id);
+               else
+                       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf_id);
+       }
+}
+
+void OpenGLVertexSetup::update_vertex_array(const VertexArray &array, unsigned binding, unsigned divisor, bool direct) const
+{
+       if(!direct)
+       {
+               OpenGLBuffer::unbind_scratch();
+               glBindBuffer(GL_ARRAY_BUFFER, array.get_buffer()->id);
+       }
+
+       const VertexFormat &fmt = array.get_format();
+       unsigned stride = fmt.stride();
+       if(direct)
+       {
+               glVertexArrayVertexBuffer(id, binding, array.get_buffer()->id, 0, stride);
+               glVertexArrayBindingDivisor(id, binding, divisor);
+       }
+
+       unsigned offset = 0;
+       for(VertexAttribute a: fmt)
+       {
+               unsigned sem = get_attribute_semantic(a);
+               bool integer = is_integer_attribute(a);
+               GLenum type = get_gl_type(get_attribute_source_type(a));
+               unsigned cc = get_attribute_component_count(a);
+               if(direct)
+               {
+                       if(integer)
+                               glVertexArrayAttribIFormat(id, sem, cc, type, offset);
+                       else
+                               glVertexArrayAttribFormat(id, sem, cc, type, true, offset);
+                       glVertexArrayAttribBinding(id, sem, binding);
+                       glEnableVertexArrayAttrib(id, sem);
+               }
+               else
+               {
+                       if(integer)
+                               glVertexAttribIPointer(sem, cc, type, stride, reinterpret_cast<void *>(offset));
+                       else
+                               glVertexAttribPointer(sem, cc, type, true, stride, reinterpret_cast<void *>(offset));
+                       if(ARB_instanced_arrays)
+                               glVertexAttribDivisor(sem, divisor);
+                       glEnableVertexAttribArray(sem);
+               }
+               offset += get_attribute_size(a);
+       }
+
+       if(!direct)
+               glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+void OpenGLVertexSetup::unload()
+{
+       if(ARB_direct_state_access)
+       {
+               glVertexArrayVertexBuffer(id, 0, 0, 0, 0);
+               glVertexArrayVertexBuffer(id, 1, 0, 0, 0);
+               glVertexArrayElementBuffer(id, 0);
+       }
+       else
+       {
+               glBindVertexArray(id);
+               glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+               for(VertexAttribute a: static_cast<const VertexSetup *>(this)->vertex_format)
+               {
+                       unsigned sem = get_attribute_semantic(a);
+                       glDisableVertexAttribArray(sem);
+                       glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
+               }
+               for(VertexAttribute a: static_cast<const VertexSetup *>(this)->inst_format)
+               {
+                       unsigned sem = get_attribute_semantic(a);
+                       glDisableVertexAttribArray(sem);
+                       glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
+               }
+
+               glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+       }
+}
+
+void OpenGLVertexSetup::set_debug_name(const string &name)
+{
+#ifdef DEBUG
+       if(KHR_debug)
+               glObjectLabel(GL_VERTEX_ARRAY, id, name.size(), name.c_str());
+#else
+       (void)name;
+#endif
+}
+
+} // namespace GL
+} // namespace Msp