]> git.tdb.fi Git - libs/gl.git/blob - source/vertexarray.cpp
Remove VertexArray's own dirty member now that it's a Bufferable
[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::upload_data() const
107 {
108         get_buffer()->sub_data(get_offset(), get_data_size(), &data[0]);
109 }
110
111 void VertexArray::apply() const
112 {
113         if(format.empty())
114                 throw invalid_operation("VertexArray::apply");
115         // Don't mess up the vertex array object of a mesh
116         if(Mesh::current())
117                 throw invalid_operation("VertexArray::apply");
118
119         const VertexArray *old = current();
120         /* If the array has been modified, apply it even if it was the last one to
121         be applied.  This is necessary to get the data updated to vertex buffer, and
122         to resync things after a format change.  Radeon drivers also have some
123         problems with modifying vertex arrays without re-setting the pointers. */
124         if(!set_current(this) && !dirty)
125                 return;
126
127         Buffer *vbuf = get_buffer();
128         if(vbuf)
129         {
130                 vbuf->bind_to(ARRAY_BUFFER);
131                 if(dirty)
132                         update_buffer();
133         }
134
135         const float *base = (vbuf ? reinterpret_cast<float *>(get_offset()) : &data[0]);
136         unsigned stride_bytes = stride*sizeof(float);
137         apply_arrays(&arrays, (old ? &old->arrays : 0), base, stride_bytes);
138
139         if(vbuf)
140                 Buffer::unbind_from(ARRAY_BUFFER);
141 }
142
143 void VertexArray::apply_arrays(const vector<Array> *arrays, const vector<Array> *old_arrays, const float *base, unsigned stride_bytes)
144 {
145         unsigned active_tex = 0;
146         unsigned n_arrays = arrays ? arrays->size() : 0;
147         if(old_arrays)
148                 n_arrays = max<unsigned>(n_arrays, old_arrays->size());
149         for(unsigned i=0; i<n_arrays; ++i)
150         {
151                 const Array *arr = ((arrays && i<arrays->size() && (*arrays)[i].component) ? &(*arrays)[i] : 0);
152                 const Array *old_arr = ((old_arrays && i<old_arrays->size() && (*old_arrays)[i].component) ? &(*old_arrays)[i] : 0);
153                 if(!arr && !old_arr)
154                         continue;
155
156                 unsigned char comp = (arr ? arr->component : old_arr->component);
157                 unsigned sz = get_component_size(comp);
158                 unsigned t = get_component_type(comp);
159                 GLenum array_type = 0;
160                 if(t==get_component_type(VERTEX3))
161                 {
162                         if(arr)
163                                 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
164                         array_type = GL_VERTEX_ARRAY;
165                 }
166                 else if(t==get_component_type(NORMAL3))
167                 {
168                         if(arr)
169                                 glNormalPointer(GL_FLOAT, stride_bytes, base+arr->offset);
170                         array_type = GL_NORMAL_ARRAY;
171                 }
172                 else if(t==get_component_type(COLOR4_FLOAT))
173                 {
174                         if(arr)
175                         {
176                                 if(sz==1)
177                                         glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+arr->offset);
178                                 else
179                                         glColorPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
180                         }
181                         array_type = GL_COLOR_ARRAY;
182                 }
183                 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
184                 {
185                         t -= get_component_type(TEXCOORD1);
186                         if(t>0 || active_tex)
187                         {
188                                 glClientActiveTexture(GL_TEXTURE0+t);
189                                 active_tex = t;
190                         }
191                         if(arr)
192                                 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+arr->offset);
193                         array_type = GL_TEXTURE_COORD_ARRAY;
194                 }
195                 else
196                 {
197                         if(t>=get_component_type(ATTRIB1))
198                                 t -= get_component_type(ATTRIB1);
199                         if(arr)
200                                 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+arr->offset);
201                 }
202
203                 // Only change enable state if needed
204                 if(arr && !old_arr)
205                 {
206                         if(array_type)
207                                 glEnableClientState(array_type);
208                         else
209                                 glEnableVertexAttribArray(t);
210                 }
211                 else if(old_arr && !arr)
212                 {
213                         if(array_type)
214                                 glDisableClientState(array_type);
215                         else
216                                 glDisableVertexAttribArray(t);
217                 }
218         }
219
220         if(active_tex)
221                 glClientActiveTexture(GL_TEXTURE0);
222 }
223
224
225 VertexArray::Array::Array():
226         component(0),
227         offset(0)
228 { }
229
230
231 VertexArray::Loader::Loader(VertexArray &a):
232         VertexArrayBuilder(a)
233 {
234         add("vertex2",   static_cast<void (Loader::*)(float, float)>(&Loader::vertex));
235         add("vertex3",   static_cast<void (Loader::*)(float, float, float)>(&Loader::vertex));
236         add("vertex4",   static_cast<void (Loader::*)(float, float, float, float)>(&Loader::vertex));
237         add("normal3",   static_cast<void (Loader::*)(float, float, float)>(&Loader::normal));
238         add("texcoord1", static_cast<void (Loader::*)(float)>(&Loader::texcoord));
239         add("texcoord2", static_cast<void (Loader::*)(float, float)>(&Loader::texcoord));
240         add("texcoord3", static_cast<void (Loader::*)(float, float, float)>(&Loader::texcoord));
241         add("texcoord4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::texcoord));
242         add("multitexcoord1", static_cast<void (Loader::*)(unsigned, float)>(&Loader::multitexcoord));
243         add("multitexcoord2", static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::multitexcoord));
244         add("multitexcoord3", static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::multitexcoord));
245         add("multitexcoord4", static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::multitexcoord));
246         add("color3",    static_cast<void (Loader::*)(float, float, float)>(&Loader::color));
247         add("color4",    static_cast<void (Loader::*)(float, float, float, float)>(&Loader::color));
248         add("attrib1",   static_cast<void (Loader::*)(unsigned, float)>(&Loader::attrib));
249         add("attrib2",   static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::attrib));
250         add("attrib3",   static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::attrib));
251         add("attrib4",   static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::attrib));
252         add("tangent3",  static_cast<void (Loader::*)(float, float, float)>(&Loader::tangent));
253         add("binormal3", static_cast<void (Loader::*)(float, float, float)>(&Loader::binormal));
254 }
255
256 } // namespace GL
257 } // namespace Msp