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