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