]> git.tdb.fi Git - libs/gl.git/blob - source/vertexarray.cpp
Rework vertex array application
[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
23 void VertexArray::reset(const VertexFormat &f)
24 {
25         clear();
26         format = f;
27         stride = get_stride(format);
28
29         arrays.clear();
30
31         for(const unsigned char *c=format.begin(); c!=format.end(); ++c)
32         {
33                 unsigned slot = get_array_slot(*c);
34                 if(slot>=arrays.size())
35                         arrays.resize(slot+1);
36                 arrays[slot] = *c;
37         }
38 }
39
40 unsigned VertexArray::get_array_slot(unsigned char comp)
41 {
42         unsigned t = get_component_type(comp);
43         if(t==get_component_type(VERTEX3))
44                 return 0;
45         else if(t==get_component_type(NORMAL3))
46                 return 1;
47         else if(t==get_component_type(COLOR4_FLOAT))
48                 return 2;
49         else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
50         {
51                 t -= get_component_type(TEXCOORD1);
52                 if(t>0)
53                         static Require _req(ARB_multitexture);
54                 return 3+t;
55         }
56         else
57         {
58                 static Require _req(ARB_vertex_shader);
59                 if(comp>=ATTRIB1)
60                         t -= get_component_type(ATTRIB1);
61                 return 7+t;
62         }
63 }
64
65 void VertexArray::use_vertex_buffer()
66 {
67         if(vbuf)
68                 return;
69
70         vbuf = new Buffer(ARRAY_BUFFER);
71         defer_vbuf = false;
72         dirty = true;
73 }
74
75 void VertexArray::use_vertex_buffer(Buffer *b)
76 {
77         vbuf = b;
78         vbuf.keep();
79         defer_vbuf = false;
80         dirty = true;
81 }
82
83 void VertexArray::clear()
84 {
85         data.clear();
86 }
87
88 void VertexArray::reserve(unsigned n)
89 {
90         data.reserve(n*stride);
91 }
92
93 float *VertexArray::append()
94 {
95         data.insert(data.end(), stride, 0.0f);
96         set_dirty();
97         return &*(data.end()-stride);
98 }
99
100 float *VertexArray::modify(unsigned i)
101 {
102         set_dirty();
103         return &data[0]+i*stride;
104 }
105
106 void VertexArray::set_dirty()
107 {
108         dirty = true;
109         if(defer_vbuf)
110         {
111                 vbuf = new Buffer(ARRAY_BUFFER);
112                 defer_vbuf = false;
113         }
114 }
115
116 void VertexArray::apply() const
117 {
118         if(format.empty())
119                 throw invalid_operation("VertexArray::apply");
120
121         const VertexArray *old = current();
122         if(!set_current(this))
123                 return;
124
125         if(vbuf)
126         {
127                 vbuf->bind_to(ARRAY_BUFFER);
128                 if(dirty)
129                 {
130                         vbuf->data(data.size()*sizeof(float), &data[0]);
131                         dirty = false;
132                 }
133         }
134
135         const float *base = (vbuf ? 0 : &data[0]);
136         unsigned offset = 0;
137         unsigned stride_bytes = stride*sizeof(float);
138         unsigned active_tex = 0;
139         unsigned n_arrays = arrays.size();
140         if(old)
141                 n_arrays = max(n_arrays, old->arrays.size());
142         for(unsigned i=0; i<n_arrays; ++i)
143         {
144                 unsigned char arr = (i<arrays.size() ? arrays[i] : 0);
145                 unsigned char old_arr = (old && i<old->arrays.size() ? old->arrays[i] : 0);
146                 if(!arr && !old_arr)
147                         continue;
148
149                 unsigned char comp = (arr ? arr : old_arr);
150                 unsigned sz = get_component_size(comp);
151                 unsigned t = get_component_type(comp);
152                 GLenum array_type = 0;
153                 if(t==get_component_type(VERTEX3))
154                 {
155                         if(arr)
156                                 glVertexPointer(sz, GL_FLOAT, stride_bytes, base+offset);
157                         array_type = GL_VERTEX_ARRAY;
158                 }
159                 else if(t==get_component_type(NORMAL3))
160                 {
161                         if(arr)
162                                 glNormalPointer(GL_FLOAT, stride_bytes, base+offset);
163                         array_type = GL_NORMAL_ARRAY;
164                 }
165                 else if(t==get_component_type(COLOR4_FLOAT))
166                 {
167                         if(arr)
168                         {
169                                 if(sz==1)
170                                         glColorPointer(4, GL_UNSIGNED_BYTE, stride_bytes, base+offset);
171                                 else
172                                         glColorPointer(sz, GL_FLOAT, stride_bytes, base+offset);
173                         }
174                         array_type = GL_COLOR_ARRAY;
175                 }
176                 else if(comp>=TEXCOORD1 && comp<=TEXCOORD4+12)
177                 {
178                         t -= get_component_type(TEXCOORD1);
179                         if(t>0 || active_tex)
180                         {
181                                 glClientActiveTexture(GL_TEXTURE0+t);
182                                 active_tex = t;
183                         }
184                         if(arr)
185                                 glTexCoordPointer(sz, GL_FLOAT, stride_bytes, base+offset);
186                         array_type = GL_TEXTURE_COORD_ARRAY;
187                 }
188                 else
189                 {
190                         if(t>=get_component_type(ATTRIB1))
191                                 t -= get_component_type(ATTRIB1);
192                         if(arr)
193                                 glVertexAttribPointer(t, sz, GL_FLOAT, false, stride_bytes, base+offset);
194                 }
195
196                 // Only change enable state if needed
197                 if(arr && !old_arr)
198                 {
199                         if(array_type)
200                                 glEnableClientState(array_type);
201                         else
202                                 glEnableVertexAttribArray(t);
203                 }
204                 else if(old_arr && !arr)
205                 {
206                         if(array_type)
207                                 glDisableClientState(array_type);
208                         else
209                                 glDisableVertexAttribArray(t);
210                 }
211
212                 if(arr)
213                         offset += sz;
214         }
215
216         if(active_tex)
217                 glClientActiveTexture(GL_TEXTURE0);
218
219         if(vbuf)
220                 Buffer::unbind_from(ARRAY_BUFFER);
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