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):
19 VertexArray::~VertexArray()
23 /* We must deactivate arrays here, or apply() would try to access deleted
24 data on the next invocation. */
26 apply_arrays(0, &arrays, 0, 0);
30 void VertexArray::reset(const VertexFormat &f)
34 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];
49 offset += get_component_size(*c);
53 unsigned VertexArray::get_array_slot(unsigned char comp)
55 unsigned t = get_component_type(comp);
56 if(t==get_component_type(VERTEX3))
58 else if(t==get_component_type(NORMAL3))
60 else if(t==get_component_type(COLOR4_FLOAT))
62 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
64 t -= get_component_type(TEXCOORD1);
66 static Require _req(ARB_multitexture);
71 static Require _req(ARB_vertex_shader);
73 t -= get_component_type(ATTRIB1);
78 void VertexArray::use_vertex_buffer(Buffer *b)
84 void VertexArray::clear()
89 void VertexArray::reserve(unsigned n)
91 data.reserve(n*stride);
94 float *VertexArray::append()
96 data.insert(data.end(), stride, 0.0f);
98 return &*(data.end()-stride);
101 float *VertexArray::modify(unsigned i)
104 return &data[0]+i*stride;
107 void VertexArray::set_dirty()
112 void VertexArray::apply() const
115 throw invalid_operation("VertexArray::apply");
117 const VertexArray *old = current();
118 /* If the array has been modified, apply it even if it was the last one to
119 be applied. This is necessary to get the data updated to vertex buffer, and
120 to resync things after a format change. Radeon drivers also have some
121 problems with modifying vertex arrays without re-setting the pointers. */
122 if(!set_current(this) && !dirty)
127 vbuf->bind_to(ARRAY_BUFFER);
130 vbuf->data(data.size()*sizeof(float), &data[0]);
135 const float *base = (vbuf ? 0 : &data[0]);
136 unsigned stride_bytes = stride*sizeof(float);
137 apply_arrays(&arrays, (old ? &old->arrays : 0), base, stride_bytes);
140 Buffer::unbind_from(ARRAY_BUFFER);
143 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes)
145 unsigned active_tex = 0;
146 unsigned n_arrays = arrays ? arrays->size() : 0;
148 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
149 for(unsigned i=0; i<n_arrays; ++i)
151 const Array *arr = ((arrays && i<arrays->size() && (*arrays)[i].component) ? &(*arrays)[i] : 0);
152 const Array *old_arr = ((old_arrays && i<old_arrays->size() && (*old_arrays)[i].component) ? &(*old_arrays)[i] : 0);
156 unsigned char comp = (arr ? arr->component : old_arr->component);
157 unsigned sz = get_component_size(comp);
158 unsigned t = get_component_type(comp);
159 GLenum array_type = 0;
160 if(t==get_component_type(VERTEX3))
163 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
164 array_type = GL_VERTEX_ARRAY;
166 else if(t==get_component_type(NORMAL3))
169 glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
170 array_type = GL_NORMAL_ARRAY;
172 else if(t==get_component_type(COLOR4_FLOAT))
177 glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
179 glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
181 array_type = GL_COLOR_ARRAY;
183 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
185 t -= get_component_type(TEXCOORD1);
186 if(t>0 || active_tex)
188 glClientActiveTexture(GL_TEXTURE0+t);
192 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
193 array_type = GL_TEXTURE_COORD_ARRAY;
197 if(t>=get_component_type(ATTRIB1))
198 t -= get_component_type(ATTRIB1);
200 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
203 // Only change enable state if needed
207 glEnableClientState(array_type);
209 glEnableVertexAttribArray(t);
211 else if(old_arr && !arr)
214 glDisableClientState(array_type);
216 glDisableVertexAttribArray(t);
221 glClientActiveTexture(GL_TEXTURE0);
225 VertexArray::Array::Array():
231 VertexArray::Loader::Loader(VertexArray &a):
232 VertexArrayBuilder(a)
234 add("vertex2", static_cast<void (Loader::*)(float, float)>(&Loader::vertex));
235 add("vertex3", static_cast<void (Loader::*)(float, float, float)>(&Loader::vertex));
236 add("vertex4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::vertex));
237 add("normal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::normal));
238 add("texcoord1", static_cast<void (Loader::*)(float)>(&Loader::texcoord));
239 add("texcoord2", static_cast<void (Loader::*)(float, float)>(&Loader::texcoord));
240 add("texcoord3", static_cast<void (Loader::*)(float, float, float)>(&Loader::texcoord));
241 add("texcoord4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::texcoord));
242 add("multitexcoord1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::multitexcoord));
243 add("multitexcoord2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::multitexcoord));
244 add("multitexcoord3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::multitexcoord));
245 add("multitexcoord4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::multitexcoord));
246 add("color3", static_cast<void (Loader::*)(float, float, float)>(&Loader::color));
247 add("color4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::color));
248 add("attrib1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::attrib));
249 add("attrib2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::attrib));
250 add("attrib3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::attrib));
251 add("attrib4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::attrib));
252 add("tangent3", static_cast<void (Loader::*)(float, float, float)>(&Loader::tangent));
253 add("binormal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::binormal));