]> git.tdb.fi Git - libs/gl.git/blob - source/batch.cpp
Remove the EXT_draw_range_elements extension
[libs/gl.git] / source / batch.cpp
1 #include <msp/gl/extensions/arb_draw_instanced.h>
2 #include <msp/gl/extensions/msp_primitive_restart.h>
3 #include "batch.h"
4 #include "bindable.h"
5 #include "buffer.h"
6 #include "error.h"
7 #include "mesh.h"
8 #include "vertexarray.h"
9
10 using namespace std;
11
12 namespace {
13
14 template<typename T>
15 void append(vector<unsigned char> &data, T i)
16 {
17         data.insert(data.end(), sizeof(T), 0);
18         *(T *)(&data[data.size()-sizeof(T)]) = i;
19 }
20
21 template<typename T, typename U>
22 U convert(T n)
23 {
24         if(!static_cast<T>(~n))
25                 return ~0;
26         else
27                 return n;
28 }
29
30 template<typename T, typename U>
31 void expand(vector<unsigned char> &data)
32 {
33         unsigned count = data.size()/sizeof(T);
34         data.resize(count*sizeof(U));
35         for(unsigned i=count; i--;)
36                 *(U *)(&data[i*sizeof(U)]) = convert<T, U>(*(T *)(&data[i*sizeof(T)]));
37 }
38
39 template<typename T, typename U>
40 void shrink(vector<unsigned char> &data)
41 {
42         unsigned count = data.size()/sizeof(T);
43         for(unsigned i=0; i<count; ++i)
44                 *(U *)(&data[i*sizeof(U)]) = convert<T, U>(*(T *)(&data[i*sizeof(T)]));
45         data.resize(count*sizeof(U));
46 }
47
48 }
49
50 namespace Msp {
51 namespace GL {
52
53 unsigned Batch::restart_index = 0;
54
55 Batch::Batch(PrimitiveType t):
56         prim_type(t),
57         data_type(UNSIGNED_BYTE),
58         max_index(0),
59         restart(false)
60 { }
61
62 Batch::~Batch()
63 {
64 }
65
66 void Batch::set_data_type(DataType t)
67 {
68         if(t!=UNSIGNED_BYTE && t!=UNSIGNED_SHORT && t!=UNSIGNED_INT)
69                 throw invalid_argument("Batch::set_data_type");
70         if(t==UNSIGNED_BYTE && max_index>0xFE)
71                 throw invalid_operation("Batch::set_data_type");
72         else if(t==UNSIGNED_SHORT && max_index>0xFFFE)
73                 throw invalid_operation("Batch::set_data_type");
74
75         if(data_type==UNSIGNED_BYTE && t==UNSIGNED_SHORT)
76                 expand<unsigned char, unsigned short>(data);
77         else if(data_type==UNSIGNED_BYTE && t==UNSIGNED_INT)
78                 expand<unsigned char, unsigned>(data);
79         else if(data_type==UNSIGNED_SHORT && t==UNSIGNED_INT)
80                 expand<unsigned short, unsigned>(data);
81         else if(data_type==UNSIGNED_INT && t==UNSIGNED_BYTE)
82                 shrink<unsigned, unsigned char>(data);
83         else if(data_type==UNSIGNED_INT && t==UNSIGNED_SHORT)
84                 shrink<unsigned, unsigned short>(data);
85         else if(data_type==UNSIGNED_SHORT && t==UNSIGNED_BYTE)
86                 shrink<unsigned short, unsigned char>(data);
87
88         data_type = t;
89         update_offset();
90         dirty = true;
91 }
92
93 Batch &Batch::append(unsigned i)
94 {
95         append_index(i);
96
97         update_offset();
98         dirty = true;
99
100         return *this;
101 }
102
103 Batch &Batch::append(const vector<unsigned> &ind)
104 {
105         if(ind.empty())
106                 return *this;
107
108         data.reserve(data.size()+ind.size()*get_index_size());
109         for(vector<unsigned>::const_iterator i=ind.begin(); i!=ind.end(); ++i)
110                 append_index(*i);
111
112         update_offset();
113         dirty = true;
114
115         return *this;
116 }
117
118 bool Batch::can_append(PrimitiveType other_type)
119 {
120         if(other_type!=prim_type)
121                 return false;
122         else if(prim_type==LINE_STRIP || prim_type==LINE_LOOP || prim_type==TRIANGLE_FAN)
123                 return MSP_primitive_restart;
124         else
125                 return true;
126 }
127
128 Batch &Batch::append(const Batch &other)
129 {
130         if(other.prim_type!=prim_type)
131                 throw invalid_argument("Batch::append");
132         if(prim_type==LINE_STRIP || prim_type==LINE_LOOP || prim_type==TRIANGLE_FAN)
133                 static Require _req(MSP_primitive_restart);
134
135         if(other.data.empty())
136                 return *this;
137
138         if(prim_type==POINTS || prim_type==LINES || prim_type==TRIANGLES)
139                 ;
140         else if(MSP_primitive_restart)
141         {
142                 restart = true;
143                 if(data_type==UNSIGNED_SHORT)
144                         ::append<unsigned short>(data, 0xFFFF);
145                 else if(data_type==UNSIGNED_INT)
146                         ::append<unsigned>(data, 0xFFFFFFFF);
147                 else
148                         data.push_back(0xFF);
149         }
150         else if(prim_type==TRIANGLE_STRIP)
151         {
152                 append(get_index(size()-1));
153                 append(other.get_index(0));
154                 if(size()&1)
155                         append(other.get_index(0));
156         }
157
158         unsigned count = other.size();
159         for(unsigned i=0; i<count; ++i)
160                 append_index(other.get_index(i));
161
162         update_offset();
163         dirty = true;
164
165         return *this;
166 }
167
168 void Batch::append_index(unsigned i)
169 {
170         if(data.empty())
171                 max_index = i;
172         else
173                 max_index = max(max_index, i);
174
175         if((data_type==UNSIGNED_BYTE || data_type==UNSIGNED_SHORT) && max_index>0xFFFE)
176                 set_data_type(UNSIGNED_INT);
177         else if(data_type==UNSIGNED_BYTE && max_index>0xFE)
178                 set_data_type(UNSIGNED_SHORT);
179
180         if(data_type==UNSIGNED_SHORT)
181                 ::append<unsigned short>(data, i);
182         else if(data_type==UNSIGNED_INT)
183                 ::append<unsigned>(data, i);
184         else
185                 data.push_back(i);
186 }
187
188 unsigned Batch::get_index_size() const
189 {
190         if(data_type==UNSIGNED_SHORT)
191                 return sizeof(unsigned short);
192         else if(data_type==UNSIGNED_INT)
193                 return sizeof(unsigned);
194         return sizeof(unsigned char);
195 }
196
197 unsigned Batch::get_index(unsigned i) const
198 {
199         if(data_type==UNSIGNED_SHORT)
200                 return *(unsigned short *)&data[i*sizeof(unsigned short)];
201         else if(data_type==UNSIGNED_INT)
202                 return *(unsigned *)&data[i*sizeof(unsigned )];
203         else
204                 return data[i];
205 }
206
207 void Batch::draw() const
208 {
209         BindRestore _bind_ibuf(get_buffer(), ELEMENT_ARRAY_BUFFER);
210         const void *data_ptr = setup_draw();
211
212         glDrawElements(prim_type, size(), data_type, data_ptr);
213 }
214
215 void Batch::draw_instanced(unsigned count) const
216 {
217         static Require req(ARB_draw_instanced);
218
219         BindRestore _bind_ibuf(get_buffer(), ELEMENT_ARRAY_BUFFER);
220         const void *data_ptr = setup_draw();
221
222         glDrawElementsInstanced(prim_type, size(), data_type, data_ptr, count);
223 }
224
225 const void *Batch::setup_draw() const
226 {
227         if(restart)
228         {
229                 unsigned index;
230                 if(data_type==UNSIGNED_SHORT)
231                         index = 0xFFFF;
232                 else if(data_type==UNSIGNED_INT)
233                         index = 0xFFFFFFFF;
234                 else
235                         index = 0xFF;
236
237                 if(index!=restart_index)
238                         set_restart_index(index);
239         }
240         else if(restart_index && restart_index<=max_index)
241                 set_restart_index(0);
242
243         if(get_buffer())
244         {
245                 if(dirty)
246                         update_buffer();
247
248                 return reinterpret_cast<const void *>(get_offset());
249         }
250         else
251                 return &data[0];
252 }
253
254 void Batch::set_restart_index(unsigned index)
255 {
256         if(index>0)
257         {
258                 if(!restart_index)
259                         glEnable(GL_PRIMITIVE_RESTART);
260                 glPrimitiveRestartIndex(index);
261         }
262         else
263                 glDisable(GL_PRIMITIVE_RESTART);
264
265         restart_index = index;
266 }
267
268
269 Batch::Loader::Loader(Batch &b):
270         DataFile::ObjectLoader<Batch>(b)
271 {
272         add("indices", &Loader::indices);
273 }
274
275 void Batch::Loader::indices(const vector<unsigned> &ind)
276 {
277         obj.append(ind);
278 }
279
280 } // namespace GL
281 } // namespace Msp