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