]> git.tdb.fi Git - libs/gl.git/blob - source/vertexarray.cpp
Add vertex arrays and buffers
[libs/gl.git] / source / vertexarray.cpp
1 #include <GL/gl.h>
2 #include "vertexarray.h"
3 #include "vertexbuffer.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9
10 uint get_stride(VertexFormat f)
11 {
12         uint stride=0;
13         for(uint fmt=f; fmt; fmt>>=4)
14                 stride+=(fmt&3)+1;
15         return stride*sizeof(float);
16 }
17
18
19 VertexArrayBuilder::VertexArrayBuilder(VertexArray &a, vector<float> &d):
20         data(d),
21         array(a),
22         format(array.get_format()),
23         stride(get_stride(format)),
24         cr(1), cg(1), cb(1), ca(1),
25         ts(0), tt(0), tr(0), tq(0),
26         nx(0), ny(0), nz(1)
27 { }
28
29 void VertexArrayBuilder::vertex(float x, float y, float z, float w)
30 {
31         for(uint fmt=format; fmt; fmt>>=4)
32         {
33                 uint size=(fmt&3)+1;
34                 switch(fmt&12)
35                 {
36                 case 0:
37                         data.push_back(x);
38                         data.push_back(y);
39                         if(size>=3) data.push_back(z);
40                         if(size>=4) data.push_back(w);
41                         break;
42                 case 4:
43                         data.push_back(nx);
44                         data.push_back(ny);
45                         data.push_back(nz);
46                         break;
47                 case 8:
48                         data.push_back(ts);
49                         if(size>=2) data.push_back(tt);
50                         if(size>=3) data.push_back(tr);
51                         if(size>=4) data.push_back(tq);
52                         break;
53                 case 12:
54                         if(size==1)
55                         {
56                                 union { ubyte c[4]; float f; } u;
57                                 u.c[0]=(ubyte)(cr*255);
58                                 u.c[1]=(ubyte)(cg*255);
59                                 u.c[2]=(ubyte)(cb*255);
60                                 u.c[3]=(ubyte)(ca*255);
61                                 data.push_back(u.f);
62                         }
63                         else
64                         {
65                                 data.push_back(cr);
66                                 data.push_back(cg);
67                                 data.push_back(cb);
68                                 if(size>=4) data.push_back(ca);
69                         }
70                         break;
71                 }
72         }
73         //cout<<"Added vertex with "<<data.size()-old_size<<" floats\n";
74 }
75
76 VertexArrayBuilder::~VertexArrayBuilder()
77 {
78         array.update_data();
79 }
80
81
82 VertexArray::VertexArray(VertexFormat f):
83         format(NODATA),
84         stride(get_stride(f)),
85         vbuf(0),
86         own_vbuf(false)
87 {
88         // Reverse the format so the first item is in lowest bits
89         for(uint fmt=f; fmt; fmt>>=4)
90                 format=(format, static_cast<VertexFormat>(fmt&15));
91 }
92
93 VertexArray::~VertexArray()
94 {
95         if(own_vbuf)
96                 delete vbuf;
97 }
98
99 void VertexArray::use_vertex_buffer()
100 {
101         if(vbuf) return;
102
103         vbuf=new VertexBuffer();
104         own_vbuf=true;
105         update_data();
106 }
107
108 void VertexArray::use_vertex_buffer(VertexBuffer *b)
109 {
110         if(vbuf) return;
111
112         vbuf=b;
113         update_data();
114 }
115
116 void VertexArray::clear()
117 {
118         data.clear();
119 }
120
121 void VertexArray::apply() const
122 {
123         if(vbuf) vbuf->bind();
124
125         const float *base=vbuf?0:&data[0];
126         uint offset=0;
127         uint found=0;
128         for(uint fmt=format; fmt; fmt>>=4)
129         {
130                 uint size=(fmt&3)+1;
131                 switch(fmt&12)
132                 {
133                 case 0:
134                         glVertexPointer(size, GL_FLOAT, stride, base+offset);
135                         break;
136                 case 4:
137                         glNormalPointer(GL_FLOAT, stride, base+offset);
138                         break;
139                 case 8:
140                         glTexCoordPointer(size, GL_FLOAT, stride, base+offset);
141                         break;
142                 case 12:
143                         if(size==1)
144                                 glColorPointer(4, GL_UNSIGNED_BYTE, stride, base+offset);
145                         else
146                                 glColorPointer(size, GL_FLOAT, stride, base+offset);
147                         break;
148                 }
149                 found|=1<<((fmt&12)>>2);
150                 offset+=size;
151         }
152
153         set_array(GL_VERTEX_ARRAY, found&1, 1);
154         set_array(GL_NORMAL_ARRAY, found&2, 2);
155         set_array(GL_TEXTURE_COORD_ARRAY, found&4, 4);
156         set_array(GL_COLOR_ARRAY, found&8, 8);
157
158         VertexBuffer::unbind();
159 }
160
161 /**
162 Updates the VertexArray data to the VertexBuffer tied to the array, if any.
163 */
164 void VertexArray::update_data()
165 {
166         if(vbuf)
167                 vbuf->data(data.size()*sizeof(float), &data[0]);
168 }
169
170 void VertexArray::set_array(unsigned array, unsigned bit, unsigned mask) const
171 {
172         if((enabled_arrays&mask) && !bit)
173         {
174                 glDisableClientState(array);
175                 enabled_arrays&=~mask;
176         }
177         else if(!(enabled_arrays&mask) && bit)
178         {
179                 glEnableClientState(array);
180                 enabled_arrays|=mask;
181         }
182 }
183
184 unsigned VertexArray::enabled_arrays=0;
185
186
187 } // namespace GL
188 } // namespace Msp