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