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 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");
116 const VertexArray *old = current();
117 /* If the array has been modified, apply it even if it was the last one to
118 be applied. This is necessary to get the data updated to vertex buffer, and
119 to resync things after a format change. Radeon drivers also have some
120 problems with modifying vertex arrays without re-setting the pointers. */
121 if(!set_current(this) && !dirty)
124 Buffer *vbuf = get_buffer();
127 vbuf->bind_to(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 Buffer::unbind_from(ARRAY_BUFFER);
140 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes)
142 unsigned active_tex = 0;
143 unsigned n_arrays = arrays ? arrays->size() : 0;
145 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
146 for(unsigned i=0; i<n_arrays; ++i)
148 const Array *arr = ((arrays && i<arrays->size() && (*arrays)[i].component) ? &(*arrays)[i] : 0);
149 const Array *old_arr = ((old_arrays && i<old_arrays->size() && (*old_arrays)[i].component) ? &(*old_arrays)[i] : 0);
153 unsigned char comp = (arr ? arr->component : old_arr->component);
154 unsigned sz = get_component_size(comp);
155 unsigned t = get_component_type(comp);
156 GLenum array_type = 0;
157 if(t==get_component_type(VERTEX3))
160 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
161 array_type = GL_VERTEX_ARRAY;
163 else if(t==get_component_type(NORMAL3))
166 glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
167 array_type = GL_NORMAL_ARRAY;
169 else if(t==get_component_type(COLOR4_FLOAT))
174 glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
176 glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
178 array_type = GL_COLOR_ARRAY;
180 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
182 t -= get_component_type(TEXCOORD1);
183 if(t>0 || active_tex)
185 glClientActiveTexture(GL_TEXTURE0+t);
189 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
190 array_type = GL_TEXTURE_COORD_ARRAY;
194 if(t>=get_component_type(ATTRIB1))
195 t -= get_component_type(ATTRIB1);
197 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
200 // Only change enable state if needed
204 glEnableClientState(array_type);
206 glEnableVertexAttribArray(t);
208 else if(old_arr && !arr)
211 glDisableClientState(array_type);
213 glDisableVertexAttribArray(t);
218 glClientActiveTexture(GL_TEXTURE0);
222 VertexArray::Array::Array():
228 VertexArray::Loader::Loader(VertexArray &a):
229 VertexArrayBuilder(a)
231 add("vertex2", static_cast<void (Loader::*)(float, float)>(&Loader::vertex));
232 add("vertex3", static_cast<void (Loader::*)(float, float, float)>(&Loader::vertex));
233 add("vertex4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::vertex));
234 add("normal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::normal));
235 add("texcoord1", static_cast<void (Loader::*)(float)>(&Loader::texcoord));
236 add("texcoord2", static_cast<void (Loader::*)(float, float)>(&Loader::texcoord));
237 add("texcoord3", static_cast<void (Loader::*)(float, float, float)>(&Loader::texcoord));
238 add("texcoord4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::texcoord));
239 add("multitexcoord1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::multitexcoord));
240 add("multitexcoord2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::multitexcoord));
241 add("multitexcoord3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::multitexcoord));
242 add("multitexcoord4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::multitexcoord));
243 add("color3", static_cast<void (Loader::*)(float, float, float)>(&Loader::color));
244 add("color4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::color));
245 add("attrib1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::attrib));
246 add("attrib2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::attrib));
247 add("attrib3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::attrib));
248 add("attrib4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::attrib));
249 add("tangent3", static_cast<void (Loader::*)(float, float, float)>(&Loader::tangent));
250 add("binormal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::binormal));