]> git.tdb.fi Git - libs/gl.git/blob - source/vertexarray.cpp
Refactor the internal interface of Bufferable a bit
[libs/gl.git] / source / vertexarray.cpp
1 #include <msp/gl/extensions/arb_multitexture.h>
2 #include <msp/gl/extensions/arb_vertex_shader.h>
3 #include "buffer.h"
4 #include "error.h"
5 #include "gl.h"
6 #include "mesh.h"
7 #include "vertexarray.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace GL {
13
14 VertexArray::VertexArray(const VertexFormat &f)
15 {
16         reset(f);
17 }
18
19 VertexArray::~VertexArray()
20 {
21         if(current()==this)
22         {
23                 /* We must deactivate arrays here, or apply() would try to access deleted
24                 data on the next invocation. */
25                 set_current(0);
26                 apply_arrays(0, &arrays, 0, 0);
27         }
28 }
29
30 void VertexArray::reset(const VertexFormat &f)
31 {
32         clear();
33         format = f;
34         stride = get_stride(format);
35
36         arrays.clear();
37
38         unsigned offs = 0;
39         for(const unsigned char *c=format.begin(); c!=format.end(); ++c)
40         {
41                 unsigned slot = get_array_slot(*c);
42                 if(slot>=arrays.size())
43                         arrays.resize(slot+1);
44
45                 Array &arr = arrays[slot];
46                 arr.component = *c;
47                 arr.offset = offs;
48
49                 offs += get_component_size(*c);
50         }
51 }
52
53 unsigned VertexArray::get_array_slot(unsigned char comp)
54 {
55         unsigned t = get_component_type(comp);
56         if(t==get_component_type(VERTEX3))
57                 return 0;
58         else if(t==get_component_type(NORMAL3))
59                 return 1;
60         else if(t==get_component_type(COLOR4_FLOAT))
61                 return 2;
62         else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
63         {
64                 t -= get_component_type(TEXCOORD1);
65                 if(t>0)
66                         static Require _req(ARB_multitexture);
67                 return 3+t;
68         }
69         else
70         {
71                 static Require _req(ARB_vertex_shader);
72                 if(comp>=ATTRIB1)
73                         t -= get_component_type(ATTRIB1);
74                 return 7+t;
75         }
76 }
77
78 void VertexArray::clear()
79 {
80         data.clear();
81 }
82
83 void VertexArray::reserve(unsigned n)
84 {
85         data.reserve(n*stride);
86 }
87
88 float *VertexArray::append()
89 {
90         data.insert(data.end(), stride, 0.0f);
91         dirty = true;
92         return &*(data.end()-stride);
93 }
94
95 float *VertexArray::modify(unsigned i)
96 {
97         dirty = true;
98         return &data[0]+i*stride;
99 }
100
101 unsigned VertexArray::get_data_size() const
102 {
103         return data.size()*sizeof(float);
104 }
105
106 void VertexArray::apply() const
107 {
108         if(format.empty())
109                 throw invalid_operation("VertexArray::apply");
110         // Don't mess up the vertex array object of a mesh
111         if(Mesh::current())
112                 throw invalid_operation("VertexArray::apply");
113
114         const VertexArray *old = current();
115         /* If the array has been modified, apply it even if it was the last one to
116         be applied.  This is necessary to get the data updated to vertex buffer, and
117         to resync things after a format change.  Radeon drivers also have some
118         problems with modifying vertex arrays without re-setting the pointers. */
119         if(!set_current(this) && !dirty)
120                 return;
121
122         Buffer *vbuf = get_buffer();
123         Bind _bind_vbuf(vbuf, ARRAY_BUFFER);
124         if(vbuf && dirty)
125                 update_buffer();
126
127         const float *base = (vbuf ? reinterpret_cast<float *>(get_offset()) : &data[0]);
128         unsigned stride_bytes = stride*sizeof(float);
129         apply_arrays(&arrays, (old ? &old->arrays : 0), base, stride_bytes);
130 }
131
132 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes)
133 {
134         unsigned active_tex = 0;
135         unsigned n_arrays = arrays ? arrays->size() : 0;
136         if(old_arrays)
137                 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
138         for(unsigned i=0; i<n_arrays; ++i)
139         {
140                 const Array *arr = ((arrays && i<arrays->size() && (*arrays)[i].component) ? &(*arrays)[i] : 0);
141                 const Array *old_arr = ((old_arrays && i<old_arrays->size() && (*old_arrays)[i].component) ? &(*old_arrays)[i] : 0);
142                 if(!arr && !old_arr)
143                         continue;
144
145                 unsigned char comp = (arr ? arr->component : old_arr->component);
146                 unsigned sz = get_component_size(comp);
147                 unsigned t = get_component_type(comp);
148                 GLenum array_type = 0;
149                 if(t==get_component_type(VERTEX3))
150                 {
151                         if(arr)
152                                 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
153                         array_type = GL_VERTEX_ARRAY;
154                 }
155                 else if(t==get_component_type(NORMAL3))
156                 {
157                         if(arr)
158                                 glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
159                         array_type = GL_NORMAL_ARRAY;
160                 }
161                 else if(t==get_component_type(COLOR4_FLOAT))
162                 {
163                         if(arr)
164                         {
165                                 if(sz==1)
166                                         glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
167                                 else
168                                         glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
169                         }
170                         array_type = GL_COLOR_ARRAY;
171                 }
172                 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
173                 {
174                         t -= get_component_type(TEXCOORD1);
175                         if(t>0 || active_tex)
176                         {
177                                 glClientActiveTexture(GL_TEXTURE0+t);
178                                 active_tex = t;
179                         }
180                         if(arr)
181                                 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
182                         array_type = GL_TEXTURE_COORD_ARRAY;
183                 }
184                 else
185                 {
186                         if(t>=get_component_type(ATTRIB1))
187                                 t -= get_component_type(ATTRIB1);
188                         if(arr)
189                                 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
190                 }
191
192                 // Only change enable state if needed
193                 if(arr && !old_arr)
194                 {
195                         if(array_type)
196                                 glEnableClientState(array_type);
197                         else
198                                 glEnableVertexAttribArray(t);
199                 }
200                 else if(old_arr && !arr)
201                 {
202                         if(array_type)
203                                 glDisableClientState(array_type);
204                         else
205                                 glDisableVertexAttribArray(t);
206                 }
207         }
208
209         if(active_tex)
210                 glClientActiveTexture(GL_TEXTURE0);
211 }
212
213
214 VertexArray::Array::Array():
215         component(0),
216         offset(0)
217 { }
218
219
220 VertexArray::Loader::Loader(VertexArray &a):
221         VertexArrayBuilder(a)
222 {
223         add("vertex2",   static_cast<void (Loader::*)(float, float)>(&Loader::vertex));
224         add("vertex3",   static_cast<void (Loader::*)(float, float, float)>(&Loader::vertex));
225         add("vertex4",   static_cast<void (Loader::*)(float, float, float, float)>(&Loader::vertex));
226         add("normal3",   static_cast<void (Loader::*)(float, float, float)>(&Loader::normal));
227         add("texcoord1", static_cast<void (Loader::*)(float)>(&Loader::texcoord));
228         add("texcoord2", static_cast<void (Loader::*)(float, float)>(&Loader::texcoord));
229         add("texcoord3", static_cast<void (Loader::*)(float, float, float)>(&Loader::texcoord));
230         add("texcoord4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::texcoord));
231         add("multitexcoord1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::multitexcoord));
232         add("multitexcoord2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::multitexcoord));
233         add("multitexcoord3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::multitexcoord));
234         add("multitexcoord4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::multitexcoord));
235         add("color3",    static_cast<void (Loader::*)(float, float, float)>(&Loader::color));
236         add("color4",    static_cast<void (Loader::*)(float, float, float, float)>(&Loader::color));
237         add("attrib1",   static_cast<void (Loader::*)(unsigned, float)>(&Loader::attrib));
238         add("attrib2",   static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::attrib));
239         add("attrib3",   static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::attrib));
240         add("attrib4",   static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::attrib));
241         add("tangent3",  static_cast<void (Loader::*)(float, float, float)>(&Loader::tangent));
242         add("binormal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::binormal));
243 }
244
245 } // namespace GL
246 } // namespace Msp