]> git.tdb.fi Git - libs/gl.git/blob - source/vertexarray.cpp
Support multiple sets of texture coordinates in VertexArrays
[libs/gl.git] / source / vertexarray.cpp
1 /* $Id$
2
3 This file is part of libmspgl
4 Copyright © 2007-2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include "arb_vertex_program.h"
9 #include "extension.h"
10 #include "gl.h"
11 #include "version_1_2.h"
12 #include "vertexarray.h"
13 #include "vertexbuffer.h"
14
15 using namespace std;
16
17 namespace Msp {
18 namespace GL {
19
20 VertexArray::VertexArray(const VertexFormat &f):
21         vbuf(0),
22         own_vbuf(false)
23 {
24         reset(f);
25 }
26
27 VertexArray::~VertexArray()
28 {
29         if(own_vbuf)
30                 delete vbuf;
31 }
32
33 void VertexArray::use_vertex_buffer()
34 {
35         if(vbuf && own_vbuf)
36                 return;
37
38         vbuf = new Buffer(ARRAY_BUFFER);
39         own_vbuf = true;
40
41         update_data();
42 }
43
44 void VertexArray::use_vertex_buffer(Buffer *b)
45 {
46         if(own_vbuf)
47                 delete vbuf;
48         vbuf = b;
49         own_vbuf = false;
50
51         update_data();
52 }
53
54 void VertexArray::reserve(unsigned n)
55 {
56         data.reserve(n*stride);
57 }
58
59 void VertexArray::clear()
60 {
61         data.clear();
62 }
63
64 void VertexArray::reset(const VertexFormat &f)
65 {
66         clear();
67         format = f;
68         stride = get_stride(format);
69
70         bool has_multitex = false;
71         bool has_gen_attrs = false;
72         for(const unsigned char *c=format.begin(); c!=format.end(); ++c)
73         {
74                 if(*c>=TEXCOORD1+4 && *c<ATTRIB1)
75                         has_multitex = true;
76                 if(*c>=ATTRIB1)
77                         has_gen_attrs = true;
78         }
79         if(has_multitex)
80                 static RequireVersion _ver(1, 3);
81         if(has_gen_attrs)
82                 static RequireExtension _ext("GL_ARB_vertex_program");
83 }
84
85 void VertexArray::apply() const
86 {
87         if(format.empty())
88                 throw InvalidState("Trying to apply a vertex array with no data");
89
90         if(vbuf)
91                 vbuf->bind();
92
93         const float *base = vbuf?0:&data[0];
94         unsigned offset = 0;
95         ArrayMask found;
96         unsigned bpv = stride*sizeof(float);
97         unsigned active_tex = 0;
98         for(const unsigned char *c=format.begin(); c!=format.end(); ++c)
99         {
100                 unsigned sz = (*c&3)+1;
101                 unsigned t = *c>>2;
102                 bool en = enabled_arrays.is_set(t);
103                 switch(t)
104                 {
105                 case 0:
106                         glVertexPointer(sz, GL_FLOAT, bpv, base+offset);
107                         if(!en)
108                                 glEnableClientState(GL_VERTEX_ARRAY);
109                         break;
110                 case 1:
111                         glNormalPointer(GL_FLOAT, bpv, base+offset);
112                         if(!en)
113                                 glEnableClientState(GL_NORMAL_ARRAY);
114                         break;
115                 case 2:
116                         if(sz==1)
117                                 glColorPointer(4, GL_UNSIGNED_BYTE, bpv, base+offset);
118                         else
119                                 glColorPointer(sz, GL_FLOAT, bpv, base+offset);
120                         if(!en)
121                                 glEnableClientState(GL_COLOR_ARRAY);
122                         break;
123                 default:
124                         if(t<11)
125                         {
126                                 if(t>3 || active_tex)
127                                 {
128                                         glClientActiveTexture(GL_TEXTURE0+(t-3));
129                                         active_tex = t-3;
130                                 }
131                                 glTexCoordPointer(sz, GL_FLOAT, bpv, base+offset);
132                                 if(!en)
133                                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
134                         }
135                         else
136                         {
137                                 glVertexAttribPointerARB(t-11, sz, GL_FLOAT, false, bpv, base+offset);
138                                 if(!en)
139                                         glEnableVertexAttribArrayARB(t-11);
140                         }
141                         break;
142                 }
143                 found.set(t);
144                 offset += sz;
145         }
146
147         for(unsigned i=0; i<64; ++i)
148                 if(enabled_arrays.is_set(i) && !found.is_set(i))
149                 {
150                         if(i==0)
151                                 glDisableClientState(GL_VERTEX_ARRAY);
152                         else if(i==1)
153                                 glDisableClientState(GL_NORMAL_ARRAY);
154                         else if(i==2)
155                                 glDisableClientState(GL_COLOR_ARRAY);
156                         else if(i>=3 && i<11)
157                         {
158                                 if(i>3 || active_tex)
159                                         glClientActiveTexture(GL_TEXTURE0+(i-3));
160                                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
161                         }
162                         else
163                                 glDisableVertexAttribArrayARB(i-11);
164                 }
165
166         enabled_arrays = found;
167
168         if(active_tex)
169                 glClientActiveTexture(GL_TEXTURE0);
170
171         if(vbuf)
172                 vbuf->unbind();
173 }
174
175 /**
176 Updates the VertexArray data to the VertexBuffer tied to the array, if any.
177 */
178 void VertexArray::update_data()
179 {
180         if(vbuf)
181         {
182                 vbuf->data(data.size()*sizeof(float), &data[0]);
183                 vbuf->unbind();
184         }
185 }
186
187 float *VertexArray::append()
188 {
189         data.insert(data.end(), stride, 0.0f);
190         return &*data.end()-stride;
191 }
192
193 VertexArray::ArrayMask VertexArray::enabled_arrays;
194
195
196 VertexArray::ArrayMask::ArrayMask()
197 {
198         for(unsigned i=0; i<N; ++i)
199                 mask[i] = 0;
200 }
201
202 void VertexArray::ArrayMask::set(unsigned bit)
203 {
204         mask[bit/B] |= 1<<(bit%B);
205 }
206
207 bool VertexArray::ArrayMask::is_set(unsigned bit) const
208 {
209         return mask[bit/B]&(1<<(bit%B));
210 }
211
212
213 VertexArray::Loader::Loader(VertexArray &a):
214         VertexArrayBuilder(a)
215 {
216         add("vertex2",   static_cast<void (Loader::*)(float, float)>(&Loader::vertex));
217         add("vertex3",   static_cast<void (Loader::*)(float, float, float)>(&Loader::vertex));
218         add("vertex4",   static_cast<void (Loader::*)(float, float, float, float)>(&Loader::vertex));
219         add("normal3",   static_cast<void (Loader::*)(float, float, float)>(&Loader::normal));
220         add("texcoord1", static_cast<void (Loader::*)(float)>(&Loader::texcoord));
221         add("texcoord2", static_cast<void (Loader::*)(float, float)>(&Loader::texcoord));
222         add("texcoord3", static_cast<void (Loader::*)(float, float, float)>(&Loader::texcoord));
223         add("texcoord4", static_cast<void (Loader::*)(float, float, float, float)>(&Loader::texcoord));
224         add("color3",    static_cast<void (Loader::*)(float, float, float)>(&Loader::color));
225         add("color4",    static_cast<void (Loader::*)(float, float, float, float)>(&Loader::color));
226         add("attrib1",   static_cast<void (Loader::*)(unsigned, float)>(&Loader::attrib));
227         add("attrib2",   static_cast<void (Loader::*)(unsigned, float, float)>(&Loader::attrib));
228         add("attrib3",   static_cast<void (Loader::*)(unsigned, float, float, float)>(&Loader::attrib));
229         add("attrib4",   static_cast<void (Loader::*)(unsigned, float, float, float, float)>(&Loader::attrib));
230 }
231
232
233 void array_element(int i)
234 {
235         glArrayElement(i);
236 }
237
238 void draw_arrays(PrimitiveType mode, int first, unsigned count)
239 {
240         glDrawArrays(mode, first, count);
241 }
242
243 void draw_elements(PrimitiveType mode, unsigned count, DataType type, const void *indices)
244 {
245         glDrawElements(mode, count, type, indices);
246 }
247
248 void draw_range_elements(PrimitiveType mode, unsigned low, unsigned high, unsigned count, DataType type, const void *indices)
249 {
250         static RequireVersion _ver(1, 2);
251         glDrawRangeElements(mode, low, high, count, type, indices);
252 }
253
254 } // namespace GL
255 } // namespace Msp