1 #include <msp/gl/extensions/arb_multitexture.h>
2 #include <msp/gl/extensions/arb_vertex_shader.h>
7 #include "vertexarray.h"
14 bool VertexArray::legacy_used = false;
16 VertexArray::VertexArray(const VertexFormat &f)
21 VertexArray::~VertexArray()
23 /* Unbind accesses the current VertexArray, so a call from ~Bindable would
24 try to access destroyed data. */
29 void VertexArray::reset(const VertexFormat &f)
33 stride = get_stride(format);
39 for(const unsigned char *c=format.begin(); c!=format.end(); ++c)
41 unsigned slot = get_array_slot(*c);
42 if(slot>=arrays.size())
43 arrays.resize(slot+1);
45 Array &arr = arrays[slot];
52 offs += get_component_size(*c);
56 unsigned VertexArray::get_array_slot(unsigned char comp)
58 unsigned t = get_component_type(comp);
59 if(t==get_component_type(VERTEX3))
61 else if(t==get_component_type(NORMAL3))
63 else if(t==get_component_type(COLOR4_FLOAT))
65 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
67 t -= get_component_type(TEXCOORD1);
69 static Require _req(ARB_multitexture);
74 static Require _req(ARB_vertex_shader);
76 t -= get_component_type(ATTRIB1);
81 void VertexArray::clear()
86 void VertexArray::reserve(unsigned n)
88 data.reserve(n*stride);
91 float *VertexArray::append()
93 data.insert(data.end(), stride, 0.0f);
96 return &*(data.end()-stride);
99 float *VertexArray::modify(unsigned i)
102 return &data[0]+i*stride;
105 unsigned VertexArray::get_data_size() const
107 return data.size()*sizeof(float);
110 void VertexArray::apply(bool use_legacy) const
113 throw invalid_operation("VertexArray::apply");
114 // Don't mess up the vertex array object of a mesh
116 throw invalid_operation("VertexArray::apply");
118 /* Unbind first if the legacy flag changes. The logic for supporting it
119 directly in apply_arrays would get too complicated, and this also allows
120 rebinding the same array with different legacy setting. */
121 if(legacy_used!=use_legacy)
125 static Require _req(ARB_vertex_shader);
127 const VertexArray *old = current();
128 /* If the array has been modified, apply it even if it was the last one to
129 be applied. This is necessary to get the data updated to vertex buffer, and
130 to resync things after a format change. Radeon drivers also have some
131 problems with modifying vertex arrays without re-setting the pointers. */
132 if(!set_current(this) && !dirty)
135 Buffer *vbuf = get_buffer();
136 Bind _bind_vbuf(vbuf, ARRAY_BUFFER);
140 const float *base = (vbuf ? reinterpret_cast<float *>(get_offset()) : &data[0]);
141 unsigned stride_bytes = stride*sizeof(float);
142 apply_arrays(&arrays, (old ? &old->arrays : 0), base, stride_bytes, use_legacy);
145 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes, bool use_legacy)
147 unsigned active_tex = 0;
148 unsigned n_arrays = arrays ? arrays->size() : 0;
150 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
151 for(unsigned i=0; i<n_arrays; ++i)
153 const Array *arr = ((arrays && i<arrays->size() && (*arrays)[i].component) ? &(*arrays)[i] : 0);
154 const Array *old_arr = ((old_arrays && i<old_arrays->size() && (*old_arrays)[i].component) ? &(*old_arrays)[i] : 0);
158 unsigned char comp = (arr ? arr->component : old_arr->component);
159 unsigned sz = get_component_size(comp);
160 unsigned t = get_component_type(comp);
163 GLenum array_type = 0;
164 if(t==get_component_type(VERTEX3))
167 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
168 array_type = GL_VERTEX_ARRAY;
170 else if(t==get_component_type(NORMAL3))
173 glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
174 array_type = GL_NORMAL_ARRAY;
176 else if(t==get_component_type(COLOR4_FLOAT))
181 glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
183 glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
185 array_type = GL_COLOR_ARRAY;
187 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
189 t -= get_component_type(TEXCOORD1);
190 if(t>0 || active_tex)
192 glClientActiveTexture(GL_TEXTURE0+t);
196 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
197 array_type = GL_TEXTURE_COORD_ARRAY;
202 // Only change enable state if needed
204 glEnableClientState(array_type);
205 else if(old_arr && !arr)
206 glDisableClientState(array_type);
212 if(t>=get_component_type(ATTRIB1))
213 t -= get_component_type(ATTRIB1);
216 if(arr->component==COLOR4_UBYTE)
217 glVertexAttribPointer(t, 4, GL_UNSIGNED_BYTE, true, stride_bytes, base+arr->offset);
219 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
222 // Only change enable state if needed
224 glEnableVertexAttribArray(t);
225 else if(old_arr && !arr)
226 glDisableVertexAttribArray(t);
230 glClientActiveTexture(GL_TEXTURE0);
232 legacy_used = use_legacy;
235 void VertexArray::unbind()
237 const VertexArray *old = current();
239 apply_arrays(0, &old->arrays, 0, 0, legacy_used);
243 VertexArray::Array::Array():
249 VertexArray::Loader::Loader(VertexArray &a):
250 VertexArrayBuilder(a)
252 add("vertex2", static_cast<void (Loader::*)(float, float)>(&Loader::vertex));
253 add("vertex3", static_cast<void (Loader::*)(float, float, float)>(&Loader::vertex));
254 add("vertex4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::vertex));
255 add("normal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::normal));
256 add("texcoord1", static_cast<void (Loader::*)(float)>(&Loader::texcoord));
257 add("texcoord2", static_cast<void (Loader::*)(float, float)>(&Loader::texcoord));
258 add("texcoord3", static_cast<void (Loader::*)(float, float, float)>(&Loader::texcoord));
259 add("texcoord4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::texcoord));
260 add("multitexcoord1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::multitexcoord));
261 add("multitexcoord2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::multitexcoord));
262 add("multitexcoord3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::multitexcoord));
263 add("multitexcoord4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::multitexcoord));
264 add("color3", static_cast<void (Loader::*)(float, float, float)>(&Loader::color));
265 add("color4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::color));
266 add("attrib1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::attrib));
267 add("attrib2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::attrib));
268 add("attrib3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::attrib));
269 add("attrib4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::attrib));
270 add("tangent3", static_cast<void (Loader::*)(float, float, float)>(&Loader::tangent));
271 add("binormal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::binormal));