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