1 #include <msp/gl/extensions/arb_multitexture.h>
2 #include <msp/gl/extensions/arb_vertex_shader.h>
7 #include "vertexarray.h"
14 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 offs += 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::clear()
84 void VertexArray::reserve(unsigned n)
86 data.reserve(n*stride);
89 float *VertexArray::append()
91 data.insert(data.end(), stride, 0.0f);
93 return &*(data.end()-stride);
96 float *VertexArray::modify(unsigned i)
99 return &data[0]+i*stride;
102 unsigned VertexArray::get_data_size() const
104 return data.size()*sizeof(float);
107 void VertexArray::upload_data() const
109 get_buffer()->sub_data(get_offset(), get_data_size(), &data[0]);
112 void VertexArray::apply() const
115 throw invalid_operation("VertexArray::apply");
116 // Don't mess up the vertex array object of a mesh
118 throw invalid_operation("VertexArray::apply");
120 const VertexArray *old = current();
121 /* If the array has been modified, apply it even if it was the last one to
122 be applied. This is necessary to get the data updated to vertex buffer, and
123 to resync things after a format change. Radeon drivers also have some
124 problems with modifying vertex arrays without re-setting the pointers. */
125 if(!set_current(this) && !dirty)
128 Buffer *vbuf = get_buffer();
131 vbuf->bind_to(ARRAY_BUFFER);
136 const float *base = (vbuf ? reinterpret_cast<float *>(get_offset()) : &data[0]);
137 unsigned stride_bytes = stride*sizeof(float);
138 apply_arrays(&arrays, (old ? &old->arrays : 0), base, stride_bytes);
141 Buffer::unbind_from(ARRAY_BUFFER);
144 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes)
146 unsigned active_tex = 0;
147 unsigned n_arrays = arrays ? arrays->size() : 0;
149 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
150 for(unsigned i=0; i<n_arrays; ++i)
152 const Array *arr = ((arrays && i<arrays->size() && (*arrays)[i].component) ? &(*arrays)[i] : 0);
153 const Array *old_arr = ((old_arrays && i<old_arrays->size() && (*old_arrays)[i].component) ? &(*old_arrays)[i] : 0);
157 unsigned char comp = (arr ? arr->component : old_arr->component);
158 unsigned sz = get_component_size(comp);
159 unsigned t = get_component_type(comp);
160 GLenum array_type = 0;
161 if(t==get_component_type(VERTEX3))
164 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
165 array_type = GL_VERTEX_ARRAY;
167 else if(t==get_component_type(NORMAL3))
170 glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
171 array_type = GL_NORMAL_ARRAY;
173 else if(t==get_component_type(COLOR4_FLOAT))
178 glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
180 glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
182 array_type = GL_COLOR_ARRAY;
184 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
186 t -= get_component_type(TEXCOORD1);
187 if(t>0 || active_tex)
189 glClientActiveTexture(GL_TEXTURE0+t);
193 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
194 array_type = GL_TEXTURE_COORD_ARRAY;
198 if(t>=get_component_type(ATTRIB1))
199 t -= get_component_type(ATTRIB1);
201 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
204 // Only change enable state if needed
208 glEnableClientState(array_type);
210 glEnableVertexAttribArray(t);
212 else if(old_arr && !arr)
215 glDisableClientState(array_type);
217 glDisableVertexAttribArray(t);
222 glClientActiveTexture(GL_TEXTURE0);
226 VertexArray::Array::Array():
232 VertexArray::Loader::Loader(VertexArray &a):
233 VertexArrayBuilder(a)
235 add("vertex2", static_cast<void (Loader::*)(float, float)>(&Loader::vertex));
236 add("vertex3", static_cast<void (Loader::*)(float, float, float)>(&Loader::vertex));
237 add("vertex4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::vertex));
238 add("normal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::normal));
239 add("texcoord1", static_cast<void (Loader::*)(float)>(&Loader::texcoord));
240 add("texcoord2", static_cast<void (Loader::*)(float, float)>(&Loader::texcoord));
241 add("texcoord3", static_cast<void (Loader::*)(float, float, float)>(&Loader::texcoord));
242 add("texcoord4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::texcoord));
243 add("multitexcoord1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::multitexcoord));
244 add("multitexcoord2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::multitexcoord));
245 add("multitexcoord3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::multitexcoord));
246 add("multitexcoord4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::multitexcoord));
247 add("color3", static_cast<void (Loader::*)(float, float, float)>(&Loader::color));
248 add("color4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::color));
249 add("attrib1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::attrib));
250 add("attrib2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::attrib));
251 add("attrib3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::attrib));
252 add("attrib4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::attrib));
253 add("tangent3", static_cast<void (Loader::*)(float, float, float)>(&Loader::tangent));
254 add("binormal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::binormal));