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