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