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()
21 /* Unbind accesses the current VertexArray, so a call from ~Bindable would
22 try to access destroyed data. */
27 void VertexArray::reset(const VertexFormat &f)
31 stride = get_stride(format);
36 for(const unsigned char *c=format.begin(); c!=format.end(); ++c)
38 unsigned slot = get_array_slot(*c);
39 if(slot>=arrays.size())
40 arrays.resize(slot+1);
42 Array &arr = arrays[slot];
46 offs += get_component_size(*c);
50 unsigned VertexArray::get_array_slot(unsigned char comp)
52 unsigned t = get_component_type(comp);
53 if(t==get_component_type(VERTEX3))
55 else if(t==get_component_type(NORMAL3))
57 else if(t==get_component_type(COLOR4_FLOAT))
59 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
61 t -= get_component_type(TEXCOORD1);
63 static Require _req(ARB_multitexture);
68 static Require _req(ARB_vertex_shader);
70 t -= get_component_type(ATTRIB1);
75 void VertexArray::clear()
80 void VertexArray::reserve(unsigned n)
82 data.reserve(n*stride);
85 float *VertexArray::append()
87 data.insert(data.end(), stride, 0.0f);
90 return &*(data.end()-stride);
93 float *VertexArray::modify(unsigned i)
96 return &data[0]+i*stride;
99 unsigned VertexArray::get_data_size() const
101 return data.size()*sizeof(float);
104 void VertexArray::bind() const
107 throw invalid_operation("VertexArray::apply");
108 // Don't mess up the vertex array object of a mesh
110 throw invalid_operation("VertexArray::apply");
112 const VertexArray *old = current();
113 /* If the array has been modified, apply it even if it was the last one to
114 be applied. This is necessary to get the data updated to vertex buffer, and
115 to resync things after a format change. Radeon drivers also have some
116 problems with modifying vertex arrays without re-setting the pointers. */
117 if(!set_current(this) && !dirty)
120 Buffer *vbuf = get_buffer();
121 Bind _bind_vbuf(vbuf, ARRAY_BUFFER);
125 const float *base = (vbuf ? reinterpret_cast<float *>(get_offset()) : &data[0]);
126 unsigned stride_bytes = stride*sizeof(float);
127 apply_arrays(&arrays, (old ? &old->arrays : 0), base, stride_bytes);
130 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes)
132 unsigned active_tex = 0;
133 unsigned n_arrays = arrays ? arrays->size() : 0;
135 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
136 for(unsigned i=0; i<n_arrays; ++i)
138 const Array *arr = ((arrays && i<arrays->size() && (*arrays)[i].component) ? &(*arrays)[i] : 0);
139 const Array *old_arr = ((old_arrays && i<old_arrays->size() && (*old_arrays)[i].component) ? &(*old_arrays)[i] : 0);
143 unsigned char comp = (arr ? arr->component : old_arr->component);
144 unsigned sz = get_component_size(comp);
145 unsigned t = get_component_type(comp);
146 GLenum array_type = 0;
147 if(t==get_component_type(VERTEX3))
150 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
151 array_type = GL_VERTEX_ARRAY;
153 else if(t==get_component_type(NORMAL3))
156 glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
157 array_type = GL_NORMAL_ARRAY;
159 else if(t==get_component_type(COLOR4_FLOAT))
164 glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
166 glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
168 array_type = GL_COLOR_ARRAY;
170 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
172 t -= get_component_type(TEXCOORD1);
173 if(t>0 || active_tex)
175 glClientActiveTexture(GL_TEXTURE0+t);
179 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
180 array_type = GL_TEXTURE_COORD_ARRAY;
184 if(t>=get_component_type(ATTRIB1))
185 t -= get_component_type(ATTRIB1);
187 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
190 // Only change enable state if needed
194 glEnableClientState(array_type);
196 glEnableVertexAttribArray(t);
198 else if(old_arr && !arr)
201 glDisableClientState(array_type);
203 glDisableVertexAttribArray(t);
208 glClientActiveTexture(GL_TEXTURE0);
211 void VertexArray::unbind()
213 const VertexArray *old = current();
215 apply_arrays(0, &old->arrays, 0, 0);
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));