]> git.tdb.fi Git - libs/gl.git/blob - source/backends/opengl/vertexsetup_backend.cpp
Check the flat qualifier from the correct member
[libs/gl.git] / source / backends / opengl / vertexsetup_backend.cpp
1 #include <algorithm>
2 #include <msp/gl/extensions/arb_direct_state_access.h>
3 #include <msp/gl/extensions/arb_instanced_arrays.h>
4 #include <msp/gl/extensions/arb_vertex_array_object.h>
5 #include <msp/gl/extensions/arb_vertex_attrib_binding.h>
6 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
7 #include <msp/gl/extensions/arb_vertex_shader.h>
8 #include <msp/gl/extensions/ext_gpu_shader4.h>
9 #include <msp/gl/extensions/khr_debug.h>
10 #include "buffer.h"
11 #include "vertexarray.h"
12 #include "vertexformat.h"
13 #include "vertexsetup.h"
14 #include "vertexsetup_backend.h"
15
16 using namespace std;
17
18 namespace Msp {
19 namespace GL {
20
21 OpenGLVertexSetup::OpenGLVertexSetup()
22 {
23         static Require req(ARB_vertex_array_object);
24         if(ARB_direct_state_access)
25                 glCreateVertexArrays(1, &id);
26         else
27                 glGenVertexArrays(1, &id);
28 }
29
30 OpenGLVertexSetup::OpenGLVertexSetup(OpenGLVertexSetup &&other):
31         id(other.id)
32 {
33         other.id = 0;
34 }
35
36 OpenGLVertexSetup::~OpenGLVertexSetup()
37 {
38         if(id)
39                 glDeleteVertexArrays(1, &id);
40 }
41
42 void OpenGLVertexSetup::require_format(const VertexFormat &fmt, bool instanced)
43 {
44         if(any_of(fmt.begin(), fmt.end(), is_integer_attribute))
45                 static Require _req(EXT_gpu_shader4);
46         if(instanced)
47                 static Require req(ARB_instanced_arrays);
48 }
49
50 void OpenGLVertexSetup::update(unsigned mask) const
51 {
52         static bool direct = ARB_direct_state_access && ARB_vertex_attrib_binding;
53
54         const VertexSetup &self = *static_cast<const VertexSetup *>(this);
55
56         if(mask&VertexSetup::VERTEX_ARRAY)
57                 update_vertex_array(*self.vertex_array, 0, 0, direct);
58
59         if(mask&VertexSetup::INSTANCE_ARRAY)
60                 update_vertex_array(*self.inst_array, 1, 1, direct);
61
62         if(mask&VertexSetup::INDEX_BUFFER)
63         {
64                 unsigned buf_id = self.index_buffer->id;
65                 if(direct)
66                         glVertexArrayElementBuffer(id, buf_id);
67                 else
68                         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf_id);
69         }
70 }
71
72 void OpenGLVertexSetup::update_vertex_array(const VertexArray &array, unsigned binding, unsigned divisor, bool direct) const
73 {
74         if(!direct)
75         {
76                 OpenGLBuffer::unbind_scratch();
77                 glBindBuffer(GL_ARRAY_BUFFER, array.get_buffer()->id);
78         }
79
80         const VertexFormat &fmt = array.get_format();
81         unsigned stride = fmt.stride();
82         if(direct)
83         {
84                 glVertexArrayVertexBuffer(id, binding, array.get_buffer()->id, 0, stride);
85                 glVertexArrayBindingDivisor(id, binding, divisor);
86         }
87
88         unsigned offset = array.get_offset();
89         for(VertexAttribute a: fmt)
90         {
91                 unsigned sem = get_attribute_semantic(a);
92                 if(!is_padding(a))
93                 {
94                         bool integer = is_integer_attribute(a);
95                         GLenum type = get_gl_type(get_attribute_source_type(a));
96                         unsigned cc = get_attribute_component_count(a);
97                         if(direct)
98                         {
99                                 if(integer)
100                                         glVertexArrayAttribIFormat(id, sem, cc, type, offset);
101                                 else
102                                         glVertexArrayAttribFormat(id, sem, cc, type, true, offset);
103                                 glVertexArrayAttribBinding(id, sem, binding);
104                                 glEnableVertexArrayAttrib(id, sem);
105                         }
106                         else
107                         {
108                                 if(integer)
109                                         glVertexAttribIPointer(sem, cc, type, stride, reinterpret_cast<void *>(offset));
110                                 else
111                                         glVertexAttribPointer(sem, cc, type, true, stride, reinterpret_cast<void *>(offset));
112                                 if(ARB_instanced_arrays)
113                                         glVertexAttribDivisor(sem, divisor);
114                                 glEnableVertexAttribArray(sem);
115                         }
116                 }
117                 offset += get_attribute_size(a);
118         }
119
120         if(!direct)
121                 glBindBuffer(GL_ARRAY_BUFFER, 0);
122 }
123
124 void OpenGLVertexSetup::unload()
125 {
126         if(ARB_direct_state_access)
127         {
128                 glVertexArrayVertexBuffer(id, 0, 0, 0, 0);
129                 glVertexArrayVertexBuffer(id, 1, 0, 0, 0);
130                 glVertexArrayElementBuffer(id, 0);
131         }
132         else
133         {
134                 const VertexSetup &self = *static_cast<const VertexSetup *>(this);
135
136                 glBindVertexArray(id);
137                 glBindBuffer(GL_ARRAY_BUFFER, 0);
138
139                 for(VertexAttribute a: self.vertex_format)
140                         if(!is_padding(a))
141                         {
142                                 unsigned sem = get_attribute_semantic(a);
143                                 glDisableVertexAttribArray(sem);
144                                 glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
145                         }
146                 for(VertexAttribute a: self.inst_format)
147                         if(!is_padding(a))
148                         {
149                                 unsigned sem = get_attribute_semantic(a);
150                                 glDisableVertexAttribArray(sem);
151                                 glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
152                         }
153
154                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
155         }
156 }
157
158 void OpenGLVertexSetup::set_debug_name(const string &name)
159 {
160 #ifdef DEBUG
161         if(KHR_debug)
162                 glObjectLabel(GL_VERTEX_ARRAY, id, name.size(), name.c_str());
163 #else
164         (void)name;
165 #endif
166 }
167
168 } // namespace GL
169 } // namespace Msp