X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fbatch.cpp;h=1d9b1d4cd4ab7081a3bf95522056f61b91375217;hb=50175b88e2f189e80881d292dcc32523c5b272fc;hp=9ed20a1f524dc5d334c2825a8867f77cc8ea31f5;hpb=ceae2a27dfc58310c5bab7e3aa3fedf0fa9a1f49;p=libs%2Fgl.git diff --git a/source/batch.cpp b/source/batch.cpp index 9ed20a1f..1d9b1d4c 100644 --- a/source/batch.cpp +++ b/source/batch.cpp @@ -1,54 +1,336 @@ -/* $Id$ - -This file is part of libmspgl -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - #include "batch.h" -#include "extension.h" +#include "bindable.h" +#include "buffer.h" +#include "error.h" +#include "ext_draw_range_elements.h" +#include "nv_primitive_restart.h" #include "vertexarray.h" using namespace std; +namespace { + +template +void append(vector &data, T i) +{ + data.insert(data.end(), sizeof(T), 0); + *(T *)(&data[data.size()-sizeof(T)]) = i; +} + +template +U convert(T n) +{ + if(!static_cast(~n)) + return ~0; + else + return n; +} + +template +void expand(vector &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 shrink(vector &data) +{ + unsigned count = data.size()/sizeof(T); + for(unsigned i=0; i(*(T *)(&data[i*sizeof(T)])); + data.resize(count*sizeof(U)); +} + +} + 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) +{ + /* XXX Should probably provide a fallback to glDrawElements since this class + is pretty much required to render anything. */ + static Require _req(EXT_draw_range_elements); +} + +Batch::~Batch() +{ + unlink_from_ibuf(); +} + +void Batch::set_data_type(DataType t) +{ + if(t!=UNSIGNED_BYTE && t!=UNSIGNED_SHORT && t!=UNSIGNED_INT) + throw invalid_argument("Batch::set_data_type"); + if(t==UNSIGNED_BYTE && max_index>0xFE) + throw invalid_operation("Batch::set_data_type"); + else if(t==UNSIGNED_SHORT && max_index>0xFFFE) + throw invalid_operation("Batch::set_data_type"); + + 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 invalid_argument("Batch::use_index_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; +} + +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::update_ibuf_offsets() +{ + 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(); +} 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(data, i); + else if(data_type==UNSIGNED_INT) + ::append(data, 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(data, 0xFFFF); + else if(data_type==UNSIGNED_INT) + ::append(data, 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, reinterpret_cast(ibuf_offset)); + } + else + glDrawRangeElements(prim_type, min_index, max_index, size(), data_type, &data[0]); }