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)
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 offs += 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::clear()
83 void VertexArray::reserve(unsigned n)
85 data.reserve(n*stride);
88 float *VertexArray::append()
90 data.insert(data.end(), stride, 0.0f);
92 return &*(data.end()-stride);
95 float *VertexArray::modify(unsigned i)
98 return &data[0]+i*stride;
101 unsigned VertexArray::get_data_size() const
103 return data.size()*sizeof(float);
106 void VertexArray::upload_data() const
108 get_buffer()->sub_data(get_offset(), get_data_size(), &data[0]);
111 void VertexArray::apply() const
114 throw invalid_operation("VertexArray::apply");
115 // Don't mess up the vertex array object of a mesh
117 throw invalid_operation("VertexArray::apply");
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)
127 Buffer *vbuf = get_buffer();
128 Bind _bind_vbuf(vbuf, ARRAY_BUFFER);
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);
137 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes)
139 unsigned active_tex = 0;
140 unsigned n_arrays = arrays ? arrays->size() : 0;
142 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
143 for(unsigned i=0; i<n_arrays; ++i)
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);
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))
157 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
158 array_type = GL_VERTEX_ARRAY;
160 else if(t==get_component_type(NORMAL3))
163 glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
164 array_type = GL_NORMAL_ARRAY;
166 else if(t==get_component_type(COLOR4_FLOAT))
171 glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
173 glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
175 array_type = GL_COLOR_ARRAY;
177 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
179 t -= get_component_type(TEXCOORD1);
180 if(t>0 || active_tex)
182 glClientActiveTexture(GL_TEXTURE0+t);
186 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
187 array_type = GL_TEXTURE_COORD_ARRAY;
191 if(t>=get_component_type(ATTRIB1))
192 t -= get_component_type(ATTRIB1);
194 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
197 // Only change enable state if needed
201 glEnableClientState(array_type);
203 glEnableVertexAttribArray(t);
205 else if(old_arr && !arr)
208 glDisableClientState(array_type);
210 glDisableVertexAttribArray(t);
215 glClientActiveTexture(GL_TEXTURE0);
219 VertexArray::Array::Array():
225 VertexArray::Loader::Loader(VertexArray &a):
226 VertexArrayBuilder(a)
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));