5 #include "ext_draw_range_elements.h"
6 #include "nv_primitive_restart.h"
7 #include "vertexarray.h"
14 unsigned Batch::restart_index = 0;
16 Batch::Batch(PrimitiveType t):
18 data_type(UNSIGNED_BYTE),
28 /* XXX Should probably provide a fallback to glDrawElements since this class
29 is pretty much required to render anything. */
30 static Require _req(EXT_draw_range_elements);
38 void Batch::set_data_type(DataType t)
40 if(t!=UNSIGNED_BYTE && t!=UNSIGNED_SHORT && t!=UNSIGNED_INT)
41 throw invalid_argument("Batch::set_data_type");
42 if(t==UNSIGNED_BYTE && max_index>0xFE)
43 throw invalid_operation("Batch::set_data_type");
44 else if(t==UNSIGNED_SHORT && max_index>0xFFFE)
45 throw invalid_operation("Batch::set_data_type");
47 if(data_type==UNSIGNED_BYTE && t==UNSIGNED_SHORT)
48 expand_data<unsigned char, unsigned short>();
49 else if(data_type==UNSIGNED_BYTE && t==UNSIGNED_INT)
50 expand_data<unsigned char, unsigned>();
51 else if(data_type==UNSIGNED_SHORT && t==UNSIGNED_INT)
52 expand_data<unsigned short, unsigned>();
53 else if(data_type==UNSIGNED_INT && t==UNSIGNED_BYTE)
54 shrink_data<unsigned, unsigned char>();
55 else if(data_type==UNSIGNED_INT && t==UNSIGNED_SHORT)
56 shrink_data<unsigned, unsigned short>();
57 else if(data_type==UNSIGNED_SHORT && t==UNSIGNED_BYTE)
58 shrink_data<unsigned short, unsigned char>();
61 update_ibuf_offsets();
65 void Batch::use_index_buffer(Buffer *buf, Batch *prev)
67 if(buf && prev && prev->ibuf!=buf)
68 throw invalid_argument("Batch::use_index_buffer");
81 prev->next_in_ibuf = this;
82 ibuf_offset = prev->ibuf_offset+prev->data.size();
90 Batch &Batch::append(unsigned i)
93 min_index = max_index = i;
96 min_index = min(min_index, i);
97 max_index = max(max_index, i);
100 if((data_type==UNSIGNED_BYTE || data_type==UNSIGNED_SHORT) && max_index>0xFFFE)
101 set_data_type(UNSIGNED_INT);
102 else if(data_type==UNSIGNED_BYTE && max_index>0xFE)
103 set_data_type(UNSIGNED_SHORT);
105 if(data_type==UNSIGNED_SHORT)
106 append_index<unsigned short>(i);
107 else if(data_type==UNSIGNED_INT)
108 append_index<unsigned>(i);
112 update_ibuf_offsets();
118 void Batch::append(const vector<unsigned> &ind)
124 min_index = max_index = ind.front();
126 for(vector<unsigned>::const_iterator i=ind.begin(); i!=ind.end(); ++i)
128 min_index = min(min_index, *i);
129 max_index = max(max_index, *i);
132 if((data_type==UNSIGNED_BYTE || data_type==UNSIGNED_SHORT) && max_index>0xFFFE)
133 set_data_type(UNSIGNED_INT);
134 else if(data_type==UNSIGNED_BYTE && max_index>0xFE)
135 set_data_type(UNSIGNED_SHORT);
137 unsigned base = data.size();
138 data.resize(data.size()+ind.size()*get_index_size());
139 if(data_type==UNSIGNED_SHORT)
141 unsigned short *ptr = reinterpret_cast<unsigned short *>(&data[base]);
142 for(unsigned i=0; i<ind.size(); ++i)
145 else if(data_type==UNSIGNED_INT)
147 unsigned *ptr = reinterpret_cast<unsigned *>(&data[base]);
148 for(unsigned i=0; i<ind.size(); ++i)
153 for(unsigned i=0; i<ind.size(); ++i)
154 data[base+i] = ind[i];
158 void Batch::append(const Batch &other)
160 if(other.prim_type!=prim_type)
161 throw invalid_argument("Batch::append");
162 if(prim_type==LINE_STRIP || prim_type==LINE_LOOP)
163 throw incompatible_data("Batch::append");
164 else if(prim_type==POLYGON)
165 throw incompatible_data("Batch::append");
166 else if(prim_type==TRIANGLE_FAN)
167 static Require _req(NV_primitive_restart);
169 if(other.data.empty())
172 if(NV_primitive_restart)
175 if(data_type==UNSIGNED_SHORT)
176 append_index<unsigned short>(0xFFFF);
177 else if(data_type==UNSIGNED_INT)
178 append_index<unsigned>(0xFFFFFFFF);
180 data.push_back(0xFF);
182 else if(prim_type==TRIANGLE_STRIP)
184 append(get_index(size()-1));
185 append(other.get_index(0));
187 append(other.get_index(0));
189 else if(prim_type==QUAD_STRIP)
191 append(get_index(size()-1));
192 append(get_index(size()-1));
193 append(other.get_index(0));
194 append(other.get_index(0));
197 unsigned count = other.size();
198 for(unsigned i=0; i<count; ++i)
199 append(other.get_index(i));
202 void Batch::draw() const
207 if(data_type==UNSIGNED_SHORT)
209 else if(data_type==UNSIGNED_INT)
214 if(index!=restart_index)
217 glEnableClientState(GL_PRIMITIVE_RESTART_NV);
218 glPrimitiveRestartIndexNV(index);
219 restart_index = index;
222 else if(restart_index && restart_index<max_index)
224 glDisableClientState(GL_PRIMITIVE_RESTART_NV);
232 const Batch *b = this;
233 for(; b->prev_in_ibuf; b=b->prev_in_ibuf) ;
235 unsigned chain_size = 0;
236 for(const Batch *a=b; a; a=a->next_in_ibuf)
237 chain_size += a->data.size();
239 ibuf->data(chain_size, 0);
241 for(; b; b=b->next_in_ibuf)
243 ibuf->sub_data(b->ibuf_offset, b->data.size(), &b->data[0]);
248 BufferAlias<ELEMENT_ARRAY_BUFFER> alias(*ibuf);
249 Bind bind_ibuf(alias, true);
251 glDrawRangeElements(prim_type, min_index, max_index, size(), data_type, reinterpret_cast<void *>(ibuf_offset));
254 glDrawRangeElements(prim_type, min_index, max_index, size(), data_type, &data[0]);
257 unsigned Batch::get_index_size() const
259 if(data_type==UNSIGNED_SHORT)
260 return sizeof(unsigned short);
261 else if(data_type==UNSIGNED_INT)
262 return sizeof(unsigned);
263 return sizeof(unsigned char);
267 void Batch::append_index(T i)
269 data.insert(data.end(), sizeof(T), 0);
270 *(T *)(&data[data.size()-sizeof(T)]) = i;
273 unsigned Batch::get_index(unsigned i) const
275 if(data_type==UNSIGNED_SHORT)
276 return *(unsigned short *)&data[i*sizeof(unsigned short)];
277 else if(data_type==UNSIGNED_INT)
278 return *(unsigned *)&data[i*sizeof(unsigned )];
283 template<typename T, typename U>
284 void Batch::expand_data()
286 unsigned count = data.size()/sizeof(T);
287 data.resize(count*sizeof(U));
288 for(unsigned i=count; i--;)
289 *(U *)(&data[i*sizeof(U)]) = convert<T, U>(*(T *)(&data[i*sizeof(T)]));
292 template<typename T, typename U>
293 void Batch::shrink_data()
295 unsigned count = data.size()/sizeof(T);
296 for(unsigned i=0; i<count; ++i)
297 *(U *)(&data[i*sizeof(U)]) = convert<T, U>(*(T *)(&data[i*sizeof(T)]));
298 data.resize(count*sizeof(U));
301 template<typename T, typename U>
302 U Batch::convert(T i) const
304 if(!static_cast<T>(~i))
310 void Batch::unlink_from_ibuf()
313 next_in_ibuf->prev_in_ibuf = prev_in_ibuf;
316 prev_in_ibuf->next_in_ibuf = next_in_ibuf;
317 prev_in_ibuf->update_ibuf_offsets();
319 else if(next_in_ibuf)
321 next_in_ibuf->ibuf_offset = 0;
322 next_in_ibuf->update_ibuf_offsets();
326 void Batch::update_ibuf_offsets()
328 for(Batch *b=this; b->next_in_ibuf; b=b->next_in_ibuf)
329 b->next_in_ibuf->ibuf_offset = b->ibuf_offset+b->data.size();
333 Batch::Loader::Loader(Batch &b):
334 DataFile::ObjectLoader<Batch>(b)
336 add("indices", &Loader::indices);
339 void Batch::Loader::indices(const vector<unsigned> &ind)