]> git.tdb.fi Git - libs/gl.git/blob - source/vertexarray.cpp
Allow setting uniform values using a Uniform object
[libs/gl.git] / source / vertexarray.cpp
1 #include <msp/gl/extensions/arb_multitexture.h>
2 #include <msp/gl/extensions/arb_vertex_shader.h>
3 #include <msp/gl/extensions/msp_legacy_features.h>
4 #include "buffer.h"
5 #include "error.h"
6 #include "gl.h"
7 #include "mesh.h"
8 #include "vertexarray.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 bool VertexArray::legacy_used = false;
16
17 VertexArray::VertexArray(const VertexFormat &f)
18 {
19         reset(f);
20 }
21
22 VertexArray::~VertexArray()
23 {
24         /* Unbind accesses the current VertexArray, so a call from ~Bindable would
25         try to access destroyed data. */
26         if(current()==this)
27                 unbind();
28 }
29
30 void VertexArray::reset(const VertexFormat &f)
31 {
32         clear();
33         format = f;
34         stride = get_stride(format);
35         legacy = false;
36
37         arrays.clear();
38
39         unsigned offs = 0;
40         for(const unsigned char *c=format.begin(); c!=format.end(); ++c)
41         {
42                 unsigned slot = get_array_slot(*c);
43                 if(slot>=arrays.size())
44                         arrays.resize(slot+1);
45
46                 Array &arr = arrays[slot];
47                 arr.component = *c;
48                 arr.offset = offs;
49
50                 if(*c<ATTRIB1)
51                         legacy = true;
52
53                 offs += get_component_size(*c);
54         }
55 }
56
57 unsigned VertexArray::get_array_slot(unsigned char comp)
58 {
59         unsigned t = get_component_type(comp);
60         if(t==get_component_type(VERTEX3))
61                 return 0;
62         else if(t==get_component_type(NORMAL3))
63                 return 1;
64         else if(t==get_component_type(COLOR4_FLOAT))
65                 return 2;
66         else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
67         {
68                 t -= get_component_type(TEXCOORD1);
69                 if(t>0)
70                         static Require _req(ARB_multitexture);
71                 return 3+t;
72         }
73         else
74         {
75                 static Require _req(ARB_vertex_shader);
76                 if(comp>=ATTRIB1)
77                         t -= get_component_type(ATTRIB1);
78                 return 7+t;
79         }
80 }
81
82 void VertexArray::clear()
83 {
84         data.clear();
85 }
86
87 void VertexArray::reserve(unsigned n)
88 {
89         data.reserve(n*stride);
90 }
91
92 float *VertexArray::append()
93 {
94         data.insert(data.end(), stride, 0.0f);
95         update_offset();
96         dirty = true;
97         return &*(data.end()-stride);
98 }
99
100 float *VertexArray::modify(unsigned i)
101 {
102         dirty = true;
103         return &data[0]+i*stride;
104 }
105
106 unsigned VertexArray::get_data_size() const
107 {
108         return data.size()*sizeof(float);
109 }
110
111 void VertexArray::apply(bool use_legacy) const
112 {
113         if(format.empty())
114                 throw invalid_operation("VertexArray::apply");
115         // Don't mess up the vertex array object of a mesh
116         if(Mesh::current())
117                 throw invalid_operation("VertexArray::apply");
118
119         /* Unbind first if the legacy flag changes.  The logic for supporting it
120         directly in apply_arrays would get too complicated, and this also allows
121         rebinding the same array with different legacy setting. */
122         if(legacy_used!=use_legacy)
123                 unbind();
124
125         if(!use_legacy)
126                 static Require _req(ARB_vertex_shader);
127         else if(legacy)
128                 static Require _req(MSP_legacy_features);
129
130         const VertexArray *old = current();
131         /* If the array has been modified, apply it even if it was the last one to
132         be applied.  This is necessary to get the data updated to vertex buffer, and
133         to resync things after a format change.  Radeon drivers also have some
134         problems with modifying vertex arrays without re-setting the pointers. */
135         if(!set_current(this) && !dirty)
136                 return;
137
138         Buffer *vbuf = get_buffer();
139         Bind _bind_vbuf(vbuf, ARRAY_BUFFER);
140         if(vbuf && dirty)
141                 update_buffer();
142
143         const float *base = (vbuf ? reinterpret_cast<float *>(get_offset()) : &data[0]);
144         unsigned stride_bytes = stride*sizeof(float);
145         apply_arrays(&arrays, (old ? &old->arrays : 0), base, stride_bytes, use_legacy);
146 }
147
148 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes, bool use_legacy)
149 {
150         unsigned active_tex = 0;
151         unsigned n_arrays = arrays ? arrays->size() : 0;
152         if(old_arrays)
153                 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
154         for(unsigned i=0; i<n_arrays; ++i)
155         {
156                 const Array *arr = ((arrays && i<arrays->size() && (*arrays)[i].component) ? &(*arrays)[i] : 0);
157                 const Array *old_arr = ((old_arrays && i<old_arrays->size() && (*old_arrays)[i].component) ? &(*old_arrays)[i] : 0);
158                 if(!arr && !old_arr)
159                         continue;
160
161                 unsigned char comp = (arr ? arr->component : old_arr->component);
162                 unsigned sz = get_component_size(comp);
163                 unsigned t = get_component_type(comp);
164                 if(use_legacy)
165                 {
166                         GLenum array_type = 0;
167                         if(t==get_component_type(VERTEX3))
168                         {
169                                 if(arr)
170                                         glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
171                                 array_type = GL_VERTEX_ARRAY;
172                         }
173                         else if(t==get_component_type(NORMAL3))
174                         {
175                                 if(arr)
176                                         glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
177                                 array_type = GL_NORMAL_ARRAY;
178                         }
179                         else if(t==get_component_type(COLOR4_FLOAT))
180                         {
181                                 if(arr)
182                                 {
183                                         if(sz==1)
184                                                 glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
185                                         else
186                                                 glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
187                                 }
188                                 array_type = GL_COLOR_ARRAY;
189                         }
190                         else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
191                         {
192                                 t -= get_component_type(TEXCOORD1);
193                                 if(t>0 || active_tex)
194                                 {
195                                         glClientActiveTexture(GL_TEXTURE0+t);
196                                         active_tex = t;
197                                 }
198                                 if(arr)
199                                         glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
200                                 array_type = GL_TEXTURE_COORD_ARRAY;
201                         }
202
203                         if(array_type)
204                         {
205                                 // Only change enable state if needed
206                                 if(arr && !old_arr)
207                                         glEnableClientState(array_type);
208                                 else if(old_arr && !arr)
209                                         glDisableClientState(array_type);
210
211                                 continue;
212                         }
213                 }
214
215                 if(t>=get_component_type(ATTRIB1))
216                         t -= get_component_type(ATTRIB1);
217                 if(arr)
218                 {
219                         if(arr->component==COLOR4_UBYTE)
220                                 glVertexAttribPointer(t, 4, GL_UNSIGNED_BYTE, true, stride_bytes, base+arr->offset);
221                         else
222                                 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
223                 }
224
225                 // Only change enable state if needed
226                 if(arr && !old_arr)
227                         glEnableVertexAttribArray(t);
228                 else if(old_arr && !arr)
229                         glDisableVertexAttribArray(t);
230         }
231
232         if(active_tex)
233                 glClientActiveTexture(GL_TEXTURE0);
234
235         legacy_used = use_legacy;
236 }
237
238 void VertexArray::unbind()
239 {
240         const VertexArray *old = current();
241         if(set_current(0))
242                 apply_arrays(0, &old->arrays, 0, 0, legacy_used);
243 }
244
245
246 VertexArray::Array::Array():
247         component(0),
248         offset(0)
249 { }
250
251
252 VertexArray::Loader::Loader(VertexArray &a):
253         VertexArrayBuilder(a)
254 {
255         add("vertex2",   static_cast<void (Loader::*)(float, float)>(&Loader::vertex));
256         add("vertex3",   static_cast<void (Loader::*)(float, float, float)>(&Loader::vertex));
257         add("vertex4",   static_cast<void (Loader::*)(float, float, float, float)>(&Loader::vertex));
258         add("normal3",   static_cast<void (Loader::*)(float, float, float)>(&Loader::normal));
259         add("texcoord1", static_cast<void (Loader::*)(float)>(&Loader::texcoord));
260         add("texcoord2", static_cast<void (Loader::*)(float, float)>(&Loader::texcoord));
261         add("texcoord3", static_cast<void (Loader::*)(float, float, float)>(&Loader::texcoord));
262         add("texcoord4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::texcoord));
263         add("multitexcoord1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::multitexcoord));
264         add("multitexcoord2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::multitexcoord));
265         add("multitexcoord3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::multitexcoord));
266         add("multitexcoord4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::multitexcoord));
267         add("color3",    static_cast<void (Loader::*)(float, float, float)>(&Loader::color));
268         add("color4",    static_cast<void (Loader::*)(float, float, float, float)>(&Loader::color));
269         add("attrib1",   static_cast<void (Loader::*)(unsigned, float)>(&Loader::attrib));
270         add("attrib2",   static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::attrib));
271         add("attrib3",   static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::attrib));
272         add("attrib4",   static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::attrib));
273         add("tangent3",  static_cast<void (Loader::*)(float, float, float)>(&Loader::tangent));
274         add("binormal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::binormal));
275 }
276
277 } // namespace GL
278 } // namespace Msp