X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fbatch.cpp;h=1260c6abe5e995203af5ff3a70d10ce9fc1d8d63;hp=9ed20a1f524dc5d334c2825a8867f77cc8ea31f5;hb=f14435e58bfa0fa697a06ba9a454bb30cd37d9d8;hpb=ceae2a27dfc58310c5bab7e3aa3fedf0fa9a1f49 diff --git a/source/batch.cpp b/source/batch.cpp index 9ed20a1f..1260c6ab 100644 --- a/source/batch.cpp +++ b/source/batch.cpp @@ -1,12 +1,8 @@ -/* $Id$ - -This file is part of libmspgl -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - #include "batch.h" +#include "bindable.h" +#include "buffer.h" #include "extension.h" +#include "nv_primitive_restart.h" #include "vertexarray.h" using namespace std; @@ -14,41 +10,318 @@ using namespace std; namespace Msp { namespace GL { +unsigned Batch::restart_index = 0; + Batch::Batch(PrimitiveType t): - type(t), + prim_type(t), + data_type(UNSIGNED_BYTE), min_index(0), - max_index(0) + max_index(0), + restart(false), + ibuf(0), + ibuf_offset(0), + next_in_ibuf(0), + prev_in_ibuf(0), + dirty(false) { } +Batch::~Batch() +{ + unlink_from_ibuf(); +} + +void Batch::set_data_type(DataType t) +{ + if(t!=UNSIGNED_BYTE && t!=UNSIGNED_SHORT && t!=UNSIGNED_INT) + throw InvalidParameterValue("Batch data type must be an unsigned integer"); + if(t==UNSIGNED_BYTE && max_index>0xFE) + throw InvalidState("UNSIGNED_BYTE can't hold all indices in Batch"); + else if(t==UNSIGNED_SHORT && max_index>0xFFFE) + throw InvalidState("UNSIGNED_SHORT can't hold all indices in Batch"); + + if(data_type==UNSIGNED_BYTE && t==UNSIGNED_SHORT) + expand_data(); + else if(data_type==UNSIGNED_BYTE && t==UNSIGNED_INT) + expand_data(); + else if(data_type==UNSIGNED_SHORT && t==UNSIGNED_INT) + expand_data(); + else if(data_type==UNSIGNED_INT && t==UNSIGNED_BYTE) + shrink_data(); + else if(data_type==UNSIGNED_INT && t==UNSIGNED_SHORT) + shrink_data(); + else if(data_type==UNSIGNED_SHORT && t==UNSIGNED_BYTE) + shrink_data(); + + data_type = t; + update_ibuf_offsets(); + dirty = true; +} + +void Batch::use_index_buffer(Buffer *buf, Batch *prev) +{ + if(buf && prev && prev->ibuf!=buf) + throw InvalidParameterValue("Previous batch is not in the same buffer"); + + if(!buf) + { + prev = 0; + unlink_from_ibuf(); + } + + ibuf = buf; + prev_in_ibuf = prev; + next_in_ibuf = 0; + if(prev) + { + prev->next_in_ibuf = this; + ibuf_offset = prev->ibuf_offset+prev->data.size(); + } + else + ibuf_offset = 0; + + dirty = true; +} + Batch &Batch::append(unsigned i) { - if(indices.empty()) - min_index=max_index=i; + if(data.empty()) + min_index = max_index = i; else { - min_index=min(min_index, i); - max_index=max(max_index, i); + min_index = min(min_index, i); + max_index = max(max_index, i); } - indices.push_back(i); + + if((data_type==UNSIGNED_BYTE || data_type==UNSIGNED_SHORT) && max_index>0xFFFE) + set_data_type(UNSIGNED_INT); + else if(data_type==UNSIGNED_BYTE && max_index>0xFE) + set_data_type(UNSIGNED_SHORT); + + if(data_type==UNSIGNED_SHORT) + append_index(i); + else if(data_type==UNSIGNED_INT) + append_index(i); + else + data.push_back(i); + + update_ibuf_offsets(); + dirty = true; return *this; } void Batch::append(const vector &ind) { - indices.reserve(indices.size()+ind.size()); + if(ind.empty()) + return; + + if(data.empty()) + min_index = max_index = ind.front(); + for(vector::const_iterator i=ind.begin(); i!=ind.end(); ++i) - append(*i); + { + min_index = min(min_index, *i); + max_index = max(max_index, *i); + } + + if((data_type==UNSIGNED_BYTE || data_type==UNSIGNED_SHORT) && max_index>0xFFFE) + set_data_type(UNSIGNED_INT); + else if(data_type==UNSIGNED_BYTE && max_index>0xFE) + set_data_type(UNSIGNED_SHORT); + + unsigned base = data.size(); + data.resize(data.size()+ind.size()*get_index_size()); + if(data_type==UNSIGNED_SHORT) + { + unsigned short *ptr = reinterpret_cast(&data[base]); + for(unsigned i=0; i(&data[base]); + for(unsigned i=0; i(0xFFFF); + else if(data_type==UNSIGNED_INT) + append_index(0xFFFFFFFF); + else + data.push_back(0xFF); + } + else if(prim_type==TRIANGLE_STRIP) + { + append(get_index(size()-1)); + append(other.get_index(0)); + if(size()&1) + append(other.get_index(0)); + } + else if(prim_type==QUAD_STRIP) + { + append(get_index(size()-1)); + append(get_index(size()-1)); + append(other.get_index(0)); + append(other.get_index(0)); + } + + unsigned count = other.size(); + for(unsigned i=0; iprev_in_ibuf; b=b->prev_in_ibuf) ; + + unsigned chain_size = 0; + for(const Batch *a=b; a; a=a->next_in_ibuf) + chain_size += a->data.size(); + + ibuf->data(chain_size, 0); + + for(; b; b=b->next_in_ibuf) + { + ibuf->sub_data(b->ibuf_offset, b->data.size(), &b->data[0]); + b->dirty = false; + } + } + + BufferAlias alias(*ibuf); + Bind bind_ibuf(alias, true); + + glDrawRangeElements(prim_type, min_index, max_index, size(), data_type, (void *)ibuf_offset); + } + else + glDrawRangeElements(prim_type, min_index, max_index, size(), data_type, &data[0]); +} + +unsigned Batch::get_index_size() const +{ + if(data_type==UNSIGNED_SHORT) + return sizeof(unsigned short); + else if(data_type==UNSIGNED_INT) + return sizeof(unsigned); + return sizeof(unsigned char); +} + +template +void Batch::append_index(T i) +{ + data.insert(data.end(), sizeof(T), 0); + *(T *)(&data[data.size()-sizeof(T)]) = i; +} + +unsigned Batch::get_index(unsigned i) const +{ + if(data_type==UNSIGNED_SHORT) + return *(unsigned short *)&data[i*sizeof(unsigned short)]; + else if(data_type==UNSIGNED_INT) + return *(unsigned *)&data[i*sizeof(unsigned )]; + else + return data[i]; +} + +template +void Batch::expand_data() +{ + unsigned count = data.size()/sizeof(T); + data.resize(count*sizeof(U)); + for(unsigned i=count; i--;) + *(U *)(&data[i*sizeof(U)]) = convert(*(T *)(&data[i*sizeof(T)])); +} + +template +void Batch::shrink_data() +{ + unsigned count = data.size()/sizeof(T); + for(unsigned i=0; i(*(T *)(&data[i*sizeof(T)])); + data.resize(count*sizeof(U)); +} + +template +U Batch::convert(T i) const +{ + if(!static_cast(~i)) + return ~0; + else + return i; +} + +void Batch::unlink_from_ibuf() +{ + if(next_in_ibuf) + next_in_ibuf->prev_in_ibuf = prev_in_ibuf; + if(prev_in_ibuf) + { + prev_in_ibuf->next_in_ibuf = next_in_ibuf; + prev_in_ibuf->update_ibuf_offsets(); + } + else if(next_in_ibuf) + { + next_in_ibuf->ibuf_offset = 0; + next_in_ibuf->update_ibuf_offsets(); + } } -void Batch::draw_with_buffer(unsigned offset) const +void Batch::update_ibuf_offsets() { - draw_range_elements(type, min_index, max_index, indices.size(), (unsigned *)0+offset); + for(Batch *b=this; b->next_in_ibuf; b=b->next_in_ibuf) + b->next_in_ibuf->ibuf_offset = b->ibuf_offset+b->data.size(); }