X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fbatch.cpp;h=a59fad99f03b988309ef60042324df71ebf3c6ab;hp=375c52e9ca25da98131f76924eb457b80bf9f255;hb=f50822b9e73a6ecdacbc4af4c4d9aba435a72386;hpb=69bd7cdfb824c9189ef89e112222141c28b163f6 diff --git a/source/batch.cpp b/source/batch.cpp index 375c52e9..a59fad99 100644 --- a/source/batch.cpp +++ b/source/batch.cpp @@ -1,14 +1,54 @@ +#include +#include +#include +#include #include "batch.h" #include "bindable.h" #include "buffer.h" #include "error.h" -#include "extension.h" -#include "nv_primitive_restart.h" +#include "mesh.h" #include "vertexarray.h" -#include "version_1_2.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 { @@ -19,21 +59,11 @@ Batch::Batch(PrimitiveType t): data_type(UNSIGNED_BYTE), min_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 RequireVersion _ver(1, 2); -} + restart(false) +{ } Batch::~Batch() { - unlink_from_ibuf(); } void Batch::set_data_type(DataType t) @@ -46,137 +76,84 @@ void Batch::set_data_type(DataType t) throw invalid_operation("Batch::set_data_type"); if(data_type==UNSIGNED_BYTE && t==UNSIGNED_SHORT) - expand_data(); + expand(data); else if(data_type==UNSIGNED_BYTE && t==UNSIGNED_INT) - expand_data(); + expand(data); else if(data_type==UNSIGNED_SHORT && t==UNSIGNED_INT) - expand_data(); + expand(data); else if(data_type==UNSIGNED_INT && t==UNSIGNED_BYTE) - shrink_data(); + shrink(data); else if(data_type==UNSIGNED_INT && t==UNSIGNED_SHORT) - shrink_data(); + shrink(data); else if(data_type==UNSIGNED_SHORT && t==UNSIGNED_BYTE) - shrink_data(); + 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; - + update_offset(); dirty = true; } Batch &Batch::append(unsigned i) { - if(data.empty()) - min_index = max_index = i; - else - { - min_index = min(min_index, i); - max_index = max(max_index, i); - } + append_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); - - 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(); + update_offset(); dirty = true; return *this; } -void Batch::append(const vector &ind) +Batch &Batch::append(const vector &ind) { if(ind.empty()) - return; - - if(data.empty()) - min_index = max_index = ind.front(); + return *this; + data.reserve(data.size()+ind.size()*get_index_size()); for(vector::const_iterator i=ind.begin(); i!=ind.end(); ++i) - { - min_index = min(min_index, *i); - max_index = max(max_index, *i); - } + append_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); + update_offset(); + dirty = true; - 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); + ::append(data, 0xFFFF); else if(data_type==UNSIGNED_INT) - append_index(0xFFFFFFFF); + ::append(data, 0xFFFFFFFF); else data.push_back(0xFF); } @@ -197,62 +174,35 @@ void Batch::append(const Batch &other) 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); + 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); - glDrawRangeElements(prim_type, min_index, max_index, size(), data_type, reinterpret_cast(ibuf_offset)); - } + if(data_type==UNSIGNED_SHORT) + ::append(data, i); + else if(data_type==UNSIGNED_INT) + ::append(data, i); else - glDrawRangeElements(prim_type, min_index, max_index, size(), data_type, &data[0]); + data.push_back(i); } unsigned Batch::get_index_size() const @@ -264,13 +214,6 @@ unsigned Batch::get_index_size() const 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) @@ -281,53 +224,72 @@ unsigned Batch::get_index(unsigned i) const return data[i]; } -template -void Batch::expand_data() +void Batch::draw() const { - 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)])); -} + BindRestore _bind_ibuf(get_buffer(), ELEMENT_ARRAY_BUFFER); + const void *data_ptr = setup_draw(); -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)); + if(EXT_draw_range_elements) + glDrawRangeElements(prim_type, min_index, max_index, size(), data_type, data_ptr); + else + glDrawElements(prim_type, size(), data_type, data_ptr); } -template -U Batch::convert(T i) const +const void *Batch::setup_draw() const { - if(!static_cast(~i)) - return ~0; + if(restart) + { + unsigned index; + if(data_type==UNSIGNED_SHORT) + index = 0xFFFF; + else if(data_type==UNSIGNED_INT) + index = 0xFFFFFFFF; + else + index = 0xFF; + + if(index!=restart_index) + set_restart_index(index); + } + else if(restart_index && restart_index<=max_index) + set_restart_index(0); + + if(get_buffer()) + { + if(dirty) + update_buffer(); + + return reinterpret_cast(get_offset()); + } else - return i; + return &data[0]; } -void Batch::unlink_from_ibuf() +void Batch::set_restart_index(unsigned index) { - if(next_in_ibuf) - next_in_ibuf->prev_in_ibuf = prev_in_ibuf; - if(prev_in_ibuf) + if(MSP_primitive_restart) { - prev_in_ibuf->next_in_ibuf = next_in_ibuf; - prev_in_ibuf->update_ibuf_offsets(); + if(index>0) + { + if(!restart_index) + glEnable(GL_PRIMITIVE_RESTART); + glPrimitiveRestartIndex(index); + } + else + glDisable(GL_PRIMITIVE_RESTART); } - else if(next_in_ibuf) + else { - next_in_ibuf->ibuf_offset = 0; - next_in_ibuf->update_ibuf_offsets(); + if(index>0) + { + if(!restart_index) + glEnableClientState(GL_PRIMITIVE_RESTART_NV); + glPrimitiveRestartIndexNV(index); + } + else + glDisableClientState(GL_PRIMITIVE_RESTART_NV); } -} -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(); + restart_index = index; }