vcglib/wrap/gl/trimesh.h

2172 lines
69 KiB
C++

/****************************************************************************
* 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_GLTRIMESH
#define __VCG_GLTRIMESH
#include <queue>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
//#include <GL/glew.h>
#include <wrap/gl/space.h>
#include <wrap/gl/math.h>
#include <vcg/space/color4.h>
namespace vcg {
template <typename T>
class GL_TYPE_NM
{public:
static GLenum SCALAR() { assert(0); return 0;}
};
template <> class GL_TYPE_NM<float>
{ public:
typedef GLfloat ScalarType;
static GLenum SCALAR() { return GL_FLOAT; }
};
template <> class GL_TYPE_NM<double>
{public:
typedef GLdouble ScalarType;
static GLenum SCALAR() { return GL_DOUBLE; }
};
//template <> GL_TYPE::SCALAR<double>() { return GL_DOUBLE; }
// classe base di glwrap usata solo per poter usare i vari drawmode, normalmode senza dover
// specificare tutto il tipo (a volte lunghissimo)
// della particolare classe glwrap usata.
class GLW
{
public:
enum DrawMode {DMNone, DMBox, DMPoints, DMWire, DMHidden, DMFlat, DMSmooth, DMFlatWire, DMRadar, DMLast} ;
enum NormalMode {NMNone, NMPerVert, NMPerFace, NMPerWedge, NMLast};
enum ColorMode {CMNone, CMPerMesh, CMPerFace, CMPerVert, CMLast};
enum TextureMode{TMNone, TMPerVert, TMPerWedge, TMPerWedgeMulti};
enum Hint {
HNUseTriStrip = 0x0001, // ha bisogno che ci sia la fftopology gia calcolata!
// HNUseEdgeStrip = 0x0002, //
HNUseDisplayList = 0x0004,
HNCacheDisplayList = 0x0008, // Each mode has its dl;
HNLazyDisplayList = 0x0010, // Display list are generated only when requested
HNIsTwoManifold = 0x0020, // There is no need to make DetachComplex before .
HNUsePerWedgeNormal = 0x0040, //
HNHasFFTopology = 0x0080, // E' l'utente che si preoccupa di tenere aggiornata la topologia ff
HNHasVFTopology = 0x0100, // E' l'utente che si preoccupa di tenere aggiornata la topologia vf
HNHasVertNormal = 0x0200, // E' l'utente che si preoccupa di tenere aggiornata le normali per faccia
HNHasFaceNormal = 0x0400, // E' l'utente che si preoccupa di tenere aggiornata le normali per vertice
HNUseVArray = 0x0800,
HNUseLazyEdgeStrip = 0x1000, // Edge Strip are generated only when requested
HNUseVBO = 0x2000, // Use Vertex Buffer Object
HNIsPolygonal = 0x4000 // In wireframe modes, hide faux edges
};
enum Change {
CHVertex = 0x01,
CHNormal = 0x02,
CHColor = 0x04,
CHFace = 0x08,
CHFaceNormal = 0x10,
CHRender = 0x20,
CHAll = 0xff
};
enum HintParami {
HNPDisplayListSize =0,
HNPPointDistanceAttenuation =1,
HNPPointSmooth = 2
};
enum HintParamf {
HNPCreaseAngle =0, // crease angle in radians
HNPZTwist = 1, // Z offset used in Flatwire and hiddenline modality
HNPPointSize = 2 // the point size used in point rendering
};
template<class MeshType>
class VertToSplit
{
public:
typename MeshType::face_base_pointer f;
char z;
char edge;
bool newp;
typename MeshType::vertex_pointer v;
};
// GL Array Elemet
class GLAElem {
public :
int glmode;
int len;
int start;
};
std::vector<unsigned int> TMId;
};
template <class MeshType, bool partial = false , class FACE_POINTER_CONTAINER = std::vector<typename MeshType::FacePointer> >
class GlTrimesh : public GLW
{
public:
typedef typename MeshType::VertexType VertexType;
typedef typename MeshType::FaceType FaceType;
typedef typename MeshType::VertexType::CoordType CoordType;
typedef typename MeshType::VertexType::ScalarType ScalarType;
typedef typename MeshType::VertexIterator VertexIterator;
typedef typename MeshType::EdgeIterator EdgeIterator;
typedef typename MeshType::FaceIterator FaceIterator;
FACE_POINTER_CONTAINER face_pointers;
MeshType *m;
unsigned int array_buffers[3];
int curr_hints; // the current hints
// The parameters of hints
int HNParami[8];
float HNParamf[8];
DrawMode cdm; // Current DrawMode
NormalMode cnm; // Current NormalMode
ColorMode ccm; // Current ColorMode
static NormalMode convertDrawModeToNormalMode(DrawMode dm)
{
switch(dm)
{
case(DMFlat):
case(DMFlatWire):
case(DMRadar):
return NMPerFace;
case(DMPoints):
case(DMWire):
case(DMSmooth):
return NMPerVert;
default:
return NMNone;
}
return NMNone;
}
GlTrimesh()
{
m=0;
dl=0xffffffff;
curr_hints=HNUseLazyEdgeStrip;
cdm=DMNone;
ccm=CMNone;
cnm=NMNone;
SetHintParamf(HNPCreaseAngle,float(M_PI/5));
SetHintParamf(HNPZTwist,0.00005f);
SetHintParamf(HNPPointSize,1.0f);
SetHintParami(HNPPointDistanceAttenuation, 1);
SetHintParami(HNPPointSmooth, 0);
}
~GlTrimesh()
{
//Delete the VBOs
if(curr_hints&HNUseVBO)
{
for(int i=0;i<3;++i)
if(glIsBuffer(GLuint(array_buffers[i])))
glDeleteBuffersARB(1, (GLuint *)(array_buffers+i));
}
}
unsigned int dl;
std::vector<unsigned int> indices;
void SetHintParami(const HintParami hip, const int value)
{
HNParami[hip]=value;
}
int GetHintParami(const HintParami hip) const
{
return HNParami[hip];
}
void SetHintParamf(const HintParamf hip, const float value)
{
HNParamf[hip]=value;
}
float GetHintParamf(const HintParamf hip) const
{
return HNParamf[hip];
}
void SetHint(Hint hn)
{
curr_hints |= hn;
}
void ClearHint(Hint hn)
{
curr_hints&=(~hn);
}
void Update(/*Change c=CHAll*/)
{
if(m==0) return;
if(curr_hints&HNUseVArray || curr_hints&HNUseVBO)
{
indices.clear();
for(FaceIterator fi = m->face.begin(); fi != m->face.end(); ++fi)
{
indices.push_back((unsigned int)((*fi).V(0) - &(*m->vert.begin())));
indices.push_back((unsigned int)((*fi).V(1) - &(*m->vert.begin())));
indices.push_back((unsigned int)((*fi).V(2) - &(*m->vert.begin())));
}
if(curr_hints&HNUseVBO)
{
if(!glIsBuffer(array_buffers[1]))
glGenBuffers(2,(GLuint*)array_buffers);
glBindBuffer(GL_ARRAY_BUFFER,array_buffers[0]);
glBufferData(GL_ARRAY_BUFFER_ARB, m->vn * sizeof(VertexType),
(char *)&(m->vert[0].P()), GL_STATIC_DRAW_ARB);
glBindBuffer(GL_ARRAY_BUFFER,array_buffers[1]);
glBufferData(GL_ARRAY_BUFFER_ARB, m->vn * sizeof(VertexType),
(char *)&(m->vert[0].N()), GL_STATIC_DRAW_ARB);
}
glVertexPointer(3,GL_TYPE_NM<ScalarType>::SCALAR(),sizeof(VertexType),0);
glNormalPointer(GL_TYPE_NM<ScalarType>::SCALAR(),sizeof(VertexType),0);
}
//int C=c;
//if((C&CHVertex) || (C&CHFace)) {
// ComputeBBox(*m);
// if(!(curr_hints&HNHasFaceNormal)) m->ComputeFaceNormal();
// if(!(curr_hints&HNHasVertNormal)) m->ComputeVertexNormal();
// C= (C | CHFaceNormal);
//}
//if((C&CHFace) && (curr_hints&HNUseEdgeStrip)) ComputeEdges();
//if((C&CHFace) && (curr_hints&HNUseLazyEdgeStrip)) ClearEdges();
//if(MeshType::HasFFTopology())
// if((C&CHFace) && (curr_hints&HNUseTriStrip)) {
// if(!(curr_hints&HNHasFFTopology)) m->FFTopology();
// ComputeTriStrip();
// }
//if((C&CHFaceNormal) && (curr_hints&HNUsePerWedgeNormal)) {
// if(!(curr_hints&HNHasVFTopology)) m->VFTopology();
// CreaseWN(*m,MeshType::scalar_type(GetHintParamf(HNPCreaseAngle)));
//}
//if(C!=0) { // force the recomputation of display list
// cdm=DMNone;
// ccm=CMNone;
// cnm=NMNone;
//}
//if((curr_hints&HNUseVArray) && (curr_hints&HNUseTriStrip))
// {
// ConvertTriStrip<MeshType>(*m,TStrip,TStripF,TStripVED,TStripVEI);
// }
}
void Draw(DrawMode dm ,ColorMode cm, TextureMode tm)
{
switch(dm)
{
case DMNone : Draw<DMNone >(cm,tm); break;
case DMBox : Draw<DMBox >(cm,tm); break;
case DMPoints : Draw<DMPoints >(cm,tm); break;
case DMWire : Draw<DMWire >(cm,tm); break;
case DMHidden : Draw<DMHidden >(cm,tm); break;
case DMFlat : Draw<DMFlat >(cm,tm); break;
case DMSmooth : Draw<DMSmooth >(cm,tm); break;
case DMFlatWire: Draw<DMFlatWire>(cm,tm); break;
default : break;
}
}
template< DrawMode dm >
void Draw(ColorMode cm, TextureMode tm)
{
switch(cm)
{
case CMNone : Draw<dm,CMNone >(tm); break;
case CMPerMesh : Draw<dm,CMPerMesh>(tm); break;
case CMPerFace : Draw<dm,CMPerFace>(tm); break;
case CMPerVert : Draw<dm,CMPerVert>(tm); break;
default : break;
}
}
template< DrawMode dm, ColorMode cm >
void Draw(TextureMode tm)
{
switch(tm)
{
case TMNone : Draw<dm,cm,TMNone >(); break;
case TMPerVert : Draw<dm,cm,TMPerVert >(); break;
case TMPerWedge : Draw<dm,cm,TMPerWedge >(); break;
case TMPerWedgeMulti : Draw<dm,cm,TMPerWedgeMulti >(); break;
default : break;
}
}
template< DrawMode dm, ColorMode cm, TextureMode tm>
void Draw()
{
if(!m) return;
if((curr_hints & HNUseDisplayList)){
if (cdm==dm && ccm==cm){
glCallList(dl);
return;
}
else {
if(dl==0xffffffff) dl=glGenLists(1);
glNewList(dl,GL_COMPILE);
}
}
glPushMatrix();
switch(dm)
{
case DMNone : break;
case DMBox : DrawBBox(cm);break;
case DMPoints : DrawPoints<NMPerVert,cm>();break;
case DMHidden : DrawHidden();break;
case DMFlat : DrawFill<NMPerFace,cm,tm>();break;
case DMFlatWire : DrawFlatWire<NMPerFace,cm,tm>();break;
case DMRadar : DrawRadar<NMPerFace,cm>();break;
case DMWire : DrawWire<NMPerVert,cm>();break;
case DMSmooth : DrawFill<NMPerVert,cm,tm>();break;
default : break;
}
glPopMatrix();
if((curr_hints & HNUseDisplayList)){
cdm=dm;
ccm=cm;
glEndList();
glCallList(dl);
}
}
/*********************************************************************************************/
/*********************************************************************************************/
template <NormalMode nm, ColorMode cm, TextureMode tm>
void DrawFill()
{
if(m->fn==0) return;
if(cm == CMPerMesh)
glColor(m->C());
if(tm == TMPerWedge || tm == TMPerWedgeMulti )
glDisable(GL_TEXTURE_2D);
if(curr_hints&HNUseVBO)
{
if( (cm==CMNone) || (cm==CMPerMesh) )
{
if (nm==NMPerVert)
glEnableClientState (GL_NORMAL_ARRAY);
glEnableClientState (GL_VERTEX_ARRAY);
if (nm==NMPerVert)
{
glBindBuffer(GL_ARRAY_BUFFER,array_buffers[1]);
glNormalPointer(GL_TYPE_NM<ScalarType>::SCALAR(),sizeof(typename MeshType::VertexType),0);
}
glBindBuffer(GL_ARRAY_BUFFER,array_buffers[0]);
glVertexPointer(3,GL_TYPE_NM<ScalarType>::SCALAR(),sizeof(typename MeshType::VertexType),0);
glDrawElements(GL_TRIANGLES ,m->fn*3,GL_UNSIGNED_INT, &(*indices.begin()) );
glDisableClientState (GL_VERTEX_ARRAY);
if (nm==NMPerVert)
glDisableClientState (GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
return;
}
}
if(curr_hints&HNUseVArray)
{
if( (cm==CMNone) || (cm==CMPerMesh) )
{
if (nm==NMPerVert)
glEnableClientState (GL_NORMAL_ARRAY);
glEnableClientState (GL_VERTEX_ARRAY);
if (nm==NMPerVert)
glNormalPointer(GL_TYPE_NM<ScalarType>::SCALAR(),sizeof(typename MeshType::VertexType),&(m->vert.begin()->N()[0]));
glVertexPointer(3,GL_TYPE_NM<ScalarType>::SCALAR(),sizeof(typename MeshType::VertexType),&(m->vert.begin()->P()[0]));
glDrawElements(GL_TRIANGLES ,m->fn*3,GL_UNSIGNED_INT, &(*indices.begin()) );
glDisableClientState (GL_VERTEX_ARRAY);
if (nm==NMPerVert)
glDisableClientState (GL_NORMAL_ARRAY);
return;
}
}
else
if(curr_hints&HNUseTriStrip)
{
//if( (nm==NMPerVert) && ((cm==CMNone) || (cm==CMPerMesh)))
// if(curr_hints&HNUseVArray){
// glEnableClientState (GL_NORMAL_ARRAY );
// glNormalPointer(GL_FLOAT,sizeof(MeshType::VertexType),&(m->vert[0].cN()));
// glEnableClientState (GL_VERTEX_ARRAY);
// glVertexPointer(3,GL_FLOAT,sizeof(MeshType::VertexType),&(m->vert[0].cP()));
// std::vector<GLAElem>::iterator vi;
// for(vi=TStripVED.begin();vi!=TStripVED.end();++vi)
// glDrawElements(vi->glmode ,vi->len,GL_UNSIGNED_SHORT,&TStripVEI[vi->start] );
//
// glDisableClientState (GL_NORMAL_ARRAY );
// glDisableClientState (GL_VERTEX_ARRAY);
// return;
// }
//std::vector< MeshType::VertexType *>::iterator vi;
//glBegin(GL_TRIANGLE_STRIP);
//if(nm == NMPerFace) fip=TStripF.begin();
//for(vi=TStrip.begin();vi!=TStrip.end(); ++vi){
// if((*vi)){
// if(nm==NMPerVert) glNormal((*vi)->cN());
// if(nm==NMPerFace) glNormal((*fip)->cN());
// glVertex((*vi)->P());
// }
// else
// {
// glEnd();
// glBegin(GL_TRIANGLE_STRIP);
// }
// if(nm == NMPerFace) ++fip;
// }
//glEnd();
}
else
{
typename FACE_POINTER_CONTAINER::iterator fp;
FaceIterator fi;
short curtexname=-1;
if(partial)
fp = face_pointers.begin();
else
fi = m->face.begin();
if(tm==TMPerWedgeMulti)
{
curtexname=(*fi).WT(0).n();
if ((curtexname >= 0) && (curtexname < (int)TMId.size()))
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,TMId[curtexname]);
}
else
{
glDisable(GL_TEXTURE_2D);
}
}
if(tm==TMPerWedge)
glEnable(GL_TEXTURE_2D);
if(tm==TMPerVert && !TMId.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,TMId[curtexname]);
}
glBegin(GL_TRIANGLES);
while( (partial)?(fp!=face_pointers.end()):(fi!=m->face.end()))
{
FaceType & f = (partial)?(*(*fp)): *fi;
if(!f.IsD())
{
if(tm==TMPerWedgeMulti)
if(f.WT(0).n() != curtexname)
{
curtexname=(*fi).WT(0).n();
glEnd();
if (curtexname >= 0)
{
glEnable(GL_TEXTURE_2D);
if(!TMId.empty())
glBindTexture(GL_TEXTURE_2D,TMId[curtexname]);
}
else
{
glDisable(GL_TEXTURE_2D);
}
glBegin(GL_TRIANGLES);
}
if(nm == NMPerFace) glNormal(f.cN());
if(nm == NMPerVert) glNormal(f.V(0)->cN());
if(nm == NMPerWedge)glNormal(f.WN(0));
if(cm == CMPerFace) glColor(f.C());
if(cm == CMPerVert) glColor(f.V(0)->C());
if(tm==TMPerVert) glTexCoord(f.V(0)->T().P());
if( (tm==TMPerWedge)||(tm==TMPerWedgeMulti) )glTexCoord(f.WT(0).t(0));
glVertex(f.V(0)->P());
if(nm == NMPerVert) glNormal(f.V(1)->cN());
if(nm == NMPerWedge)glNormal(f.WN(1));
if(cm == CMPerVert) glColor(f.V(1)->C());
if(tm==TMPerVert) glTexCoord(f.V(1)->T().P());
if( (tm==TMPerWedge)|| (tm==TMPerWedgeMulti)) glTexCoord(f.WT(1).t(0));
glVertex(f.V(1)->P());
if(nm == NMPerVert) glNormal(f.V(2)->cN());
if(nm == NMPerWedge)glNormal(f.WN(2));
if(cm == CMPerVert) glColor(f.V(2)->C());
if(tm==TMPerVert) glTexCoord(f.V(2)->T().P());
if( (tm==TMPerWedge)|| (tm==TMPerWedgeMulti)) glTexCoord(f.WT(2).t(0));
glVertex(f.V(2)->P());
}
if(partial)
++fp;
else
++fi;
}
glEnd();
}
}
// A draw wireframe that hides faux edges
template <NormalMode nm, ColorMode cm>
void DrawWirePolygonal()
{
if(cm == CMPerMesh) glColor(m->C());
FaceIterator fi;
typename FACE_POINTER_CONTAINER::iterator fp;
if(partial)
fp = face_pointers.begin();
else
fi = m->face.begin();
glBegin(GL_LINES);
while( (partial)?(fp!=face_pointers.end()):(fi!=m->face.end()))
{
typename MeshType::FaceType & f = (partial)?(*(*fp)): *fi;
if(!f.IsD())
{
if(nm == NMPerFace) glNormal(f.cN());
if(cm == CMPerFace) glColor(f.C());
if (!f.IsF(0)) {
if(nm == NMPerVert) glNormal(f.V(0)->cN());
if(nm == NMPerWedge)glNormal(f.WN(0));
if(cm == CMPerVert) glColor(f.V(0)->C());
glVertex(f.V(0)->P());
if(nm == NMPerVert) glNormal(f.V(1)->cN());
if(nm == NMPerWedge)glNormal(f.WN(1));
if(cm == CMPerVert) glColor(f.V(1)->C());
glVertex(f.V(1)->P());
}
if (!f.IsF(1)) {
if(nm == NMPerVert) glNormal(f.V(1)->cN());
if(nm == NMPerWedge)glNormal(f.WN(1));
if(cm == CMPerVert) glColor(f.V(1)->C());
glVertex(f.V(1)->P());
if(nm == NMPerVert) glNormal(f.V(2)->cN());
if(nm == NMPerWedge)glNormal(f.WN(2));
if(cm == CMPerVert) glColor(f.V(2)->C());
glVertex(f.V(2)->P());
}
if (!f.IsF(2)) {
if(nm == NMPerVert) glNormal(f.V(2)->cN());
if(nm == NMPerWedge)glNormal(f.WN(2));
if(cm == CMPerVert) glColor(f.V(2)->C());
glVertex(f.V(2)->P());
if(nm == NMPerVert) glNormal(f.V(0)->cN());
if(nm == NMPerWedge)glNormal(f.WN(0));
if(cm == CMPerVert) glColor(f.V(0)->C());
glVertex(f.V(0)->P());
}
}
if(partial)
++fp;
else
++fi;
}
glEnd();
}
/// Basic Point drawing fucntion
// works also for mesh with deleted vertices
template<NormalMode nm, ColorMode cm>
void DrawPointsBase()
{
glBegin(GL_POINTS);
if(cm==CMPerMesh) glColor(m->C());
for(VertexIterator vi=m->vert.begin();vi!=m->vert.end();++vi)if(!(*vi).IsD())
{
if(nm==NMPerVert) glNormal((*vi).cN());
if(cm==CMPerVert) glColor((*vi).C());
glVertex((*vi).P());
}
glEnd();
}
/// Utility function that computes in eyespace the current distance between the camera and the center of the bbox of the mesh
double CameraDistance(){
CoordType res;
Matrix44<ScalarType> mm;
glGetv(GL_MODELVIEW_MATRIX,mm);
CoordType c=m->bbox.Center();
res=mm*c;
return Norm(res);
}
template<NormalMode nm, ColorMode cm>
void DrawPoints()
{
glPushAttrib(GL_ENABLE_BIT | GL_POINT_BIT);
if(GetHintParami(HNPPointSmooth)>0) glEnable(GL_POINT_SMOOTH);
else glDisable(GL_POINT_SMOOTH);
glPointSize(GetHintParamf(HNPPointSize));
if(GetHintParami(HNPPointDistanceAttenuation)>0)
{
float camDist = (float)CameraDistance();
float quadratic[] = { 0.0f, 0.0f, 1.0f/(camDist*camDist) , 0.0f };
glPointParameterfv( GL_POINT_DISTANCE_ATTENUATION, quadratic );
glPointParameterf( GL_POINT_SIZE_MAX, 16.0f );
glPointParameterf( GL_POINT_SIZE_MIN, 1.0f );
}
else
{
float quadratic[] = { 1.0f, 0.0f, 0.0f};
glPointParameterfv( GL_POINT_DISTANCE_ATTENUATION, quadratic );
glPointSize(GetHintParamf(HNPPointSize));
}
if(m->vn!=(int)m->vert.size())
{
DrawPointsBase<nm,cm>();
}
else
{
if(cm==CMPerMesh)
glColor(m->C());
if (m->vert.size() != 0)
{
// Perfect case, no deleted stuff,
// draw the vertices using vertex arrays
if (nm==NMPerVert)
{
glEnableClientState (GL_NORMAL_ARRAY);
glNormalPointer(GL_TYPE_NM<ScalarType>::SCALAR(),sizeof(VertexType),&(m->vert.begin()->N()[0]));
}
if (cm==CMPerVert)
{
glEnableClientState (GL_COLOR_ARRAY);
glColorPointer(4,GL_UNSIGNED_BYTE,sizeof(typename MeshType::VertexType),&(m->vert.begin()->C()[0]));
}
glEnableClientState (GL_VERTEX_ARRAY);
glVertexPointer(3,GL_TYPE_NM<ScalarType>::SCALAR(),sizeof(VertexType),&(m->vert.begin()->P()[0]));
glDrawArrays(GL_POINTS,0,m->vn);
glDisableClientState (GL_VERTEX_ARRAY);
if (nm==NMPerVert) glDisableClientState (GL_NORMAL_ARRAY);
if (cm==CMPerVert) glDisableClientState (GL_COLOR_ARRAY);
}
}
glPopAttrib();
return;
}
void DrawHidden()
{
//const float ZTWIST=HNParamf[HNPZTwist];
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT );
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1);
//glDepthRange(ZTWIST,1.0f);
glDisable(GL_LIGHTING);
glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
DrawFill<NMNone,CMNone,TMNone>();
glDisable(GL_POLYGON_OFFSET_FILL);
glEnable(GL_LIGHTING);
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
//glDepthRange(0.0f,1.0f-ZTWIST);
DrawWire<NMPerVert,CMNone>();
glPopAttrib();
// glDepthRange(0,1.0f);
}
template <NormalMode nm, ColorMode cm, TextureMode tm>
void DrawFlatWire()
{
//const float ZTWIST=HNParamf[HNPZTwist];
//glDepthRange(ZTWIST,1.0f);
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT );
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1);
DrawFill<nm,cm,tm>();
glDisable(GL_POLYGON_OFFSET_FILL);
//glDepthRange(0.0f,1.0f-ZTWIST);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
//glColorMaterial(GL_FRONT,GL_DIFFUSE);
glColor3f(.3f,.3f,.3f);
DrawWire<nm,CMNone>();
glPopAttrib();
//glDepthRange(0,1.0f);
}
template <NormalMode nm, ColorMode cm>
void DrawRadar()
{
const float ZTWIST=HNParamf[HNPZTwist];
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(0);
glDepthRange(ZTWIST,1.0f);
if (cm == CMNone)
glColor4f(0.2f, 1.0f, 0.4f, 0.2f);
// DrawFill<nm,cm,TMNone>();
Draw<DMFlat,CMNone,TMNone>();
glDepthMask(1);
glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
// DrawFill<nm,cm,TMNone>();
Draw<DMFlat,CMNone,TMNone>();
glDepthRange(0.0f,1.0f-ZTWIST);
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
glColor4f(0.1f, 1.0f, 0.2f, 0.6f);
Draw<DMWire,CMNone,TMNone>();
glDisable(GL_BLEND);
glDepthRange(0,1.0f);
}
#ifdef GL_TEXTURE0_ARB
// Multitexturing nel caso voglia usare due texture unit.
void DrawTexture_NPV_TPW2()
{
unsigned int texname=(*(m->face.begin())).WT(0).n(0);
glBindTexture(GL_TEXTURE_2D,TMId[texname]);
typename MeshType::FaceIterator fi;
glBegin(GL_TRIANGLES);
for(fi=m->face.begin();fi!=m->face.end();++fi)if(!(*fi).IsD()){
if(texname!=(*fi).WT(0).n(0)) {
texname=(*fi).WT(0).n(0);
glEnd();
glBindTexture(GL_TEXTURE_2D,TMId[texname]);
glBegin(GL_TRIANGLES);
}
glMultiTexCoordARB(GL_TEXTURE0_ARB, (*fi).WT(0).t(0));
glMultiTexCoordARB(GL_TEXTURE1_ARB, (*fi).WT(0).t(0));
glNormal((*fi).V(0)->N());
glVertex((*fi).V(0)->P());
glMultiTexCoordARB(GL_TEXTURE0_ARB, (*fi).WT(1).t(0));
glMultiTexCoordARB(GL_TEXTURE1_ARB, (*fi).WT(1).t(0));
glNormal((*fi).V(1)->N());
glVertex((*fi).V(1)->P());
glMultiTexCoordARB(GL_TEXTURE0_ARB, (*fi).WT(2).t(0));
glMultiTexCoordARB(GL_TEXTURE1_ARB, (*fi).WT(2).t(0));
glNormal((*fi).V(2)->N());
glVertex((*fi).V(2)->P());
}
glEnd();
}
#endif
/*int MemUsed()
{
int tot=sizeof(GlTrimesh);
tot+=sizeof(mesh_type::edge_type)*edge.size();
tot+=sizeof(MeshType::VertexType *) * EStrip.size();
tot+=sizeof(MeshType::VertexType *) * TStrip.size();
tot+=sizeof(MeshType::FaceType *) * TStripF.size();
return tot;
}*/
private:
template <NormalMode nm, ColorMode cm>
void DrawWire()
{
//if(!(curr_hints & (HNUseEdgeStrip | HNUseLazyEdgeStrip) ) )
if ( (curr_hints & HNIsPolygonal) )
{
DrawWirePolygonal<nm,cm>();
}
else
{
glPushAttrib(GL_POLYGON_BIT);
glPolygonMode(GL_FRONT_AND_BACK ,GL_LINE);
DrawFill<nm,cm,TMNone>();
glPopAttrib();
}
if(m->fn==0 && m->en>0)
{
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glBegin(GL_LINES);
for(EdgeIterator ei=m->edge.begin();ei!=m->edge.end(); ++ei)
{
glVertex((*ei).V(0)->P());
glVertex((*ei).V(1)->P());
}
glEnd();
glPopAttrib();
}
// {
// if(!HasEdges()) ComputeEdges();
//if(cm==CMPerMesh) glColor(m->C());
//std::vector< MeshType::VertexType *>::iterator vi;
//glBegin(GL_LINE_STRIP);
//for(vi=EStrip.begin();vi!=EStrip.end(); ++vi){
// if((*vi)){
// glNormal((*vi)->N());
// glVertex((*vi)->P());
// }
// else
// {
// glEnd();
// glBegin(GL_LINE_STRIP);
// }
//}
//glEnd();
// }
}
void DrawBBox(ColorMode cm)
{
if(cm==CMPerMesh) glColor(m->C());
glBoxWire(m->bbox);
}
};// end class
//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 <typename MESHTYPE>
class GLMeshAttributesFeeder : public GLFeedEnum
{
public:
GLMeshAttributesFeeder(/*const*/ MESHTYPE& mesh,MemoryInfo& meminfo, size_t perbatchtriangles = 100)
:_mesh(mesh),_gpumeminfo(meminfo),_bo(8,0),_vaohandle(0),_lastfeedingusedreplicatedpipeline(false),_perbatchsimplex(perbatchtriangles),_chunkmap(),_borendering(false)
{
_bo[VERTPOSITIONBO] = new GLBufferObject(3,GL_FLOAT);
_bo[VERTNORMALBO] = new GLBufferObject(3,GL_FLOAT);
_bo[FACENORMALBO] = new GLBufferObject(3,GL_FLOAT);
_bo[VERTCOLORBO] = new GLBufferObject(4,GL_UNSIGNED_BYTE);
_bo[FACECOLORBO] = new GLBufferObject(4,GL_UNSIGNED_BYTE);
_bo[VERTTEXTUREBO] = new GLBufferObject(2,GL_FLOAT);
_bo[WEDGETEXTUREBO] = new GLBufferObject(2,GL_FLOAT);
_bo[VERTINDEXBO] = new GLBufferObject(3,GL_INT);
}
~GLMeshAttributesFeeder()
{
size_t ii = 0;
for(typename std::vector<GLBufferObject*>::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(NORMAL_MODALITY nm,COLOR_MODALITY cm,TEXTURE_MODALITY tm,const std::vector<GLuint>& textureindex = std::vector<GLuint>())
{
std::vector<bool> importattribute(_bo.size());
std::vector<bool> attributestobeupdated;
attributesToBeImportedInTriangleBasedPipeline(importattribute, nm, cm, tm);
bool replicated = !importattribute[VERTINDEXBO];
bool immediatemode = !(buffersAllocationFunction(nm,cm,tm,importattribute,attributestobeupdated));
if (immediatemode)
immediateMode(nm,cm,tm,textureindex);
else
{
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);
}
drawTriangles(nm,cm,tm,textureindex);
}
}
void passPointsToOpenGL(NORMAL_MODALITY nm,COLOR_MODALITY cm)
{
std::vector<bool> importattribute(_bo.size());
std::vector<bool> attributestobeupdated;
attributesToBeImportedInPointBasedPipeline(importattribute, nm, cm);
GLenum err = glGetError();
assert(err == GL_NO_ERROR);
bool immediatemode = !(buffersAllocationFunction(nm,cm,TX_NONE,importattribute,attributestobeupdated));
err = glGetError();
assert(err == GL_NO_ERROR);
std::vector<GLuint> textureindex;
if (immediatemode)
immediateMode(nm,cm,TX_NONE,textureindex);
else
{
bool somethingtoupdate = false;
for(size_t hh = 0;hh < attributestobeupdated.size();++hh)
somethingtoupdate = somethingtoupdate || attributestobeupdated[hh];
if (somethingtoupdate)
{
GLenum err = glGetError();
assert(err == GL_NO_ERROR);
updateBuffersIndexedPipeline(attributestobeupdated);
err = glGetError();
assert(err == GL_NO_ERROR);
}
err = glGetError();
assert(err == GL_NO_ERROR);
drawPoints(nm,cm);
err = glGetError();
assert(err == GL_NO_ERROR);
}
}
private:
struct GLBufferObject
{
GLBufferObject(size_t components,GLenum gltype)
:_size(0),_components(components),_isvalid(false),_gltype(gltype),_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;
GLuint _bohandle;
};
enum BO_NAMES
{
VERTPOSITIONBO = 0,
VERTNORMALBO = 1,
FACENORMALBO = 2,
VERTCOLORBO = 3,
FACECOLORBO = 4,
VERTTEXTUREBO = 5,
WEDGETEXTUREBO = 6,
VERTINDEXBO = 7
};
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<bool> &importattribute, NORMAL_MODALITY nm, COLOR_MODALITY cm, TEXTURE_MODALITY tm )
{
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<bool> &importattribute, NORMAL_MODALITY nm, COLOR_MODALITY cm)
{
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(NORMAL_MODALITY nm,COLOR_MODALITY cm,TEXTURE_MODALITY tm,const std::vector<bool>& importattribute,std::vector<bool>& attributestobeupdated)
{
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<GLBufferObject*>::iterator it = _bo.begin();it != _bo.end();++it)
{
BO_NAMES boname = static_cast<BO_NAMES>(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<GLBufferObject*>::iterator it = _bo.begin();it != _bo.end();++it)
{
BO_NAMES boname = static_cast<BO_NAMES>(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<GLBufferObject*>::iterator it = _bo.begin();it != _bo.end();++it)
{
BO_NAMES boname = static_cast<BO_NAMES>(ii);
GLBufferObject* cbo = _bo.at(boname);
bool importatt = importattribute.at(boname);
GLenum target = GL_ARRAY_BUFFER;
if (boname == VERTINDEXBO)
target = GL_ELEMENT_ARRAY_BUFFER;
glBindVertexArray(_vaohandle);
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(target, cbo->_bohandle);
glBufferData(target, dim, NULL, GL_STATIC_DRAW);
setBufferPointerEnableClientState(boname);
glBindBuffer(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 updateBuffersIndexedPipeline(const std::vector<bool>& 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<vcg::Point3f> pv(vertexchunk);
std::vector<vcg::Point3f> nv(vertexchunk);
std::vector<vcg::Color4b> cv(vertexchunk); // Per vertex Colors
std::vector<float> tv(vertexchunk * 2);
size_t chunckingpu = 0;
for(size_t i=0;i<vn;++i)
{
size_t chunckindex = i % vertexchunk;
if (attributestobeupdated[VERTPOSITIONBO])
pv[chunckindex].Import(_mesh.vert[i].cP());
if (attributestobeupdated[VERTNORMALBO])
{
nv[chunckindex].Import(_mesh.vert[i].cN());
nv[chunckindex].Normalize();
}
if (attributestobeupdated[VERTCOLORBO])
cv[chunckindex] = _mesh.vert[i].cC();
if (attributestobeupdated[VERTTEXTUREBO])
{
tv[chunckindex*2+0] = _mesh.vert[i].cT().U();
tv[chunckindex*2+1] = _mesh.vert[i].cT().V();
}
if((i == vn - 1) || (chunckindex == vertexchunk - 1))
{
size_t chuncksize = vertexchunk;
if (i == vn - 1)
chuncksize = chunckindex + 1;
if (attributestobeupdated[VERTPOSITIONBO])
{
GLBufferObject* buffobj = _bo[VERTPOSITIONBO];
glBindBuffer(GL_ARRAY_BUFFER, buffobj->_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<GLuint> ti(facechunk * 3);
for(size_t i=0;i<tn;++i)
{
size_t chunckindex = i % facechunk;
ti[chunckindex * 3 + 0] = GLuint(vcg::tri::Index(_mesh,_mesh.face[i].V(0)));
ti[chunckindex * 3 + 1] = GLuint(vcg::tri::Index(_mesh,_mesh.face[i].V(1)));
ti[chunckindex * 3 + 2] = GLuint(vcg::tri::Index(_mesh,_mesh.face[i].V(2)));
if((i == tn - 1) || (chunckindex == facechunk - 1))
{
size_t chunksize = facechunk;
if (i == tn - 1)
chunksize = chunckindex + 1;
if (attributestobeupdated[VERTINDEXBO])
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[VERTINDEXBO]->_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<bool>& attributestobeupdated,GLFeedEnum::TEXTURE_MODALITY currtextmod)
{
size_t vn = _mesh.vn;
size_t tn = _mesh.fn;
size_t facechunk = std::min(size_t(tn),_perbatchsimplex);
std::vector<vcg::Point3f> rpv(facechunk * 3);
std::vector<vcg::Point3f> rnv(facechunk * 3);
std::vector<vcg::Color4b> rcv(facechunk * 3);
std::vector<float> 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 -> [<t7,t9>]
// 0 -> [<t0,t3>,<t6,t6>]
// 4 -> [<t4,t5>,<t10,t11>]
//
//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<GLuint>& textureindex)
{
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(NORMAL_MODALITY nm,COLOR_MODALITY cm,TEXTURE_MODALITY tm,const std::vector<GLuint>& textureindex)
{
std::vector<bool> att(_bo.size(),false);
attributesToBeImportedInTriangleBasedPipeline(att,nm,cm,tm);
bool replicated = !att[VERTINDEXBO];
glBindVertexArray(_vaohandle);
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<short,GLuint> >::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)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_bo[VERTINDEXBO]->_bohandle);
glDrawElements( GL_TRIANGLES, _mesh.fn * _bo[VERTINDEXBO]->_components,GL_UNSIGNED_INT ,NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
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(NORMAL_MODALITY nm,COLOR_MODALITY cm)
{
glDisable(GL_TEXTURE_2D);
glBindVertexArray(_vaohandle);
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)
{
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):
{
glIndexPointer(cbo->_gltype, 0, 0);
glEnableClientState(GL_INDEX_ARRAY);
break;
}
}
}
void disableClientState( BO_NAMES boname,const std::vector<bool>& importatt)
{
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):
{
glDisableClientState(GL_INDEX_ARRAY);
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 -> [<t7,t9>]
// 0 -> [<t0,t3>,<t6,t6>]
// 4 -> [<t4,t5>,<t10,t11>]
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<short>::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<short>::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<GLBufferObject*> _bo;
GLuint _vaohandle;
std::vector< std::pair<short,GLuint> > _texindnumtriangles;
bool _lastfeedingusedreplicatedpipeline;
bool _borendering;
size_t _perbatchsimplex;
ChunkMap _chunkmap;
};
template<typename MESHTYPE>
class SceneToBeRendered
{
public:
SceneToBeRendered(MemoryInfo& gpumeminfo,bool highprecision,size_t perbatchtriangles = 100)
:_scene(),_gpumeminfo(gpumeminfo),_perbatchtriangles(perbatchtriangles),_globalscenecenter(),_highprecision(highprecision)
{
}
~SceneToBeRendered()
{
_scene.clear();
}
void insert(MESHTYPE* mesh,const vcg::Matrix44<typename MESHTYPE::ScalarType>& transfmat)
{
MatrixedFeeder matfeed = std::make_pair(transfmat,GLMeshAttributesFeeder<MESHTYPE>(*mesh,_gpumeminfo,_perbatchtriangles));
_scene[mesh] = matfeed;
if (_highprecision)
computeSceneGlobalCenter();
}
void remove(MESHTYPE* mesh)
{
std::map< MESHTYPE*, MatrixedFeeder >::iterator it = _scene.find(mesh);
if (it != _scene.end())
_scene.erase(it);
}
void update(MESHTYPE* mesh,int mask)
{
std::map< MESHTYPE*, MatrixedFeeder >::iterator it = _scene.find(mesh);
if (it != _scene.end())
it->second._feeder.update(mask);
}
void passTrianglesToOpenGL(MESHTYPE* mesh,GLFeedEnum::NORMAL_MODALITY nm,GLFeedEnum::COLOR_MODALITY cm,GLFeedEnum::TEXTURE_MODALITY tm,const std::vector<GLuint>& textureindex = std::vector<GLuint>())
{
std::map<MESHTYPE*,MatrixedFeeder>::iterator it = _scene.find(mesh);
if(it == _scene.end())
return;
glPushAttrib(GL_TRANSFORM_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
if (_highprecision)
{
vcg::glMultMatrix(it->second._localmeshmatrix);
vcg::glTranslate(_globalscenecenter);
}
it->second._feeder.passTrianglesToOpenGL(nm,cm,tm,textureindex);
glPopMatrix();
glPushAttrib();
}
void passPointsToOpenGL(MESHTYPE* mesh,GLFeedEnum::NORMAL_MODALITY nm,GLFeedEnum::COLOR_MODALITY cm)
{
std::map<MESHTYPE*,MatrixedFeeder>::iterator it = _scene.find(mesh);
if(it == _scene.end())
return;
glPushAttrib(GL_TRANSFORM_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
if (_highprecision)
{
vcg::glMultMatrix(it->second._localmeshmatrix);
vcg::glTranslate(_globalscenecenter);
}
it->second._feeder.passPointsToOpenGL(nm,cm);
glPopMatrix();
glPushAttrib();
}
private:
struct MatrixedFeeder
{
vcg::Matrix44<typename MESHTYPE::ScalarType> _localmeshmatrix;
GLMeshAttributesFeeder<MESHTYPE> _feeder;
MatrixedFeeder(const vcg::Matrix44<typename MESHTYPE::ScalarType>& localmeshmatrix,GLMeshAttributesFeeder& feeder)
:_localmeshmatrix(localmeshmatrix),_feeder(feeder)
{
}
};
void computeSceneGlobalCenter()
{
vcg::Box3<typename MESHTYPE::ScalarType> scenebbox;
for(std::map<MESHTYPE*,MatrixedFeeder >::const_iterator it = _scene.begin();it != _scene.end();++it)
scenebbox.Add(it->first->bbox,it->second._localmeshmatrix);
_globalscenecenter = -scenebbox.Center();
}
std::map< MESHTYPE*, MatrixedFeeder > _scene;
MemoryInfo& _gpumeminfo;
size_t _perbatchtriangles;
vcg::Point3<typename MESHTYPE::ScalarType> _globalscenecenter;
bool _highprecision;
};
} // end namespace
#endif