1 #include <msp/gl/extensions/arb_multitexture.h>
2 #include <msp/gl/extensions/arb_vertex_shader.h>
6 #include "vertexarray.h"
13 VertexArray::VertexArray(const VertexFormat &f):
20 VertexArray::~VertexArray()
24 /* We must deactivate arrays here, or apply() would try to access deleted
25 data on the next invocation. */
27 apply_arrays(0, &arrays, 0, 0);
31 void VertexArray::reset(const VertexFormat &f)
35 stride = get_stride(format);
40 for(const unsigned char *c=format.begin(); c!=format.end(); ++c)
42 unsigned slot = get_array_slot(*c);
43 if(slot>=arrays.size())
44 arrays.resize(slot+1);
46 Array &arr = arrays[slot];
50 offset += get_component_size(*c);
54 unsigned VertexArray::get_array_slot(unsigned char comp)
56 unsigned t = get_component_type(comp);
57 if(t==get_component_type(VERTEX3))
59 else if(t==get_component_type(NORMAL3))
61 else if(t==get_component_type(COLOR4_FLOAT))
63 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
65 t -= get_component_type(TEXCOORD1);
67 static Require _req(ARB_multitexture);
72 static Require _req(ARB_vertex_shader);
74 t -= get_component_type(ATTRIB1);
79 void VertexArray::use_vertex_buffer()
84 vbuf = new Buffer(ARRAY_BUFFER);
89 void VertexArray::use_vertex_buffer(Buffer *b)
97 void VertexArray::clear()
102 void VertexArray::reserve(unsigned n)
104 data.reserve(n*stride);
107 float *VertexArray::append()
109 data.insert(data.end(), stride, 0.0f);
111 return &*(data.end()-stride);
114 float *VertexArray::modify(unsigned i)
117 return &data[0]+i*stride;
120 void VertexArray::set_dirty()
125 vbuf = new Buffer(ARRAY_BUFFER);
130 void VertexArray::apply() const
133 throw invalid_operation("VertexArray::apply");
135 const VertexArray *old = current();
136 /* If the array has been modified, apply it even if it was the last one to
137 be applied. This is necessary to get the data updated to vertex buffer, and
138 to resync things after a format change. Radeon drivers also have some
139 problems with modifying vertex arrays without re-setting the pointers. */
140 if(!set_current(this) && !dirty)
145 vbuf->bind_to(ARRAY_BUFFER);
148 vbuf->data(data.size()*sizeof(float), &data[0]);
153 const float *base = (vbuf ? 0 : &data[0]);
154 unsigned stride_bytes = stride*sizeof(float);
155 apply_arrays(&arrays, (old ? &old->arrays : 0), base, stride_bytes);
158 Buffer::unbind_from(ARRAY_BUFFER);
161 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes)
163 unsigned active_tex = 0;
164 unsigned n_arrays = arrays ? arrays->size() : 0;
166 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
167 for(unsigned i=0; i<n_arrays; ++i)
169 const Array *arr = ((arrays && i<arrays->size() && (*arrays)[i].component) ? &(*arrays)[i] : 0);
170 const Array *old_arr = ((old_arrays && i<old_arrays->size() && (*old_arrays)[i].component) ? &(*old_arrays)[i] : 0);
174 unsigned char comp = (arr ? arr->component : old_arr->component);
175 unsigned sz = get_component_size(comp);
176 unsigned t = get_component_type(comp);
177 GLenum array_type = 0;
178 if(t==get_component_type(VERTEX3))
181 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
182 array_type = GL_VERTEX_ARRAY;
184 else if(t==get_component_type(NORMAL3))
187 glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
188 array_type = GL_NORMAL_ARRAY;
190 else if(t==get_component_type(COLOR4_FLOAT))
195 glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
197 glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
199 array_type = GL_COLOR_ARRAY;
201 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
203 t -= get_component_type(TEXCOORD1);
204 if(t>0 || active_tex)
206 glClientActiveTexture(GL_TEXTURE0+t);
210 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
211 array_type = GL_TEXTURE_COORD_ARRAY;
215 if(t>=get_component_type(ATTRIB1))
216 t -= get_component_type(ATTRIB1);
218 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
221 // Only change enable state if needed
225 glEnableClientState(array_type);
227 glEnableVertexAttribArray(t);
229 else if(old_arr && !arr)
232 glDisableClientState(array_type);
234 glDisableVertexAttribArray(t);
239 glClientActiveTexture(GL_TEXTURE0);
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));