diff --git a/wrap/gl/gl_mesh_attributes_feeder.h b/wrap/gl/gl_mesh_attributes_feeder.h index 94c4e466..129a0850 100644 --- a/wrap/gl/gl_mesh_attributes_feeder.h +++ b/wrap/gl/gl_mesh_attributes_feeder.h @@ -1,1220 +1,1337 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* Visual Computing Lab /\/| * -* ISTI - Italian National Research Council | * -* \ * -* All rights reserved. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * -* for more details. * -* * -****************************************************************************/ - -#ifndef __VCG_GL_MESH_ATTRIBUTES_FEEDER -#define __VCG_GL_MESH_ATTRIBUTES_FEEDER - -#include -#include -#include -#include -#include -#include -#include - -//#include -#include -#include -#include - - -namespace vcg -{ - //WARNING: All the classes derived from MemoryInfo has been intended to be instantiated as a singleton in the host application - //(i.e. in every application using it just an instance of a class derived from MemoryInfo should be declared). - - class MemoryInfo - { - public: - class MemoryInfoException : public std::exception - { - public: - MemoryInfoException(const char* text) - :std::exception(),_exctext(text){} - - ~MemoryInfoException() throw() {} - inline const char* what() const throw() {return _exctext;} - private: - const char* _exctext; - }; - - MemoryInfo(long long unsigned int originalmem) - :_originaltotalmemory(originalmem),_currentfreememory(_originaltotalmemory) - { - } - - virtual ~MemoryInfo() {} - virtual void acquiredMemory(long long unsigned int mem) = 0; - virtual long long unsigned int usedMemory() const = 0; - virtual long long unsigned int currentFreeMemory() const = 0; - virtual void releasedMemory(long long unsigned int mem = 0) = 0; - virtual bool isAdditionalMemoryAvailable(long long unsigned int mem) = 0; - - protected: - const long long unsigned int _originaltotalmemory; - long long unsigned int _currentfreememory; - }; - - //WARNING: this is not a thread safe class. The object derived from MemoryInfo are intended to be used inside GLMeshAttributeFeeder as static variable in order to manage the available GPUMemory. - //We strongly recommend you to define in your code a thread safe version of the class, defining mutexed access member functions. - //This class should be consider just as a basic example for the implementations of the required functionalities. - //It is safe to use it just when the user has only one mesh to pass to the GPU. - - class NotThreadSafeMemoryInfo : public MemoryInfo - { - public: - NotThreadSafeMemoryInfo(long long unsigned int originalmem) - :MemoryInfo(originalmem) - { - } - - ~NotThreadSafeMemoryInfo() {} - - void acquiredMemory(long long unsigned int mem) - { - if (mem > _originaltotalmemory) - throw MemoryInfo::MemoryInfoException("It has been requested more memory than the total one.\\n"); - else - if (mem > _currentfreememory) - throw MemoryInfo::MemoryInfoException("It has been requested more memory than the free available one.\\n"); - else - _currentfreememory -= mem; - } - - long long unsigned int usedMemory() const - { - return _originaltotalmemory - _currentfreememory; - } - - long long unsigned int currentFreeMemory() const - { - return _currentfreememory; - } - - void releasedMemory(long long unsigned int mem = 0) - { - if (mem > _originaltotalmemory) - throw MemoryInfo::MemoryInfoException("It has been released more memory than the total one. Something strange happened!\\n"); - else - _currentfreememory += mem; - } - - bool isAdditionalMemoryAvailable(long long unsigned int mem) - { - return (_currentfreememory >= mem); - } - }; - - struct GLFeedEnum - { - enum MESH_ATTRIBUTE_UPDATED - { - ATT_VERTPOSITION = 0x00000000, - ATT_VERTNORMAL = 0x00000001, - ATT_VERTCOLOR = 0x00000002, - ATT_VERTTEXTURE = 0x00000004, - ATT_FACENORMAL = 0x00000008, - ATT_FACECOLOR = 0x00000010, - ATT_WEDGETEXTURE = 0x00000020, - ATT_ALL = 0xffffffff - }; - - enum COLOR_MODALITY - { - CL_NONE = 0, - CL_PERVERT, - CL_PERFACE, - CL_PERMESH - }; - - enum NORMAL_MODALITY - { - NR_NONE = 0, - NR_PERVERT, - NR_PERFACE - }; - - enum TEXTURE_MODALITY - { - TX_NONE = 0, - TX_PERVERT, - TX_PERWEDGE - }; - }; - - //WARNING! member functions of this class should be called by the host application using concurrency - template - class GLMeshAttributesFeeder : public GLFeedEnum - { - public: - GLMeshAttributesFeeder(/*const*/ MESHTYPE& mesh,MemoryInfo& meminfo, size_t perbatchtriangles) - :_mesh(mesh),_gpumeminfo(meminfo),_bo(8,NULL)/*,vaohandle(0)*/,_lastfeedingusedreplicatedpipeline(false),_perbatchsimplex(perbatchtriangles),_chunkmap(),_borendering(false) - { - _bo[VERTPOSITIONBO] = new GLBufferObject(3,GL_FLOAT,GL_ARRAY_BUFFER); - _bo[VERTNORMALBO] = new GLBufferObject(3,GL_FLOAT,GL_ARRAY_BUFFER); - _bo[FACENORMALBO] = new GLBufferObject(3,GL_FLOAT,GL_ARRAY_BUFFER); - _bo[VERTCOLORBO] = new GLBufferObject(4,GL_UNSIGNED_BYTE,GL_ARRAY_BUFFER); - _bo[FACECOLORBO] = new GLBufferObject(4,GL_UNSIGNED_BYTE,GL_ARRAY_BUFFER); - _bo[VERTTEXTUREBO] = new GLBufferObject(2,GL_FLOAT,GL_ARRAY_BUFFER); - _bo[WEDGETEXTUREBO] = new GLBufferObject(2,GL_FLOAT,GL_ARRAY_BUFFER); - _bo[VERTINDEXBO] = new GLBufferObject(3,GL_UNSIGNED_INT,GL_ELEMENT_ARRAY_BUFFER); - } - - ~GLMeshAttributesFeeder() - { - size_t ii = 0; - for(typename std::vector::iterator it = _bo.begin();it != _bo.end();++it) - { - if (*it != NULL) - { - glDeleteBuffers(1,&((*it)->_bohandle)); - (*it)->_bohandle = 0; - } - delete _bo[BO_NAMES(ii)]; - ++ii; - } - _bo.clear(); - //glDeleteVertexArrays(1,&vaohandle); - } - - void setPerBatchTriangles(size_t perbatchtriangles) - { - _perbatchsimplex = perbatchtriangles; - } - - size_t perBatchTriangles() const - { - return _perbatchsimplex; - } - - bool renderedWithBO() const - { - return _borendering; - } - - void update(int mask) - { - if ((mask & ATT_VERTPOSITION) || (mask & ATT_ALL)) - _bo[VERTPOSITIONBO]->_isvalid = false; - - if ((mask & ATT_VERTNORMAL) || (mask & ATT_ALL)) - _bo[VERTNORMALBO]->_isvalid = false; - - if ((mask & ATT_FACENORMAL) || (mask & ATT_ALL)) - _bo[FACENORMALBO]->_isvalid = false; - - if ((mask & ATT_VERTCOLOR) || (mask & ATT_ALL)) - _bo[VERTCOLORBO]->_isvalid = false; - - if ((mask & ATT_FACECOLOR) || (mask & ATT_ALL)) - _bo[FACECOLORBO]->_isvalid = false; - - if ((mask & ATT_VERTTEXTURE) || (mask & ATT_ALL)) - _bo[VERTTEXTUREBO]->_isvalid = false; - - if ((mask & ATT_WEDGETEXTURE) || (mask & ATT_ALL)) - _bo[WEDGETEXTUREBO]->_isvalid = false; - - if (mask & ATT_ALL) - _bo[VERTINDEXBO]->_isvalid = false; - } - - /*WARNING: the passTrianglesToOpenGL & the passPointsToOpenGL functions should be invoked with a reading mutex, - in order to be sure that the referenced mesh would not been changed when the mesh attributes are updated into the buffer objects. - textureindex contained the texture OpenGL ids loaded in the gpu memory by the main application*/ - void passTrianglesToOpenGL(GLuint& vaohandlespecificperopenglcontext,NORMAL_MODALITY nm,COLOR_MODALITY cm,TEXTURE_MODALITY tm,const std::vector& textureindex = std::vector()) - { - if (tryToAllocatePerTriangleAttributesInBO(vaohandlespecificperopenglcontext,nm,cm,tm)) - drawTriangles(vaohandlespecificperopenglcontext,nm,cm,tm,textureindex); - else - immediateMode(nm,cm,tm,textureindex); - } - - void passPointsToOpenGL(GLuint& vaohandlespecificperopenglcontext,NORMAL_MODALITY nm,COLOR_MODALITY cm) - { - if (tryToAllocatePerPointAttributesInBO(vaohandlespecificperopenglcontext,nm,cm)) - drawPoints(vaohandlespecificperopenglcontext); - else - immediateMode(nm,cm,TX_NONE); - } - - enum BO_NAMES - { - VERTPOSITIONBO = 0, - VERTNORMALBO = 1, - FACENORMALBO = 2, - VERTCOLORBO = 3, - FACECOLORBO = 4, - VERTTEXTUREBO = 5, - WEDGETEXTUREBO = 6, - VERTINDEXBO = 7 - }; - - protected: - struct GLBufferObject - { - GLBufferObject(size_t components,GLenum gltype,GLenum target) - :_size(0),_components(components),_isvalid(false),_gltype(gltype),_target(target),_bohandle(0) - { - } - - size_t getSizeOfGLType() const - { - switch(_gltype) - { - case(GL_FLOAT): - return sizeof(GLfloat); - case(GL_INT): - return sizeof(GLint); - case(GL_UNSIGNED_INT): - return sizeof(GLuint); - case(GL_UNSIGNED_BYTE): - return sizeof(GLubyte); - } - return 0; - } - - size_t _size; - const size_t _components; - bool _isvalid; - const GLenum _gltype; - const GLenum _target; - GLuint _bohandle; - }; - - const GLBufferObject& getBufferObjectInfo(BO_NAMES boname) const - { - return _bo[boname]; - } - - long long unsigned int bufferObjectsMemoryRequired(NORMAL_MODALITY nm,COLOR_MODALITY cm,TEXTURE_MODALITY tm,bool generateindex) const - { - bool replicated = (nm == NR_PERFACE) || (cm == CL_PERFACE) || (tm == TX_PERWEDGE); - long long unsigned int result(0); - - result += (long long unsigned int) boExpectedDimension(VERTPOSITIONBO,replicated,generateindex); - if (nm == NR_PERVERT) - result += (long long unsigned int) boExpectedDimension(VERTNORMALBO,replicated,generateindex); - if (nm == NR_PERFACE) - result += (long long unsigned int) boExpectedDimension(FACENORMALBO,replicated,generateindex); - if (cm == CL_PERVERT) - result += (long long unsigned int) boExpectedDimension(VERTCOLORBO,replicated,generateindex); - if (cm == CL_PERFACE) - result += (long long unsigned int) boExpectedDimension(FACECOLORBO,replicated,generateindex); - if (tm == TX_PERVERT) - result += (long long unsigned int) boExpectedDimension(VERTTEXTUREBO,replicated,generateindex); - if (tm == TX_PERWEDGE) - result += (long long unsigned int) boExpectedDimension(WEDGETEXTUREBO,replicated,generateindex); - result += (long long unsigned int) boExpectedDimension(VERTINDEXBO,replicated,generateindex); - return result; - } - - void attributesToBeImportedInTriangleBasedPipeline( std::vector &importattribute, NORMAL_MODALITY nm, COLOR_MODALITY cm, TEXTURE_MODALITY tm ) const - { - importattribute[VERTPOSITIONBO] = true; - importattribute[VERTNORMALBO] = vcg::tri::HasPerVertexNormal(_mesh) && (nm == NR_PERVERT); - importattribute[FACENORMALBO] = vcg::tri::HasPerFaceNormal(_mesh) && (nm == NR_PERFACE); - importattribute[VERTCOLORBO] = vcg::tri::HasPerVertexColor(_mesh) && (cm == CL_PERVERT); - importattribute[FACECOLORBO] = vcg::tri::HasPerFaceColor(_mesh) && (cm == CL_PERFACE); - importattribute[VERTTEXTUREBO] = vcg::tri::HasPerVertexTexCoord(_mesh) && (tm == TX_PERVERT); - importattribute[WEDGETEXTUREBO] = vcg::tri::HasPerWedgeTexCoord(_mesh) && (tm == TX_PERWEDGE); - - /*check if the requested attributes are available inside the mesh*/ - if (!importattribute[VERTNORMALBO] && !importattribute[FACENORMALBO]) - nm = NR_NONE; - - if (!importattribute[VERTCOLORBO] && !importattribute[FACECOLORBO]) - cm = CL_NONE; - - if (!importattribute[VERTTEXTUREBO] && !importattribute[WEDGETEXTUREBO]) - tm = TX_NONE; - - bool replicated = (nm == NR_PERFACE) || (cm == CL_PERFACE) || (tm == TX_PERWEDGE); - - importattribute[VERTINDEXBO] = !replicated; - } - - void attributesToBeImportedInPointBasedPipeline( std::vector &importattribute, NORMAL_MODALITY nm, COLOR_MODALITY cm) const - { - importattribute[VERTPOSITIONBO] = true; - importattribute[VERTNORMALBO] = vcg::tri::HasPerVertexNormal(_mesh) && (nm == NR_PERVERT); - importattribute[FACENORMALBO] = false; - importattribute[VERTCOLORBO] = vcg::tri::HasPerVertexColor(_mesh) && (cm == CL_PERVERT); - importattribute[FACECOLORBO] = false; - importattribute[VERTTEXTUREBO] = false; - importattribute[WEDGETEXTUREBO] = false; - importattribute[VERTINDEXBO] = false; - } - - bool buffersAllocationFunction(GLuint& vaohandlespecificperopenglcontext,NORMAL_MODALITY nm,COLOR_MODALITY cm,TEXTURE_MODALITY tm,const std::vector& importattribute,std::vector& attributestobeupdated) - { - if (vaohandlespecificperopenglcontext == 0) - //glGenVertexArrays(1,&vaohandle); - return false; - bool replicated = (importattribute[FACENORMALBO] || importattribute[FACECOLORBO] || importattribute[WEDGETEXTUREBO]); - attributestobeupdated.clear(); - attributestobeupdated.resize(importattribute.size()); - long long unsigned int bomemoryrequiredbymesh = this->bufferObjectsMemoryRequired(nm,cm,tm,importattribute[VERTINDEXBO]); - unsigned int ii = 0; - for(typename std::vector::iterator it = _bo.begin();it != _bo.end();++it) - { - BO_NAMES boname = static_cast(ii); - size_t sz = boExpectedSize(boname,replicated,importattribute[VERTINDEXBO]); - size_t dim = boExpectedDimension(boname,replicated,importattribute[VERTINDEXBO]); - if ((*it != NULL) && ((!(*it)->_isvalid) || - /*if _lastfeedingusedreplicatedpipeline == false means that maybe there are valid per vertex attribute buffer objects that MUST be reallocated anyway cause we have to switch to the replicated attributes pipeline*/ - (replicated && !_lastfeedingusedreplicatedpipeline && (isPerVertexAttribute(boname) || (boname == VERTINDEXBO))) || - /*we switched back from the replicated pipeline to the normal one. All the bos have to be regenerated*/ - (!replicated && _lastfeedingusedreplicatedpipeline) || - /*the buffer object is valid but for same reason the number of cells of the bo don't suit anymore the required size. we have to reallocate the buffer object*/ - (((*it)->_isvalid) && (sz != (*it)->_size))) || - //the buffer is valid, but the attribute is not required to be displayed - (((*it)->_isvalid) && !importattribute[ii])) - { - - //disableClientState(boname,importattribute); - - /*WARNING! THIS CODE MUST BE INCAPSULATED INTO A DEALLOCATE FUNCTION IN A PROPER MADE BUFFER OBJECT CLASS - I DON'T INSERT IT INTO THE GLBufferObjectInfo CLASS CAUSE I CONSIDER IT A TEMPORARY PRIVATE STRUCT*/ - glDeleteBuffers(1,&((*it)->_bohandle)); - (*it)->_bohandle = 0; - if ((*it)->_size > 0) - //we don't use dim cause dim is the value that is going to be allocated, instead use (*it)->_size * (*it)->getSizeOfGLType() is the value already in the buffer - _gpumeminfo.releasedMemory((*it)->_size * (*it)->getSizeOfGLType()); - (*it)->_isvalid = false; - (*it)->_size = 0; - /**********************************************************************************************************/ - } - //there are already valid mesh attributes properly allocated in memory, we don't need to allocate them again - if ((*it != NULL) && (((*it)->_isvalid) && (sz == (*it)->_size))) - bomemoryrequiredbymesh -= dim; - ++ii; - } - - if (!_gpumeminfo.isAdditionalMemoryAvailable(bomemoryrequiredbymesh)) - { - std::cout << "no additional memory available!!! memory required: " << bomemoryrequiredbymesh << std::endl; - ii = 0; - for(typename std::vector::iterator it = _bo.begin();it != _bo.end();++it) - { - BO_NAMES boname = static_cast(ii); - size_t sz(boExpectedSize(boname,replicated,importattribute[VERTINDEXBO])); - //there are already valid mesh attributes properly allocated in memory but there is not enough gpu memory for the remaining mesh. - //we have to deallocate the previously allocated mesh attributes - if ((*it != NULL) && (((*it)->_isvalid) && (sz == (*it)->_size))) - { - long long unsigned int dim(boExpectedDimension(boname,replicated,importattribute[VERTINDEXBO])); - //disableClientState(boname,importattribute); - if ((*it)->_size > 0) - { - - - /*WARNING! THIS CODE MUST BE INCAPSULATED INTO A DEALLOCATE FUNCTION IN A PROPER MADE BUFFER OBJECT CLASS - I DON'T INSERT IT INTO THE GLBufferObjectInfo CLASS CAUSE I CONSIDER IT A TEMPORARY PRIVATE STRUCT*/ - glDeleteBuffers(1,&(*it)->_bohandle); - (*it)->_bohandle = 0; - _gpumeminfo.releasedMemory(dim); - } - (*it)->_isvalid = false; - (*it)->_size = 0; - /*********************************************************************************************************/ - } - ++ii; - } - _borendering = false; - _lastfeedingusedreplicatedpipeline = false; - return false; - } - else - { - unsigned int ii = 0; - //I have to update the invalid buffers requested to be imported - attributestobeupdated = importattribute; - for(typename std::vector::iterator it = _bo.begin();it != _bo.end();++it) - { - BO_NAMES boname = static_cast(ii); - GLBufferObject* cbo = _bo.at(boname); - bool importatt = importattribute.at(boname); - glBindVertexArray(vaohandlespecificperopenglcontext); - bool notvalidbuttoberegenerated = (cbo != NULL) && (!cbo->_isvalid) && (importatt); - if (notvalidbuttoberegenerated) - { - cbo->_size = boExpectedSize(boname,replicated,importattribute[VERTINDEXBO]); - long long unsigned int dim = boExpectedDimension(boname,replicated,importattribute[VERTINDEXBO]); - glGenBuffers(1, &cbo->_bohandle); - glBindBuffer(cbo->_target, cbo->_bohandle); - glBufferData(cbo->_target, dim, NULL, GL_STATIC_DRAW); - setBufferPointerEnableClientState(boname); - glBindBuffer(cbo->_target, 0); - _gpumeminfo.acquiredMemory(dim); - attributestobeupdated[boname] = true; - cbo->_isvalid = true; - } - else - { - attributestobeupdated[boname] = false; - if (!importatt) - cbo->_isvalid = false; - } - - if ((cbo == NULL) || (!cbo->_isvalid)) - { - //glBindVertexArray(_vaohandle); - disableClientState(boname,importattribute); - //glBindVertexArray(0); - } - ++ii; - glBindVertexArray(0); - } - _borendering = true; - _lastfeedingusedreplicatedpipeline = replicated; - return true; - } - } - - bool tryToAllocatePerTriangleAttributesInBO(GLuint& vaohandlespecificperopenglcontext,NORMAL_MODALITY nm,COLOR_MODALITY cm,TEXTURE_MODALITY tm) - { - std::vector importattribute(_bo.size()); - std::vector attributestobeupdated; - attributesToBeImportedInTriangleBasedPipeline(importattribute, nm, cm, tm); - bool replicated = !importattribute[VERTINDEXBO]; - bool immediatemode = !(buffersAllocationFunction(vaohandlespecificperopenglcontext,nm,cm,tm,importattribute,attributestobeupdated)); - - if (immediatemode) - return false; - - bool somethingtoupdate = false; - for(size_t hh = 0;hh < attributestobeupdated.size();++hh) - somethingtoupdate = somethingtoupdate || attributestobeupdated[hh]; - if (somethingtoupdate) - { - if (replicated) - { - //WARNING!In case we have to update the wedgetexture bo maybe (not always!) we must update also the other buffer already in memory - //cause the wedgetexture pipeline force a change in the order of the triangles in GPU. - //they are now ordered by the texture seam and not more by the triangle index! - if (attributestobeupdated[WEDGETEXTUREBO]) - { - for(size_t jj = 0;jj < attributestobeupdated.size();++jj) - attributestobeupdated[jj] = importattribute[jj] || attributestobeupdated[jj]; - } - updateBuffersReplicatedPipeline(attributestobeupdated,tm); - } - else - updateBuffersIndexedPipeline(attributestobeupdated); - } - return true; - } - - bool tryToAllocatePerPointAttributesInBO(GLuint& vaohandlespecificperopenglcontext,NORMAL_MODALITY nm,COLOR_MODALITY cm) - { - std::vector importattribute(_bo.size()); - std::vector attributestobeupdated; - attributesToBeImportedInPointBasedPipeline(importattribute, nm, cm); - bool immediatemode = !(buffersAllocationFunction(vaohandlespecificperopenglcontext,nm,cm,TX_NONE,importattribute,attributestobeupdated)); - if (immediatemode) - return false; - - bool somethingtoupdate = false; - for(size_t hh = 0;hh < attributestobeupdated.size();++hh) - somethingtoupdate = somethingtoupdate || attributestobeupdated[hh]; - if (somethingtoupdate) - updateBuffersIndexedPipeline(attributestobeupdated); - return true; - } - - bool updateBuffersIndexedPipeline(const std::vector& attributestobeupdated) - { - _chunkmap.clear(); - size_t vn = _mesh.vn; - size_t tn = _mesh.fn; - - size_t facechunk = std::min(size_t(tn),_perbatchsimplex); - size_t vertexchunk = std::min(size_t(vn),_perbatchsimplex); - - std::vector pv(vertexchunk); - std::vector nv(vertexchunk); - std::vector cv(vertexchunk); // Per vertex Colors - std::vector tv(vertexchunk * 2); - - size_t chunckingpu = 0; - - for(size_t i=0;i_bohandle); - glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * vertexchunk * buffobj->_components * buffobj->getSizeOfGLType(),buffobj->_components * buffobj->getSizeOfGLType() * chuncksize,&pv[0]); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - if (attributestobeupdated[VERTNORMALBO]) - { - GLBufferObject* buffobj = _bo[VERTNORMALBO]; - glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); - glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * vertexchunk * buffobj->_components * buffobj->getSizeOfGLType(),buffobj->_components * buffobj->getSizeOfGLType() * chuncksize,&nv[0]); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - if (attributestobeupdated[VERTCOLORBO]) - { - GLBufferObject* buffobj = _bo[VERTCOLORBO]; - glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); - glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * vertexchunk * buffobj->_components * buffobj->getSizeOfGLType(),buffobj->_components * buffobj->getSizeOfGLType() * chuncksize,&cv[0]); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - if (attributestobeupdated[VERTTEXTUREBO]) - { - GLBufferObject* buffobj = _bo[VERTTEXTUREBO]; - glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); - glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * vertexchunk * buffobj->_components * buffobj->getSizeOfGLType(),buffobj->_components * buffobj->getSizeOfGLType() * chuncksize,&tv[0]); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - ++chunckingpu; - } - } - - pv.clear(); - nv.clear(); - cv.clear(); - tv.clear(); - - chunckingpu = 0; - std::vector ti(facechunk * 3); - for(size_t i=0;i_bohandle); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,chunckingpu * facechunk * _bo[VERTINDEXBO]->_components * _bo[VERTINDEXBO]->getSizeOfGLType(),_bo[VERTINDEXBO]->_components * _bo[VERTINDEXBO]->getSizeOfGLType() * chunksize,&ti[0]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - ++chunckingpu; - } - } - return true; - } - - bool updateBuffersReplicatedPipeline(const std::vector& attributestobeupdated,GLFeedEnum::TEXTURE_MODALITY currtextmod) - { - size_t tn = _mesh.fn; - - size_t facechunk = std::min(size_t(tn),_perbatchsimplex); - - std::vector rpv(facechunk * 3); - std::vector rnv(facechunk * 3); - std::vector rcv(facechunk * 3); - std::vector rtv(facechunk * 3 * 2); - - size_t chunckingpu = 0; - - //it's a map containing for each texture seams n a vector of all the triangle index ranges having n has texture seam - //Suppose that in a mesh we have - //TXS_0{t0,t1,t2,t3}, TXS_4{t4,t5},TXS_0{t6},TXS_-1{t7,t8,t9},TXS_4{t10,t11} - //so chunkMap will contain - // -1 -> [] - // 0 -> [,] - // 4 -> [,] - // - //if the map has no-texture coords at all in order to unify the code we fill the ChunkMap with texture seam -1 and a single triangle range going from face_0 to face_n-1 - - - if (attributestobeupdated[WEDGETEXTUREBO] || attributestobeupdated[VERTTEXTUREBO]) - { - _chunkmap.clear(); - if (attributestobeupdated[WEDGETEXTUREBO]) - fillChunckMap(_chunkmap); - else - if(attributestobeupdated[VERTTEXTUREBO]) - _chunkmap[0].push_back(std::make_pair(0,tn-1)); - } - - //default case: no texture is required to be rendered but a non texture attribute has to be updated - //we have to init the _chunkmap with just one entry (-1...that means no texture) referring all the triangles in the mesh - if ((currtextmod == GLFeedEnum::TX_NONE) && - (attributestobeupdated[VERTPOSITIONBO] || - attributestobeupdated[VERTNORMALBO] || attributestobeupdated[FACENORMALBO] || - attributestobeupdated[VERTCOLORBO] || attributestobeupdated[FACECOLORBO])) - { - _chunkmap.clear(); - _chunkmap[-1].push_back(std::make_pair(0,tn-1)); - } - - int t = 0; - if (attributestobeupdated[WEDGETEXTUREBO] || attributestobeupdated[VERTTEXTUREBO]) - { - _texindnumtriangles.clear(); - _texindnumtriangles.resize(_chunkmap.size()); - } - int i = 0; - size_t chunkindex = i; - GLuint triangles = 0; - for(ChunkMap::const_iterator mit = _chunkmap.begin();mit != _chunkmap.end();++mit) - { - for (ChunkVector::const_iterator cit = mit->second.begin();cit != mit->second.end();++cit) - { - for(size_t indf = cit->first;indf<=cit->second;++indf) - { - chunkindex = i % facechunk; - if (attributestobeupdated[VERTPOSITIONBO]) - { - rpv[chunkindex*3+0].Import(_mesh.face[indf].V(0)->P()); - rpv[chunkindex*3+1].Import(_mesh.face[indf].V(1)->P()); - rpv[chunkindex*3+2].Import(_mesh.face[indf].V(2)->P()); - } - if (attributestobeupdated[VERTNORMALBO]) - { - rnv[chunkindex*3+0].Import(_mesh.face[indf].V(0)->N().Normalize()); - rnv[chunkindex*3+1].Import(_mesh.face[indf].V(1)->N().Normalize()); - rnv[chunkindex*3+2].Import(_mesh.face[indf].V(2)->N().Normalize()); - } - else if (attributestobeupdated[FACENORMALBO]) - { - rnv[chunkindex*3+0].Import(_mesh.face[indf].N().Normalize()); - rnv[chunkindex*3+1].Import(_mesh.face[indf].N().Normalize()); - rnv[chunkindex*3+2].Import(_mesh.face[indf].N().Normalize()); - } - - if ((attributestobeupdated[VERTCOLORBO])) - { - rcv[chunkindex*3+0] = _mesh.face[indf].V(0)->C(); - rcv[chunkindex*3+1] = _mesh.face[indf].V(1)->C(); - rcv[chunkindex*3+2] = _mesh.face[indf].V(2)->C(); - } - else if ((attributestobeupdated[FACECOLORBO])) - { - rcv[chunkindex*3+0] = _mesh.face[indf].C(); - rcv[chunkindex*3+1] = _mesh.face[indf].C(); - rcv[chunkindex*3+2] = _mesh.face[indf].C(); - } - - if (attributestobeupdated[WEDGETEXTUREBO]) - { - rtv[chunkindex*6+0]=float(_mesh.face[indf].WT(0).U()); - rtv[chunkindex*6+1]=float(_mesh.face[indf].WT(0).V()); - rtv[chunkindex*6+2]=float(_mesh.face[indf].WT(1).U()); - rtv[chunkindex*6+3]=float(_mesh.face[indf].WT(1).V()); - rtv[chunkindex*6+4]=float(_mesh.face[indf].WT(2).U()); - rtv[chunkindex*6+5]=float(_mesh.face[indf].WT(2).V()); - } - else if (attributestobeupdated[VERTTEXTUREBO]) - { - rtv[chunkindex*6+0]=float(_mesh.face[indf].V(0)->T().U()); - rtv[chunkindex*6+1]=float(_mesh.face[indf].V(0)->T().V()); - rtv[chunkindex*6+2]=float(_mesh.face[indf].V(1)->T().U()); - rtv[chunkindex*6+3]=float(_mesh.face[indf].V(1)->T().V()); - rtv[chunkindex*6+4]=float(_mesh.face[indf].V(2)->T().U()); - rtv[chunkindex*6+5]=float(_mesh.face[indf].V(2)->T().V()); - } - - if((i == tn - 1) || (chunkindex == facechunk - 1)) - { - size_t chunksize = facechunk; - if (i == tn - 1) - chunksize = chunkindex + 1; - - if (attributestobeupdated[VERTPOSITIONBO]) - { - GLBufferObject* buffobj = _bo[VERTPOSITIONBO]; - glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); - glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * facechunk * 3 * buffobj->_components * buffobj->getSizeOfGLType(),3 * buffobj->_components * buffobj->getSizeOfGLType() * chunksize,&rpv[0]); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - if (attributestobeupdated[VERTNORMALBO] || attributestobeupdated[FACENORMALBO]) - { - GLBufferObject* buffobj; - if (attributestobeupdated[VERTNORMALBO]) - buffobj = _bo[VERTNORMALBO]; - else - buffobj = _bo[FACENORMALBO]; - glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); - glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * facechunk * 3 * buffobj->_components * buffobj->getSizeOfGLType(),3 * buffobj->_components * buffobj->getSizeOfGLType() * chunksize,&rnv[0]); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - if (attributestobeupdated[VERTCOLORBO] || attributestobeupdated[FACECOLORBO]) - { - GLBufferObject* buffobj; - if (attributestobeupdated[VERTCOLORBO]) - buffobj = _bo[VERTCOLORBO]; - else - buffobj = _bo[FACECOLORBO]; - glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); - glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * facechunk * 3 *buffobj->_components * buffobj->getSizeOfGLType(),3 * buffobj->_components * buffobj->getSizeOfGLType() * chunksize,&rcv[0]); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - if (attributestobeupdated[VERTTEXTUREBO] || attributestobeupdated[WEDGETEXTUREBO]) - { - GLBufferObject* buffobj; - if (attributestobeupdated[VERTTEXTUREBO]) - buffobj = _bo[VERTTEXTUREBO]; - else - buffobj = _bo[WEDGETEXTUREBO]; - glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); - glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * facechunk * 3 *buffobj->_components * buffobj->getSizeOfGLType(),3 * buffobj->_components * buffobj->getSizeOfGLType() * chunksize,&rtv[0]); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - ++chunckingpu; - } - ++i; - } - triangles += cit->second - cit->first + 1; - } - - if (attributestobeupdated[WEDGETEXTUREBO] || attributestobeupdated[VERTTEXTUREBO]) - _texindnumtriangles[t] = std::make_pair(mit->first,triangles); - ++t; - } - - //return (k != tn) - // throw MeshLabException("Mesh has not been properly partitioned"); - return true; - } - - bool immediateMode(NORMAL_MODALITY nm,COLOR_MODALITY cm,TEXTURE_MODALITY tm,const std::vector& textureindex = std::vector()) - { - glPushAttrib(GL_ALL_ATTRIB_BITS); - if(_mesh.fn==0) - return false; - - if(cm == CL_PERMESH) - glColor(_mesh.C()); - - //typename MESHTYPE::FaceContainer::iterator fp; - typename MESHTYPE::FaceIterator fi = _mesh.face.begin(); - - short curtexname=-1; - if(tm == TX_PERWEDGE) - { - curtexname=(*fi).WT(0).n(); - if ((curtexname >= 0) && (curtexname < (int)textureindex.size())) - { - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,textureindex[curtexname]); - } - else - { - glDisable(GL_TEXTURE_2D); - } - } - - if(tm==TX_PERVERT && !textureindex.empty()) // in the case of per vertex tex coord we assume that we have a SINGLE texture. - { - curtexname = 0; - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,textureindex[curtexname]); - } - - glBegin(GL_TRIANGLES); - - while(fi!=_mesh.face.end()) - { - typename MESHTYPE::FaceType & f = *fi; - if(!f.IsD()) - { - if(tm==TX_PERWEDGE) - if(f.WT(0).n() != curtexname) - { - curtexname=(*fi).WT(0).n(); - glEnd(); - - if (curtexname >= 0) - { - glEnable(GL_TEXTURE_2D); - if(!textureindex.empty()) - glBindTexture(GL_TEXTURE_2D,textureindex[curtexname]); - } - else - { - glDisable(GL_TEXTURE_2D); - } - - glBegin(GL_TRIANGLES); - } - - if(nm == NR_PERFACE) glNormal(f.cN()); - if(nm == NR_PERVERT) glNormal(f.V(0)->cN()); - //if(nm == NMPerWedge)glNormal(f.WN(0)); - - if(cm == CL_PERFACE) glColor(f.C()); - if(cm == CL_PERVERT) glColor(f.V(0)->C()); - if(tm == TX_PERVERT) glTexCoord(f.V(0)->T().P()); - if(tm == TX_PERWEDGE) glTexCoord(f.WT(0).t(0)); - glVertex(f.V(0)->P()); - - if(nm == NR_PERVERT) glNormal(f.V(1)->cN()); - //if(nm == NMPerWedge)glNormal(f.WN(1)); - if(cm == CL_PERVERT) glColor(f.V(1)->C()); - if(tm==TX_PERVERT) glTexCoord(f.V(1)->T().P()); - if(tm==TX_PERWEDGE) glTexCoord(f.WT(1).t(0)); - glVertex(f.V(1)->P()); - - if(nm == NR_PERVERT) glNormal(f.V(2)->cN()); - //if(nm == NMPerWedge)glNormal(f.WN(2)); - if(cm == CL_PERVERT) glColor(f.V(2)->C()); - if(tm==TX_PERVERT) glTexCoord(f.V(2)->T().P()); - if(tm==TX_PERWEDGE) glTexCoord(f.WT(2).t(0)); - glVertex(f.V(2)->P()); - } - ++fi; - } - - glEnd(); - glPopMatrix(); - glPopAttrib(); - return true; - } - - bool drawTriangles(GLuint& vaohandlespecificperopenglcontext,NORMAL_MODALITY nm,COLOR_MODALITY cm,TEXTURE_MODALITY tm,const std::vector& textureindex) - { - std::vector att(_bo.size(),false); - attributesToBeImportedInTriangleBasedPipeline(att,nm,cm,tm); - bool replicated = !att[VERTINDEXBO]; - GLenum err = glGetError(); - assert(err == GL_NO_ERROR); - glBindVertexArray(vaohandlespecificperopenglcontext); - err = glGetError(); - assert(err == GL_NO_ERROR); - - if (replicated) - { - int firsttriangleoffset = 0; - if(tm == GLFeedEnum::TX_NONE) - { - glDisable(GL_TEXTURE_2D); - glDrawArrays(GL_TRIANGLES,0,_mesh.fn * 3); - } - else - { - glEnable(GL_TEXTURE_2D); - for(std::vector< std::pair >::const_iterator it = _texindnumtriangles.begin();it != _texindnumtriangles.end();++it) - { - if ((it->first != -1) && (it->first < textureindex.size())) - glBindTexture(GL_TEXTURE_2D,textureindex[it->first]); - else - glBindTexture(GL_TEXTURE_2D,0); - glDrawArrays(GL_TRIANGLES,firsttriangleoffset,it->second * 3 - firsttriangleoffset); - firsttriangleoffset = it->second * 3; - } - glBindTexture(GL_TEXTURE_2D,0); - glDisable(GL_TEXTURE_2D); - } - - } - else - { - if(tm==TX_PERVERT) - { - if (textureindex.size() > 0) - { - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,textureindex[0]); - - } - } - else - glDisable(GL_TEXTURE_2D); - - - if (_bo[VERTINDEXBO]->_isvalid) - { - err = glGetError(); - assert(err == GL_NO_ERROR); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_bo[VERTINDEXBO]->_bohandle); - err = glGetError(); - assert(err == GL_NO_ERROR); - glDrawElements( GL_TRIANGLES, _mesh.fn * _bo[VERTINDEXBO]->_components,GL_UNSIGNED_INT ,NULL); - err = glGetError(); - printf("errore (%s)\n",gluErrorString(err)); - assert(err == GL_NO_ERROR); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - err = glGetError(); - assert(err == GL_NO_ERROR); - } - - glBindTexture(GL_TEXTURE_2D,0); - glDisable(GL_TEXTURE_2D); - } - glBindVertexArray(0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); - glBindBuffer(GL_ARRAY_BUFFER,0); - - return true; - } - - void drawPoints(GLuint& vaohandlespecificperopenglcontext) - { - glDisable(GL_TEXTURE_2D); - - glBindVertexArray(vaohandlespecificperopenglcontext); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[VERTINDEXBO]->_bohandle); - glDrawArrays(GL_POINTS,0,_mesh.vn); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - } - - void setBufferPointerEnableClientState( BO_NAMES boname) const - { - if ((boname < VERTPOSITIONBO) || (boname > VERTINDEXBO)) - return; - GLBufferObject* cbo = _bo[boname]; - if (cbo == NULL) - return; - - switch(boname) - { - case(VERTPOSITIONBO): - { - glVertexPointer(cbo->_components, cbo->_gltype, 0, 0); - glEnableClientState(GL_VERTEX_ARRAY); - break; - } - case(VERTNORMALBO): - case(FACENORMALBO): - { - glNormalPointer(cbo->_gltype, 0, 0); - glEnableClientState(GL_NORMAL_ARRAY); - break; - } - case(VERTCOLORBO): - case(FACECOLORBO): - { - glColorPointer(cbo->_components, cbo->_gltype, 0, 0); - glEnableClientState(GL_COLOR_ARRAY); - break; - } - case(VERTTEXTUREBO): - case(WEDGETEXTUREBO): - { - glTexCoordPointer(cbo->_components, cbo->_gltype, 0, 0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - break; - } - case(VERTINDEXBO): - { - break; - } - } - } - - void disableClientState( BO_NAMES boname,const std::vector& importatt) const - { - if ((boname < VERTPOSITIONBO) || (boname > VERTINDEXBO)) - return; - - switch(boname) - { - case(VERTPOSITIONBO): - { - glDisableClientState(GL_VERTEX_ARRAY); - break; - } - case(VERTNORMALBO): - case(FACENORMALBO): - { - if (!importatt[VERTNORMALBO] && !importatt[FACENORMALBO]) - glDisableClientState(GL_NORMAL_ARRAY); - break; - } - case(VERTCOLORBO): - case(FACECOLORBO): - { - if (!importatt[VERTCOLORBO] && !importatt[FACECOLORBO]) - glDisableClientState(GL_COLOR_ARRAY); - break; - } - case(VERTTEXTUREBO): - case(WEDGETEXTUREBO): - { - if (!importatt[VERTTEXTUREBO] && !importatt[WEDGETEXTUREBO]) - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - break; - } - case(VERTINDEXBO): - { - break; - } - } - } - - //expected number of cells should have a the named bo - //generateindex is true when i have a triangle based mesh - // is false when i have a point based mesh - size_t boExpectedSize(BO_NAMES name,bool replicatedpipeline,bool generateindex) const - { - try - { - GLBufferObject& cbo = *_bo.at(name); - size_t vertnum(_mesh.VN()); - size_t facenum(_mesh.FN()); - - switch(name) - { - case(VERTPOSITIONBO): - case(VERTNORMALBO): - case(VERTCOLORBO): - case(VERTTEXTUREBO): - { - if (replicatedpipeline) - return facenum * 3 * cbo._components; - else - return vertnum * cbo._components; - } - - case(FACENORMALBO): - case(FACECOLORBO): - case(WEDGETEXTUREBO): - { - if (replicatedpipeline) - return facenum * 3 * cbo._components; - else - return 0; - } - case(VERTINDEXBO): - { - if (replicatedpipeline || !generateindex) - return 0; - else - return facenum * cbo._components; - } - } - } - catch(std::out_of_range& /*exc*/) - { - return 0; - } - return 0; - } - - //generateindex is true when i have a triangle based mesh - // is false when i have a point based mesh - size_t boExpectedDimension(BO_NAMES name,bool replicatedpipeline,bool generateindex) const - { - try - { - size_t sz = boExpectedSize(name,replicatedpipeline,generateindex); - GLBufferObject& cbo = *_bo.at(name); - return sz * cbo.getSizeOfGLType(); - } - catch(std::out_of_range& /*exc*/) - { - return 0; - } - return 0; - } - - static bool isPerVertexAttribute(BO_NAMES name) - { - return ((name == VERTPOSITIONBO) ||(name == VERTNORMALBO) || (name == VERTCOLORBO) || (name == VERTTEXTUREBO)); - } - - //it's a map containing for each texture seams n a vector of all the triangle index ranges having n has texture seam - //Suppose that in a mesh we have - //TXS_0{t0,t1,t2,t3}, TXS_4{t4,t5},TXS_0{t6},TXS_-1{t7,t8,t9},TXS_4{t10,t11} - //so chunkMap will contain - // -1 -> [] - // 0 -> [,] - // 4 -> [,] - - typedef std::vector< std::pair< GLuint,GLuint > > ChunkVector; - typedef std::map< short, ChunkVector > ChunkMap; - - void fillChunckMap(ChunkMap& cmap) - { - if (!vcg::tri::HasPerWedgeTexCoord(_mesh)) - return; - cmap.clear(); - typename MESHTYPE::FaceIterator infrange = _mesh.face.begin(); - short texind = std::numeric_limits::max(); - int hh = 0; - for(typename MESHTYPE::FaceIterator fit = _mesh.face.begin();fit != _mesh.face.end();++fit) - { - if (fit->WT(0).N() != texind) - { - if ((texind != std::numeric_limits::max()) || (fit == _mesh.face.end() - 1)) - { - GLuint lowind = std::distance(_mesh.face.begin(),infrange); - GLuint topind = std::distance(_mesh.face.begin(),fit) - 1; - cmap[texind].push_back(std::make_pair(lowind,topind)); - infrange = fit; - } - texind = fit->WT(0).N(); - } - ++hh; - } - cmap[texind].push_back(std::make_pair(std::distance(_mesh.face.begin(),infrange),std::distance(_mesh.face.begin(),_mesh.face.end() - 1))); - } - - //ideally this should be const. I'm not yet sure if VCGLib will allow me to declare it as constant - MESHTYPE& _mesh; - MemoryInfo& _gpumeminfo; - - std::vector _bo; - //GLuint vaohandle; - - std::vector< std::pair > _texindnumtriangles; - - bool _lastfeedingusedreplicatedpipeline; - bool _borendering; - size_t _perbatchsimplex; - ChunkMap _chunkmap; - }; -} - -#endif +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef __VCG_GL_MESH_ATTRIBUTES_FEEDER +#define __VCG_GL_MESH_ATTRIBUTES_FEEDER + +#include +#include +#include +#include +#include +#include + +//#include +#include +#include +#include +#include + + +namespace vcg +{ + struct GLFeederInfo + { + struct GLFeederException : public std::exception + { + GLFeederException(const char* text) + :std::exception(),_text(text) {} + + ~GLFeederException() {} + inline const char* what() const throw() {return _text.c_str();} + private: + std::string _text; + }; + + enum ATT_NAMES + { + ATT_ALL = -1, + ATT_VERTPOSITION = 0, + ATT_VERTNORMAL = 1, + ATT_FACENORMAL = 2, + ATT_VERTCOLOR = 3, + ATT_FACECOLOR = 4, + ATT_MESHCOLOR = 5, + ATT_VERTTEXTURE = 6, + ATT_WEDGETEXTURE = 7, + ATT_VERTINDEX = 8, + ATT_NAMES_ARITY = 9 + }; + + enum PRIMITIVE_MODALITY + { + PR_NONE = 0, + PR_TRIANGLES, + PR_POINTS, + PR_QUADS + }; + + typedef unsigned int ATT_BIT_MASK; + + static ATT_BIT_MASK attBitMask(ATT_NAMES attname) + { + if ((attname == ATT_ALL) || (attname == ATT_VERTINDEX)) + return 0xffffffff; + + if ((attname >= ATT_VERTPOSITION) && (attname <= ATT_WEDGETEXTURE)) + { + static const ATT_BIT_MASK res[] = { + 0x00000000, /*attVertPosition()*/ + 0x00000001, /*attVertNormal()*/ + 0x00000002, /*attFaceNormal()*/ + 0x00000004, /*attVertColor()*/ + 0x00000008, /*attFaceColor()*/ + 0x00000010, /*attVertTexture()*/ + 0x00000020}; /*attWedgeTexture()*/ + return res[attname]; + } + else + throw GLFeederException("Out of range value\n"); + return 0; + } + + class ReqAtts + { + public: + ReqAtts() + { + reset(); + } + + + const bool& operator[](ATT_NAMES att) const + { + size_t ii = static_cast(att); + if ((ii < ATT_VERTPOSITION) && (ii > ATT_VERTINDEX)) + throw GLFeederException("Out of range value\n"); + return _atts[ii]; + } + + bool& operator[](ATT_NAMES att) + { + size_t ii = static_cast(att); + if ((ii < ATT_VERTPOSITION) && (ii > ATT_VERTINDEX)) + throw GLFeederException("Out of range value\n"); + return _atts[ii]; + } + + void reset() + { + for(size_t ii = 0;ii < _size;++ii) + _atts[ii] = false; + _pm = PR_NONE; + } + + inline PRIMITIVE_MODALITY& primitiveModality() + { + return _pm; + } + + inline PRIMITIVE_MODALITY primitiveModality() const + { + return _pm; + } + + private: + static const size_t _size = ATT_NAMES_ARITY; + bool _atts[_size]; + PRIMITIVE_MODALITY _pm; + }; + }; + + //WARNING! member functions of this class should be called by the host application using concurrency + template + class GLMeshAttributesFeeder : public GLFeederInfo + { + public: + GLMeshAttributesFeeder(/*const*/ MESHTYPE& mesh,MemoryInfo& meminfo, size_t perbatchprimitives) + :_mesh(mesh),_gpumeminfo(meminfo),_bo(ATT_NAMES_ARITY,NULL),_currboatt(),_allreqattsmap(),_lastfeedingusedreplicatedpipeline(false),_perbatchprim(perbatchprimitives),_chunkmap(),_borendering(false),_rendermodinitialized(false) + { + _bo[GLFeederInfo::ATT_VERTPOSITION] = new GLBufferObject(3,GL_FLOAT,GL_VERTEX_ARRAY,GL_ARRAY_BUFFER); + _bo[GLFeederInfo::ATT_VERTNORMAL] = new GLBufferObject(3,GL_FLOAT,GL_NORMAL_ARRAY,GL_ARRAY_BUFFER); + _bo[GLFeederInfo::ATT_FACENORMAL] = new GLBufferObject(3,GL_FLOAT,GL_NORMAL_ARRAY,GL_ARRAY_BUFFER); + _bo[GLFeederInfo::ATT_VERTCOLOR] = new GLBufferObject(4,GL_UNSIGNED_BYTE,GL_COLOR_ARRAY,GL_ARRAY_BUFFER); + _bo[GLFeederInfo::ATT_FACECOLOR] = new GLBufferObject(4,GL_UNSIGNED_BYTE,GL_COLOR_ARRAY,GL_ARRAY_BUFFER); + /*MESHCOLOR has not a buffer object associated with it. It's just a call to glColor3f. it's anyway added to the _bo arrays for sake of coherence*/ + _bo[GLFeederInfo::ATT_MESHCOLOR] = NULL; + _bo[GLFeederInfo::ATT_VERTTEXTURE] = new GLBufferObject(2,GL_FLOAT,GL_TEXTURE_COORD_ARRAY,GL_ARRAY_BUFFER); + _bo[GLFeederInfo::ATT_WEDGETEXTURE] = new GLBufferObject(2,GL_FLOAT,GL_TEXTURE_COORD_ARRAY,GL_ARRAY_BUFFER); + _bo[GLFeederInfo::ATT_VERTINDEX] = new GLBufferObject(3,GL_UNSIGNED_INT,GL_ELEMENT_ARRAY_BUFFER); + } + + ~GLMeshAttributesFeeder() + { + for(size_t ii = 0;ii < _bo.size();++ii) + delete _bo[ii]; + _bo.clear(); + } + + void meshAttributesUpdated(int mask) + { + if ((_mesh.VN() != _mesh.vert.size()) || (_mesh.FN() != _mesh.face.size())) + { + throw GLFeederException("The current mesh contains vertices/faces marked as deleted!\nPlease, call the compact vectors function in order to properly remove them\n"); + return; + } + + if (!_rendermodinitialized) + { + throw GLFeederException("Required attributes for rendering were not properly initialized\nInvokation of setAttributesToBeRendered function is strictly required!\n"); + return; + } + + bool boupdatedrequired = false; + if (((mask & attBitMask(GLFeederInfo::ATT_VERTPOSITION)) || (mask & attBitMask(ATT_ALL))) && (_currboatt[ATT_VERTPOSITION])) + { + boupdatedrequired = true; + _bo[GLFeederInfo::ATT_VERTPOSITION]->_isvalid = false; + } + + if (((mask & attBitMask(GLFeederInfo::ATT_VERTNORMAL)) || (mask & attBitMask(ATT_ALL))) && (_currboatt[ATT_VERTNORMAL] && vcg::tri::HasPerVertexNormal(_mesh))) + { + boupdatedrequired = true; + _bo[GLFeederInfo::ATT_VERTNORMAL]->_isvalid = false; + } + + if (((mask & attBitMask(GLFeederInfo::ATT_FACENORMAL)) || (mask & attBitMask(ATT_ALL))) && (_currboatt[ATT_FACENORMAL] && vcg::tri::HasPerFaceNormal(_mesh))) + { + boupdatedrequired = true; + _bo[GLFeederInfo::ATT_FACENORMAL]->_isvalid = false; + } + + if (((mask & attBitMask(GLFeederInfo::ATT_VERTCOLOR)) || (mask & attBitMask(ATT_ALL))) && (_currboatt[ATT_VERTCOLOR] && vcg::tri::HasPerVertexColor(_mesh))) + { + boupdatedrequired = true; + _bo[GLFeederInfo::ATT_VERTCOLOR]->_isvalid = false; + } + + if (((mask & attBitMask(GLFeederInfo::ATT_FACECOLOR)) || (mask & attBitMask(ATT_ALL))) && (_currboatt[ATT_FACECOLOR] && vcg::tri::HasPerFaceColor(_mesh))) + { + boupdatedrequired = true; + _bo[GLFeederInfo::ATT_FACECOLOR]->_isvalid = false; + } + + + if (((mask & attBitMask(GLFeederInfo::ATT_VERTTEXTURE)) || (mask & attBitMask(ATT_ALL))) && (_currboatt[ATT_VERTTEXTURE] && vcg::tri::HasPerVertexTexCoord(_mesh))) + { + boupdatedrequired = true; + _bo[GLFeederInfo::ATT_VERTTEXTURE]->_isvalid = false; + } + + if (((mask & attBitMask(GLFeederInfo::ATT_WEDGETEXTURE)) || (mask & attBitMask(ATT_ALL))) && (_currboatt[ATT_WEDGETEXTURE] && vcg::tri::HasPerWedgeTexCoord(_mesh))) + { + boupdatedrequired = true; + _bo[GLFeederInfo::ATT_WEDGETEXTURE]->_isvalid = false; + } + + if (mask & attBitMask(ATT_ALL)) + { + boupdatedrequired = true; + _bo[GLFeederInfo::ATT_VERTINDEX]->_isvalid = false; + } + + if (boupdatedrequired) + tryToAllocateAttributesInBO(); + } + + bool setupRequestedAttributes(unsigned int viewid,const ReqAtts& rq) + { + if (!_rendermodinitialized) + _rendermodinitialized = true; + try + { + std::map::iterator it = _allreqattsmap.insert(std::make_pair(viewid,rq)); + computeARequestedAttributesSetCompatibleWithMesh(_mesh,it->second); + mergeReqAtts(*it,_currboatt); + return tryToAllocateAttributesInBO(); + } + catch (GLFeederException& e) + { + return false; + } + return false; + } + + void buffersDeAllocationRequested() + { + for(typename std::vector::iterator it = _bo.begin();it != _bo.end();++it) + { + if ((*it != NULL) && ((*it)->_isvalid)) + { + glDeleteBuffers(1,&((*it)->_bohandle)); + (*it)->_isvalid = false; + (*it)->_bohandle = 0; + } + } + } + + void draw(unsigned int viewid,const std::vector textid = std::vector()) + { + + std::map::iterator viewiter = _allreqattsmap.find(viewid); + if (viewiter == _allreqattsmap.end()) + return; + draw(viewiter->second,textid); + } + + void setPerBatchPrimitives(size_t perbatchprimitives) + { + _perbatchprim = perbatchprimitives; + } + + size_t perBatchPrimitives() const + { + return _perbatchprim; + } + + bool isPossibleToUseBORendering() const + { + return _borendering; + } + + static bool isVertexIndexingRequired(const ReqAtts& rqatt) + { + PRIMITIVE_MODALITY pm = rqatt.primitiveModality(); + return (!isReplicatedPipeline(rqatt) && (pm != PR_POINTS) && (pm != PR_NONE)); + } + + protected: + struct GLBufferObject + { + GLBufferObject(size_t components,GLenum gltype,GLenum clientstatetag,GLenum target) + :_size(0),_components(components),_isvalid(false),_gltype(gltype),_clientstatetag(clientstatetag),_target(target),_bohandle(0) + { + } + + GLBufferObject(size_t components,GLenum gltype,GLenum target) + :_size(0),_components(components),_isvalid(false),_gltype(gltype),_clientstatetag(),_target(target),_bohandle(0) + { + } + + size_t getSizeOfGLType() const + { + switch(_gltype) + { + case(GL_FLOAT): + return sizeof(GLfloat); + case(GL_INT): + return sizeof(GLint); + case(GL_UNSIGNED_INT): + return sizeof(GLuint); + case(GL_UNSIGNED_BYTE): + return sizeof(GLubyte); + } + return 0; + } + + size_t _size; + const size_t _components; + bool _isvalid; + const GLenum _gltype; + const GLenum _target; + + /*WARNING!!!!!!!!!!!!!!!!! In openGL INDEX BO doesn't require to be enabled/disabled so has NOT a valid tag associated. + In this case the client state tag remains not initialized and it's not meaningful */ + const GLenum _clientstatetag; + /**********************************************************************************/ + + GLuint _bohandle; + }; + + const GLBufferObject& getBufferObjectInfo(ATT_NAMES boname) const + { + return _bo[boname]; + } + + static void mergeReqAtts(const ReqAtts& newone,ReqAtts& tomerge) + { + for(size_t ii = 0; ii < ReqAtts::_size;++ii) + { + ATT_NAMES name = static_cast(ii); + tomerge[name] = tomerge[name] || newone[name]; + } + + if (unsigned int(tomerge._pm) <= unsigned int(newone._pm)) + tomerge._pm = newone._pm; + + } + + static void computeARequestedAttributesSetCompatibleWithMesh(ReqAtts& rqatt,const MESHTYPE& mesh) + { + if (mesh.VN() == 0) + { + rqatt.reset(); + return; + } + + rqatt[ATT_VERTPOSITION] = true; + rqatt[ATT_VERTNORMAL] = rqatt[ATT_VERTNORMAL] && vcg::tri::HasPerVertexNormal(mesh); + rqatt[ATT_FACENORMAL] = rqatt[ATT_FACENORMAL] && vcg::tri::HasPerFaceNormal(mesh); + rqatt[ATT_VERTCOLOR] = rqatt[ATT_VERTCOLOR] && vcg::tri::HasPerVertexColor(mesh); + rqatt[ATT_FACECOLOR] = rqatt[ATT_FACECOLOR] && vcg::tri::HasPerFaceColor(mesh); + rqatt[ATT_MESHCOLOR] = rqatt[ATT_MESHCOLOR]; + rqatt[ATT_VERTTEXTURE] = rqatt[ATT_VERTTEXTURE] && vcg::tri::HasPerVertexTexCoord(mesh); + rqatt[ATT_WEDGETEXTURE] = rqatt[ATT_WEDGETEXTURE] && vcg::tri::HasPerWedgeTexCoord(mesh); + rqatt[ATT_VERTINDEX] = rqatt[ATT_VERTINDEX]; + } + + static bool isReplicatedPipeline(const ReqAtts& rqatt) + { + return (rqatt[ATT_FACENORMAL] || rqatt[ATT_FACECOLOR] || rqatt[ATT_WEDGETEXTURE]); + } + + bool buffersAllocationFunction(std::vector& attributestobeupdated) + { + bool replicated = isReplicatedPipeline(_currboatt); + attributestobeupdated.clear(); + attributestobeupdated.resize(_bo.size()); + long long unsigned int bomemoryrequiredbymesh = bufferObjectsMemoryRequired(_currboatt); + bool generateindex = isVertexIndexingRequired(_currboatt); + unsigned int ii = 0; + + for(typename std::vector::iterator it = _bo.begin();it != _bo.end();++it) + { + ATT_NAMES boname = static_cast(ii); + size_t sz = boExpectedSize(boname,replicated,generateindex); + size_t dim = boExpectedDimension(boname,replicated,generateindex); + if ((*it != NULL) && ( + /*a mesh attributes has been updated and the number of already allocated bo cells to contain the attribute values doesn't suit anymore + (i.e. if i change just the vertex positions without changing the vertex numbers i have not to reallocate the previous vertposition bo, it's just sufficient to update the vertex coordinates)*/ + ((!(*it)->_isvalid) && (sz != (*it)->_size)) || + /*if _lastfeedingusedreplicatedpipeline == false means that maybe there are valid per vertex attribute buffer objects that MUST be reallocated anyway cause we have to switch to the replicated attributes pipeline*/ + (replicated && !_lastfeedingusedreplicatedpipeline && (isPerVertexAttribute(boname) || (boname == GLFeederInfo::ATT_VERTINDEX))) || + /*we switched back from the replicated pipeline to the normal one. All the bos have to be regenerated*/ + (!replicated && _lastfeedingusedreplicatedpipeline) || + /*the buffer object is valid but for same reason the number of cells of the bo don't suit anymore the required size. we have to reallocate the buffer object*/ + (((*it)->_isvalid) && (sz != (*it)->_size))) || + //the buffer is valid, but the attribute is not required to be displayed + (((*it)->_isvalid) && !isAttributeRequiredToBeDisplayed(boname))) + { + + //disableClientState(boname,importattribute); + + /*WARNING! THIS CODE MUST BE INCAPSULATED INTO A DEALLOCATE FUNCTION IN A PROPER MADE BUFFER OBJECT CLASS + I DON'T INSERT IT INTO THE GLBufferObjectInfo CLASS CAUSE I CONSIDER IT A TEMPORARY PRIVATE STRUCT*/ + glDeleteBuffers(1,&((*it)->_bohandle)); + (*it)->_bohandle = 0; + if ((*it)->_size > 0) + //we don't use dim cause dim is the value that is going to be allocated, instead use (*it)->_size * (*it)->getSizeOfGLType() is the value already in the buffer + _gpumeminfo.releasedMemory((*it)->_size * (*it)->getSizeOfGLType()); + (*it)->_isvalid = false; + (*it)->_size = 0; + /**********************************************************************************************************/ + } + /*there are already mesh attributes properly allocated in memory, we don't need to allocate them again. there could be invalid values attributes but with properly memory space already allocated in memory + (i.e. i changed the pervertex colors but the vertex numbers remained constant)*/ + if ((*it != NULL) && (/*((*it)->_isvalid) &&*/ (sz == (*it)->_size))) + bomemoryrequiredbymesh -= dim; + ++ii; + } + + if (!_gpumeminfo.isAdditionalMemoryAvailable(bomemoryrequiredbymesh)) + { + std::cout << "no additional memory available!!! memory required: " << bomemoryrequiredbymesh << std::endl; + ii = 0; + for(typename std::vector::iterator it = _bo.begin();it != _bo.end();++it) + { + ATT_NAMES boname = static_cast(ii); + size_t sz(boExpectedSize(boname,replicated,generateindex)); + //there are already valid mesh attributes properly allocated in memory but there is not enough gpu memory for the remaining mesh. + //we have to deallocate the previously allocated mesh attributes + if ((*it != NULL) && ((sz == (*it)->_size))) + { + long long unsigned int dim(boExpectedDimension(boname,replicated,_currboatt[GLFeederInfo::ATT_VERTINDEX])); + //disableClientState(boname,importattribute); + if ((*it)->_size > 0) + { + + + /*WARNING! THIS CODE MUST BE INCAPSULATED INTO A DEALLOCATE FUNCTION IN A PROPER MADE BUFFER OBJECT CLASS + I DON'T INSERT IT INTO THE GLBufferObjectInfo CLASS CAUSE I CONSIDER IT A TEMPORARY PRIVATE STRUCT*/ + glDeleteBuffers(1,&(*it)->_bohandle); + (*it)->_bohandle = 0; + _gpumeminfo.releasedMemory(dim); + } + (*it)->_isvalid = false; + (*it)->_size = 0; + /*********************************************************************************************************/ + } + ++ii; + } + _borendering = false; + _lastfeedingusedreplicatedpipeline = false; + return false; + } + else + { + unsigned int ii = 0; + //I have to update the invalid buffers requested to be imported + for(size_t kk = 0;kk < attributestobeupdated.size();++kk) + attributestobeupdated[kk] = _currboatt[static_cast(kk)]; + bool failedallocation = false; + typename std::vector::iterator it = _bo.begin(); + while((it != _bo.end()) && (!failedallocation)) + { + ATT_NAMES boname = static_cast(ii); + GLBufferObject* cbo = _bo.at(boname); + bool importatt = _currboatt[boname]; + //glBindVertexArray(vaohandlespecificperopenglcontext); + + /*if a bo is not valid but at this point has a valid handle means that attribute values have been updated but the arity of the vertices/faces didn't change. i can use the already allocated space*/ + bool notvalidbuttoberegenerated = (cbo != NULL) && (!cbo->_isvalid) && (cbo->_bohandle != 0) && (importatt); + if (notvalidbuttoberegenerated) + { + cbo->_size = boExpectedSize(boname,replicated,_currboatt[GLFeederInfo::ATT_VERTINDEX]); + long long unsigned int dim = boExpectedDimension(boname,replicated,_currboatt[GLFeederInfo::ATT_VERTINDEX]); + + glGenBuffers(1, &cbo->_bohandle); + glBindBuffer(cbo->_target, cbo->_bohandle); + + //we call glGetError BEFORE the glBufferData function in order to clean the error flag + GLenum err = glGetError(); + glBufferData(cbo->_target, dim, NULL, GL_STATIC_DRAW); + err = glGetError(); + + //even if there according the MemoryInfo subclass there is enough space we were not able to allocate an attribute buffer object. We have to deallocate all the bos related to this mesh + failedallocation = (err == GL_OUT_OF_MEMORY); + if (!failedallocation) + { + //setBufferPointerEnableClientState(boname); + setBufferPointer(boname); + _gpumeminfo.acquiredMemory(dim); + } + attributestobeupdated[boname] = !failedallocation; + cbo->_isvalid = !failedallocation; + _borendering = !failedallocation; + glBindBuffer(cbo->_target, 0); + } + else + { + attributestobeupdated[boname] = false; + if ((!cbo->_isvalid) && (cbo->_bohandle != 0) && (importatt)) + { + attributestobeupdated[boname] = true; + cbo->_isvalid = true; + } + if (!importatt) + cbo->_isvalid = false; + } + + //if ((cbo == NULL) || (!cbo->_isvalid)) + //{ + // //glBindVertexArray(_vaohandle); + // disableClientState(boname,requestedattributes); + // //glBindVertexArray(0); + //} + ++it; + ++ii; + //glBindVertexArray(0); + } + if (failedallocation) + { + for(typename std::vector::iterator boit = _bo.begin();boit != _bo.end();++boit) + { + glDeleteBuffers(1,&((*it)->_bohandle)); + (*it)->_bohandle = 0; + if ((*it)->_size > 0) + //we don't use dim cause dim is the value that is going to be allocated, instead use (*it)->_size * (*it)->getSizeOfGLType() is the value already in the buffer + _gpumeminfo.releasedMemory((*it)->_size * (*it)->getSizeOfGLType()); + (*it)->_isvalid = false; + (*it)->_size = 0; + } + } + _borendering = true; + _lastfeedingusedreplicatedpipeline = replicated; + return true; + } + } + + bool tryToAllocateAttributesInBO() + { + std::vector attributestobeupdated; + bool replicated = !(isReplicatedPipeline(_currboatt)); + bool immediatemode = !(buffersAllocationFunction(attributestobeupdated)); + + if (immediatemode) + return false; + + bool somethingtoupdate = false; + for(size_t hh = 0;hh < attributestobeupdated.size();++hh) + somethingtoupdate = somethingtoupdate || attributestobeupdated[hh]; + if (somethingtoupdate) + { + if (replicated) + { + //WARNING!In case we have to update the wedgetexture bo maybe (not always!) we must update also the other buffer already in memory + //cause the wedgetexture pipeline force a change in the order of the triangles in GPU. + //they are now ordered by the texture seam and not more by the triangle index! + if (attributestobeupdated[ATT_WEDGETEXTURE]) + { + for(size_t jj = 0;jj < attributestobeupdated.size();++jj) + { + ATT_NAMES att = static_cast(jj); + attributestobeupdated[jj] = _currboatt[att] || attributestobeupdated[jj]; + } + } + updateBuffersReplicatedPipeline(attributestobeupdated); + } + else + updateBuffersIndexedPipeline(attributestobeupdated); + } + return true; + } + + //bool tryToAllocateAttributesInBO(NORMAL_MODALITY nm,COLOR_MODALITY cm) + //{ + // std::vector importattribute(_bo.size()); + // std::vector attributestobeupdated; + // attributesToBeImportedInPointBasedPipeline(importattribute, nm, cm); + // bool immediatemode = !(buffersAllocationFunction(nm,cm,TX_NONE,importattribute,attributestobeupdated)); + // if (immediatemode) + // return false; + // + // bool somethingtoupdate = false; + // for(size_t hh = 0;hh < attributestobeupdated.size();++hh) + // somethingtoupdate = somethingtoupdate || attributestobeupdated[hh]; + // if (somethingtoupdate) + // updateBuffersIndexedPipeline(attributestobeupdated); + // return true; + //} + + bool updateBuffersIndexedPipeline(const std::vector& attributestobeupdated) + { + _chunkmap.clear(); + size_t vn = _mesh.VN(); + size_t tn = _mesh.FN(); + + size_t facechunk = std::min(size_t(tn),_perbatchprim); + size_t vertexchunk = std::min(size_t(vn),_perbatchprim); + + std::vector pv(vertexchunk); + std::vector nv(vertexchunk); + std::vector cv(vertexchunk); // Per vertex Colors + std::vector tv(vertexchunk * 2); + + size_t chunckingpu = 0; + + for(size_t i=0;i_bohandle); + glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * vertexchunk * buffobj->_components * buffobj->getSizeOfGLType(),buffobj->_components * buffobj->getSizeOfGLType() * chuncksize,&pv[0]); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + if (attributestobeupdated[GLFeederInfo::ATT_VERTNORMAL]) + { + GLBufferObject* buffobj = _bo[GLFeederInfo::ATT_VERTNORMAL]; + glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); + glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * vertexchunk * buffobj->_components * buffobj->getSizeOfGLType(),buffobj->_components * buffobj->getSizeOfGLType() * chuncksize,&nv[0]); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + if (attributestobeupdated[GLFeederInfo::ATT_VERTCOLOR]) + { + GLBufferObject* buffobj = _bo[GLFeederInfo::ATT_VERTCOLOR]; + glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); + glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * vertexchunk * buffobj->_components * buffobj->getSizeOfGLType(),buffobj->_components * buffobj->getSizeOfGLType() * chuncksize,&cv[0]); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + if (attributestobeupdated[GLFeederInfo::ATT_VERTTEXTURE]) + { + GLBufferObject* buffobj = _bo[GLFeederInfo::ATT_VERTTEXTURE]; + glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); + glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * vertexchunk * buffobj->_components * buffobj->getSizeOfGLType(),buffobj->_components * buffobj->getSizeOfGLType() * chuncksize,&tv[0]); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + ++chunckingpu; + } + } + + pv.clear(); + nv.clear(); + cv.clear(); + tv.clear(); + + chunckingpu = 0; + std::vector ti(facechunk * 3); + for(size_t i=0;i_bohandle); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,chunckingpu * facechunk * _bo[GLFeederInfo::ATT_VERTINDEX]->_components * _bo[GLFeederInfo::ATT_VERTINDEX]->getSizeOfGLType(),_bo[GLFeederInfo::ATT_VERTINDEX]->_components * _bo[GLFeederInfo::ATT_VERTINDEX]->getSizeOfGLType() * chunksize,&ti[0]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + ++chunckingpu; + } + } + return true; + } + + bool updateBuffersReplicatedPipeline(const std::vector& attributestobeupdated) + { + size_t tn = _mesh.fn; + + size_t facechunk = std::min(size_t(tn),_perbatchprim); + + std::vector rpv(facechunk * 3); + std::vector rnv(facechunk * 3); + std::vector rcv(facechunk * 3); + std::vector rtv(facechunk * 3 * 2); + + size_t chunckingpu = 0; + + //it's a map containing for each texture seams n a vector of all the triangle index ranges having n has texture seam + //Suppose that in a mesh we have + //TXS_0{t0,t1,t2,t3}, TXS_4{t4,t5},TXS_0{t6},TXS_-1{t7,t8,t9},TXS_4{t10,t11} + //so chunkMap will contain + // -1 -> [] + // 0 -> [,] + // 4 -> [,] + // + //if the map has no-texture coords at all in order to unify the code we fill the ChunkMap with texture seam -1 and a single triangle range going from face_0 to face_n-1 + + + if (attributestobeupdated[GLFeederInfo::ATT_WEDGETEXTURE] || attributestobeupdated[GLFeederInfo::ATT_VERTTEXTURE]) + { + _chunkmap.clear(); + if (attributestobeupdated[GLFeederInfo::ATT_WEDGETEXTURE]) + fillChunckMap(_chunkmap); + else + if(attributestobeupdated[GLFeederInfo::ATT_VERTTEXTURE]) + _chunkmap[0].push_back(std::make_pair(0,tn-1)); + } + + //default case: no texture is required to be rendered but a non texture attribute has to be updated + //we have to init the _chunkmap with just one entry (-1...that means no texture) referring all the triangles in the mesh + if ((!_currboatt[ATT_VERTTEXTURE] && !_currboatt[ATT_WEDGETEXTURE]) && + (attributestobeupdated[GLFeederInfo::ATT_VERTPOSITION] || + attributestobeupdated[GLFeederInfo::ATT_VERTNORMAL] || attributestobeupdated[GLFeederInfo::ATT_FACENORMAL] || + attributestobeupdated[GLFeederInfo::ATT_VERTCOLOR] || attributestobeupdated[GLFeederInfo::ATT_FACECOLOR])) + { + _chunkmap.clear(); + _chunkmap[-1].push_back(std::make_pair(0,tn-1)); + } + + int t = 0; + if (attributestobeupdated[GLFeederInfo::ATT_WEDGETEXTURE] || attributestobeupdated[GLFeederInfo::ATT_VERTTEXTURE]) + { + _texindnumtriangles.clear(); + _texindnumtriangles.resize(_chunkmap.size()); + } + int i = 0; + size_t chunkindex = i; + GLuint triangles = 0; + for(ChunkMap::const_iterator mit = _chunkmap.begin();mit != _chunkmap.end();++mit) + { + for (ChunkVector::const_iterator cit = mit->second.begin();cit != mit->second.end();++cit) + { + for(size_t indf = cit->first;indf<=cit->second;++indf) + { + chunkindex = i % facechunk; + if (attributestobeupdated[GLFeederInfo::ATT_VERTPOSITION]) + { + rpv[chunkindex*3+0].Import(_mesh.face[indf].V(0)->P()); + rpv[chunkindex*3+1].Import(_mesh.face[indf].V(1)->P()); + rpv[chunkindex*3+2].Import(_mesh.face[indf].V(2)->P()); + } + if (attributestobeupdated[GLFeederInfo::ATT_VERTNORMAL]) + { + rnv[chunkindex*3+0].Import(_mesh.face[indf].V(0)->N().Normalize()); + rnv[chunkindex*3+1].Import(_mesh.face[indf].V(1)->N().Normalize()); + rnv[chunkindex*3+2].Import(_mesh.face[indf].V(2)->N().Normalize()); + } + else if (attributestobeupdated[GLFeederInfo::ATT_FACENORMAL]) + { + rnv[chunkindex*3+0].Import(_mesh.face[indf].N().Normalize()); + rnv[chunkindex*3+1].Import(_mesh.face[indf].N().Normalize()); + rnv[chunkindex*3+2].Import(_mesh.face[indf].N().Normalize()); + } + + if ((attributestobeupdated[GLFeederInfo::ATT_VERTCOLOR])) + { + rcv[chunkindex*3+0] = _mesh.face[indf].V(0)->C(); + rcv[chunkindex*3+1] = _mesh.face[indf].V(1)->C(); + rcv[chunkindex*3+2] = _mesh.face[indf].V(2)->C(); + } + else if ((attributestobeupdated[GLFeederInfo::ATT_FACECOLOR])) + { + rcv[chunkindex*3+0] = _mesh.face[indf].C(); + rcv[chunkindex*3+1] = _mesh.face[indf].C(); + rcv[chunkindex*3+2] = _mesh.face[indf].C(); + } + + if (attributestobeupdated[GLFeederInfo::ATT_WEDGETEXTURE]) + { + rtv[chunkindex*6+0]=float(_mesh.face[indf].WT(0).U()); + rtv[chunkindex*6+1]=float(_mesh.face[indf].WT(0).V()); + rtv[chunkindex*6+2]=float(_mesh.face[indf].WT(1).U()); + rtv[chunkindex*6+3]=float(_mesh.face[indf].WT(1).V()); + rtv[chunkindex*6+4]=float(_mesh.face[indf].WT(2).U()); + rtv[chunkindex*6+5]=float(_mesh.face[indf].WT(2).V()); + } + else if (attributestobeupdated[GLFeederInfo::ATT_VERTTEXTURE]) + { + rtv[chunkindex*6+0]=float(_mesh.face[indf].V(0)->T().U()); + rtv[chunkindex*6+1]=float(_mesh.face[indf].V(0)->T().V()); + rtv[chunkindex*6+2]=float(_mesh.face[indf].V(1)->T().U()); + rtv[chunkindex*6+3]=float(_mesh.face[indf].V(1)->T().V()); + rtv[chunkindex*6+4]=float(_mesh.face[indf].V(2)->T().U()); + rtv[chunkindex*6+5]=float(_mesh.face[indf].V(2)->T().V()); + } + + if((i == tn - 1) || (chunkindex == facechunk - 1)) + { + size_t chunksize = facechunk; + if (i == tn - 1) + chunksize = chunkindex + 1; + + if (attributestobeupdated[GLFeederInfo::ATT_VERTPOSITION]) + { + GLBufferObject* buffobj = _bo[GLFeederInfo::ATT_VERTPOSITION]; + glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); + glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * facechunk * 3 * buffobj->_components * buffobj->getSizeOfGLType(),3 * buffobj->_components * buffobj->getSizeOfGLType() * chunksize,&rpv[0]); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + if (attributestobeupdated[GLFeederInfo::ATT_VERTNORMAL] || attributestobeupdated[GLFeederInfo::ATT_FACENORMAL]) + { + GLBufferObject* buffobj; + if (attributestobeupdated[GLFeederInfo::ATT_VERTNORMAL]) + buffobj = _bo[GLFeederInfo::ATT_VERTNORMAL]; + else + buffobj = _bo[GLFeederInfo::ATT_FACENORMAL]; + glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); + glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * facechunk * 3 * buffobj->_components * buffobj->getSizeOfGLType(),3 * buffobj->_components * buffobj->getSizeOfGLType() * chunksize,&rnv[0]); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + if (attributestobeupdated[GLFeederInfo::ATT_VERTCOLOR] || attributestobeupdated[GLFeederInfo::ATT_FACECOLOR]) + { + GLBufferObject* buffobj; + if (attributestobeupdated[GLFeederInfo::ATT_VERTCOLOR]) + buffobj = _bo[GLFeederInfo::ATT_VERTCOLOR]; + else + buffobj = _bo[GLFeederInfo::ATT_FACECOLOR]; + glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); + glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * facechunk * 3 *buffobj->_components * buffobj->getSizeOfGLType(),3 * buffobj->_components * buffobj->getSizeOfGLType() * chunksize,&rcv[0]); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + if (attributestobeupdated[GLFeederInfo::ATT_VERTTEXTURE] || attributestobeupdated[GLFeederInfo::ATT_WEDGETEXTURE]) + { + GLBufferObject* buffobj; + if (attributestobeupdated[GLFeederInfo::ATT_VERTTEXTURE]) + buffobj = _bo[GLFeederInfo::ATT_VERTTEXTURE]; + else + buffobj = _bo[GLFeederInfo::ATT_WEDGETEXTURE]; + glBindBuffer(GL_ARRAY_BUFFER, buffobj->_bohandle); + glBufferSubData(GL_ARRAY_BUFFER,chunckingpu * facechunk * 3 *buffobj->_components * buffobj->getSizeOfGLType(),3 * buffobj->_components * buffobj->getSizeOfGLType() * chunksize,&rtv[0]); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + ++chunckingpu; + } + ++i; + } + triangles += cit->second - cit->first + 1; + } + + if (attributestobeupdated[GLFeederInfo::ATT_WEDGETEXTURE] || attributestobeupdated[GLFeederInfo::ATT_VERTTEXTURE]) + _texindnumtriangles[t] = std::make_pair(mit->first,triangles); + ++t; + } + + //return (k != tn) + // throw MeshLabException("Mesh has not been properly partitioned"); + return true; + } + + void draw(const ReqAtts& req,const std::vector textid = std::vector()) + { + if (isPossibleToUseBORendering()) + { + updateClientState(req); + switch(req.primitiveModality()) + { + case(PR_TRIANGLES): + drawTriangles(req,textid); + break; + case(PR_POINTS): + drawPoints(); + break; + case (PR_QUADS): + break; + default: + break; + } + } + else + immediateModeRendering(req,textid); + } + + bool immediateModeRendering(const ReqAtts& req,const std::vector& textureindex = std::vector()) + { + glPushAttrib(GL_ALL_ATTRIB_BITS); + if(_mesh.fn==0) + return false; + + if(req[ATT_MESHCOLOR]) + glColor(_mesh.C()); + + //typename MESHTYPE::FaceContainer::iterator fp; + typename MESHTYPE::FaceIterator fi = _mesh.face.begin(); + + short curtexname=-1; + if(req[ATT_WEDGETEXTURE]) + { + curtexname=(*fi).WT(0).n(); + if ((curtexname >= 0) && (curtexname < (int)textureindex.size())) + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D,textureindex[curtexname]); + } + else + { + glDisable(GL_TEXTURE_2D); + } + } + + if(req[ATT_VERTTEXTURE] && !textureindex.empty()) // in the case of per vertex tex coord we assume that we have a SINGLE texture. + { + curtexname = 0; + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D,textureindex[curtexname]); + } + + glBegin(GL_TRIANGLES); + + while(fi!=_mesh.face.end()) + { + typename MESHTYPE::FaceType & f = *fi; + if(!f.IsD()) + { + if(req[ATT_WEDGETEXTURE]) + if(f.WT(0).n() != curtexname) + { + curtexname=(*fi).WT(0).n(); + glEnd(); + + if (curtexname >= 0) + { + glEnable(GL_TEXTURE_2D); + if(!textureindex.empty()) + glBindTexture(GL_TEXTURE_2D,textureindex[curtexname]); + } + else + { + glDisable(GL_TEXTURE_2D); + } + + glBegin(GL_TRIANGLES); + } + + if(req[ATT_FACENORMAL]) glNormal(f.cN()); + if(req[ATT_VERTNORMAL]) glNormal(f.V(0)->cN()); + //if(nm == NMPerWedge)glNormal(f.WN(0)); + + if(req[ATT_FACECOLOR]) glColor(f.C()); + if(req[ATT_VERTCOLOR]) glColor(f.V(0)->C()); + if(req[ATT_VERTTEXTURE]) glTexCoord(f.V(0)->T().P()); + if(req[ATT_WEDGETEXTURE]) glTexCoord(f.WT(0).t(0)); + glVertex(f.V(0)->P()); + + if(req[ATT_VERTNORMAL]) glNormal(f.V(1)->cN()); + //if(nm == NMPerWedge)glNormal(f.WN(1)); + if(req[ATT_VERTCOLOR]) glColor(f.V(1)->C()); + if(req[ATT_VERTTEXTURE]) glTexCoord(f.V(1)->T().P()); + if(req[ATT_WEDGETEXTURE]) glTexCoord(f.WT(1).t(0)); + glVertex(f.V(1)->P()); + + if(req[ATT_VERTNORMAL]) glNormal(f.V(2)->cN()); + //if(nm == NMPerWedge)glNormal(f.WN(2)); + if(req[ATT_VERTCOLOR]) glColor(f.V(2)->C()); + if(req[ATT_VERTTEXTURE]) glTexCoord(f.V(2)->T().P()); + if(req[ATT_WEDGETEXTURE]) glTexCoord(f.WT(2).t(0)); + glVertex(f.V(2)->P()); + } + ++fi; + } + + glEnd(); + glPopMatrix(); + glPopAttrib(); + return true; + } + + void drawTriangles(const ReqAtts& req,const std::vector& textureindex = std::vector()) + { + //isBORenderingPossible( + if(!isPossibleToUseBORendering()) + return; + + bool replicated = isReplicatedPipeline(_currboatt); + + if (replicated) + { + int firsttriangleoffset = 0; + if(!req[ATT_VERTTEXTURE] && !req[ATT_WEDGETEXTURE]) + { + glDisable(GL_TEXTURE_2D); + glDrawArrays(GL_TRIANGLES,0,_mesh.fn * 3); + } + else + { + glEnable(GL_TEXTURE_2D); + for(std::vector< std::pair >::const_iterator it = _texindnumtriangles.begin();it != _texindnumtriangles.end();++it) + { + if ((it->first != -1) && (it->first < textureindex.size())) + glBindTexture(GL_TEXTURE_2D,textureindex[it->first]); + else + glBindTexture(GL_TEXTURE_2D,0); + glDrawArrays(GL_TRIANGLES,firsttriangleoffset,it->second * 3 - firsttriangleoffset); + firsttriangleoffset = it->second * 3; + } + glBindTexture(GL_TEXTURE_2D,0); + glDisable(GL_TEXTURE_2D); + } + + } + else + { + if(req[ATT_VERTTEXTURE]) + { + if (textureindex.size() > 0) + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D,textureindex[0]); + + } + } + else + glDisable(GL_TEXTURE_2D); + + + if (_bo[ATT_VERTINDEX]->_isvalid) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_bo[ATT_VERTINDEX]->_bohandle); + glDrawElements( GL_TRIANGLES, _mesh.fn * _bo[ATT_VERTINDEX]->_components,GL_UNSIGNED_INT ,NULL); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + glBindTexture(GL_TEXTURE_2D,0); + glDisable(GL_TEXTURE_2D); + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + glBindBuffer(GL_ARRAY_BUFFER,0); + } + + void drawPoints() + { + if(!isPossibleToUseBORendering()) + return; + + glDisable(GL_TEXTURE_2D); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[GLFeederInfo::ATT_VERTINDEX]->_bohandle); + glDrawArrays(GL_POINTS,0,_mesh.vn); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + void updateClientState(const ReqAtts& req) + { + int ii = 0; + for(std::vector::const_iterator it = _bo.begin();it != _bo.end();++it) + { + ATT_NAMES boname = static_cast(ii); + if(boname != GLFeederInfo::ATT_VERTINDEX) + { + if (req[boname] && _currboatt[boname] && (*it != NULL)) + glEnableClientState((*it)->_clientstatetag); + else + disableClientState(boname,req); + } + } + } + + bool isAttributeRequiredToBeDisplayed(ATT_NAMES att) + { + bool res = false; + for(std::map::const_iterator it = _allreqattsmap.begin();it != _allreqattsmap.end();++it) + res |= it->second[att]; + return res; + } + + void setBufferPointer( ATT_NAMES boname) const + { + if ((boname < GLFeederInfo::ATT_VERTPOSITION) || (boname > GLFeederInfo::ATT_VERTINDEX)) + return; + GLBufferObject* cbo = _bo[boname]; + if (cbo == NULL) + return; + + switch(boname) + { + case(GLFeederInfo::ATT_VERTPOSITION): + { + glVertexPointer(cbo->_components, cbo->_gltype, 0, 0); + break; + } + case(GLFeederInfo::ATT_VERTNORMAL): + case(GLFeederInfo::ATT_FACENORMAL): + { + glNormalPointer(cbo->_gltype, 0, 0); + break; + } + case(GLFeederInfo::ATT_VERTCOLOR): + case(GLFeederInfo::ATT_FACECOLOR): + { + glColorPointer(cbo->_components, cbo->_gltype, 0, 0); + break; + } + case(GLFeederInfo::ATT_VERTTEXTURE): + case(GLFeederInfo::ATT_WEDGETEXTURE): + { + glTexCoordPointer(cbo->_components, cbo->_gltype, 0, 0); + break; + } + case(GLFeederInfo::ATT_VERTINDEX): + { + break; + } + } + } + + void disableClientState( ATT_NAMES boname,const ReqAtts& req) const + { + if ((boname < GLFeederInfo::ATT_VERTPOSITION) || (boname > GLFeederInfo::ATT_VERTINDEX)) + return; + + switch(boname) + { + case(GLFeederInfo::ATT_VERTPOSITION): + { + glDisableClientState(GL_VERTEX_ARRAY); + break; + } + case(GLFeederInfo::ATT_VERTNORMAL): + case(GLFeederInfo::ATT_FACENORMAL): + { + if (!req[GLFeederInfo::ATT_VERTNORMAL] && !req[GLFeederInfo::ATT_FACENORMAL]) + glDisableClientState(GL_NORMAL_ARRAY); + break; + } + case(GLFeederInfo::ATT_VERTCOLOR): + case(GLFeederInfo::ATT_FACECOLOR): + { + if (!req[GLFeederInfo::ATT_VERTCOLOR] && !req[GLFeederInfo::ATT_FACECOLOR]) + glDisableClientState(GL_COLOR_ARRAY); + break; + } + case(GLFeederInfo::ATT_VERTTEXTURE): + case(GLFeederInfo::ATT_WEDGETEXTURE): + { + if (!req[GLFeederInfo::ATT_VERTTEXTURE] && !req[GLFeederInfo::ATT_WEDGETEXTURE]) + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + break; + } + default: + { + break; + } + + } + } + + long long unsigned int bufferObjectsMemoryRequired(ReqAtts& rqatt) const + { + bool replicated = isReplicatedPipeline(rqatt); + long long unsigned int result(0); + bool generateindex = isVertexIndexingRequired(rqatt); + + for(unsigned int ii = 0;ii < unsigned int(ATT_NAMES_ARITY);++ii) + { + ATT_NAMES nm = static_cast(ii); + if (rqatt[nm]) + result += (long long unsigned int) boExpectedDimension(nm,replicated,generateindex); + } + return result; + } + + //expected number of cells should have the required bo + //generateindex is true when i have a triangle based mesh + // is false when i have a point based mesh + size_t boExpectedSize(ATT_NAMES name,bool replicatedpipeline,bool generateindex) const + { + try + { + GLBufferObject& cbo = *_bo.at(name); + size_t vertnum(_mesh.VN()); + size_t facenum(_mesh.FN()); + + switch(name) + { + case(GLFeederInfo::ATT_VERTPOSITION): + case(GLFeederInfo::ATT_VERTNORMAL): + case(GLFeederInfo::ATT_VERTCOLOR): + case(GLFeederInfo::ATT_VERTTEXTURE): + { + if (replicatedpipeline) + return facenum * 3 * cbo._components; + else + return vertnum * cbo._components; + } + + case(GLFeederInfo::ATT_FACENORMAL): + case(GLFeederInfo::ATT_FACECOLOR): + case(GLFeederInfo::ATT_WEDGETEXTURE): + { + if (replicatedpipeline) + return facenum * 3 * cbo._components; + else + return 0; + } + case(GLFeederInfo::ATT_VERTINDEX): + { + if (replicatedpipeline || !generateindex) + return 0; + else + return facenum * cbo._components; + } + } + } + catch(std::out_of_range& /*exc*/) + { + return 0; + } + return 0; + } + + //generateindex is true when i have a triangle based mesh + // is false when i have a point based mesh + size_t boExpectedDimension(ATT_NAMES name,bool replicatedpipeline,bool generateindex) const + { + try + { + size_t sz = boExpectedSize(name,replicatedpipeline,generateindex); + GLBufferObject* cbo = _bo.at(name); + if (cbo == NULL) + return 0; + else + return sz * cbo->getSizeOfGLType(); + } + catch(std::out_of_range& /*exc*/) + { + return 0; + } + return 0; + } + + static bool isPerVertexAttribute(ATT_NAMES name) + { + return ((name == GLFeederInfo::ATT_VERTPOSITION) ||(name == GLFeederInfo::ATT_VERTNORMAL) || (name == GLFeederInfo::ATT_VERTCOLOR) || (name == GLFeederInfo::ATT_VERTTEXTURE)); + } + + //it's a map containing for each texture seams n a vector of all the triangle index ranges having n has texture seam + //Suppose that in a mesh we have + //TXS_0{t0,t1,t2,t3}, TXS_4{t4,t5},TXS_0{t6},TXS_-1{t7,t8,t9},TXS_4{t10,t11} + //so chunkMap will contain + // -1 -> [] + // 0 -> [,] + // 4 -> [,] + + typedef std::vector< std::pair< GLuint,GLuint > > ChunkVector; + typedef std::map< short, ChunkVector > ChunkMap; + + void fillChunckMap(ChunkMap& cmap) + { + if (!vcg::tri::HasPerWedgeTexCoord(_mesh)) + return; + cmap.clear(); + typename MESHTYPE::FaceIterator infrange = _mesh.face.begin(); + short texind = std::numeric_limits::max(); + int hh = 0; + for(typename MESHTYPE::FaceIterator fit = _mesh.face.begin();fit != _mesh.face.end();++fit) + { + if (fit->WT(0).N() != texind) + { + if ((texind != std::numeric_limits::max()) || (fit == _mesh.face.end() - 1)) + { + GLuint lowind = std::distance(_mesh.face.begin(),infrange); + GLuint topind = std::distance(_mesh.face.begin(),fit) - 1; + cmap[texind].push_back(std::make_pair(lowind,topind)); + infrange = fit; + } + texind = fit->WT(0).N(); + } + ++hh; + } + cmap[texind].push_back(std::make_pair(std::distance(_mesh.face.begin(),infrange),std::distance(_mesh.face.begin(),_mesh.face.end() - 1))); + } + + //ideally this should be const. I'm not yet sure if VCGLib will allow me to declare it as constant + MESHTYPE& _mesh; + MemoryInfo& _gpumeminfo; + + std::vector _bo; + + /*_currboatt contains the union of all the requested attributes by each single view on the scene. At the end it represents the BOs allocated in the GPU memory*/ + ReqAtts _currboatt; + /*_allreqattmap contains a map of the requested atts by each single view. it's maintained for the actual rendering step*/ + std::map _allreqattsmap; + + std::vector< std::pair > _texindnumtriangles; + + bool _lastfeedingusedreplicatedpipeline; + bool _borendering; + size_t _perbatchprim; + bool _rendermodinitialized; + ChunkMap _chunkmap; + }; +} + +#endif