/**************************************************************************** * 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_INFO #define __VCG_GL_MESH_ATTRIBUTES_INFO namespace vcg { struct GLMeshAttributesInfo { struct GLBOException : public std::exception { GLBOException(const char* text) :std::exception(),_text(text) {} ~GLBOException() throw() {} inline const char* what() const throw() {return _text.c_str();} private: std::string _text; }; /*WARNING!!!! why not a plain and simple enum? because i need to add further values to this enumeration, but the user of the class should not be interested and/or directly manage those other additional values*/ /*the struct is extended in GLMeshAttributesFeeder class, introducing the ATT_VERTINDICES and ATT_EDGEINDICES values for the class internal use*/ struct ATT_NAMES { static const unsigned int ATT_VERTPOSITION = 0; static const unsigned int ATT_VERTNORMAL = 1; static const unsigned int ATT_FACENORMAL = 2; static const unsigned int ATT_VERTCOLOR = 3; static const unsigned int ATT_FACECOLOR = 4; static const unsigned int ATT_MESHCOLOR = 5; static const unsigned int ATT_VERTTEXTURE = 6; static const unsigned int ATT_WEDGETEXTURE = 7; enum {ATT_ARITY = 8}; ATT_NAMES() :_val(ATT_VERTPOSITION) { } ATT_NAMES(unsigned int att) { if ((att < ATT_VERTPOSITION) || (att >= ATT_NAMES::enumArity())) throw GLBOException("Out of range value\n"); else _val = att; } static unsigned int enumArity() { return ATT_ARITY; } operator unsigned int() const { return _val; } bool operator==(unsigned int r) const { return (_val == r); } bool operator!=(unsigned int r) const { return (_val != r); } protected: unsigned int _val; }; enum PRIMITIVE_MODALITY { PR_NONE = 0x00000000, PR_BBOX = 0x00000001, PR_POINTS = 0x00000002, PR_WIREFRAME_EDGES = 0x00000004, PR_WIREFRAME_TRIANGLES = 0x00000008, PR_SOLID = 0x00000010 }; typedef unsigned int PRIMITIVE_MODALITY_MASK; template class RenderingAtts { public: RenderingAtts() { reset(); } RenderingAtts(const RenderingAtts& att) { reset(); //_atts = new bool[ATT_NAMES_DERIVED_CLASS::enumArity()]; for(unsigned int ii = 0;ii < ATT_NAMES_DERIVED_CLASS::enumArity();++ii) (*this)[ii] = att[ii]; } ~RenderingAtts() { } RenderingAtts& operator=(const RenderingAtts& att) { reset(); for(unsigned int ii = 0;ii < ATT_NAMES_DERIVED_CLASS::enumArity();++ii) (*this)[ii] = att[ii]; return (*this); } /*bool operator[](ATT_NAMES_DERIVED_CLASS att) const { unsigned int ii = att; if (ii >= ATT_NAMES_DERIVED_CLASS::enumArity()) throw GLFeederException("Out of range value\n"); return _atts[ii]; } bool& operator[](ATT_NAMES_DERIVED_CLASS att) { unsigned int ii = att; if (ii >= ATT_NAMES_DERIVED_CLASS::enumArity()) throw GLFeederException("Out of range value\n"); return _atts[ii]; }*/ bool operator[](unsigned int ind) const { if (ind >= ATT_NAMES_DERIVED_CLASS::enumArity()) throw GLBOException("Out of range value\n"); return _atts[ind]; } bool& operator[](unsigned int ind) { if (ind >= ATT_NAMES_DERIVED_CLASS::enumArity()) throw GLBOException("Out of range value\n"); return _atts[ind]; } void reset(bool posactivated = false) { //delete[] _atts; //_atts = new bool[ATT_NAMES_DERIVED_CLASS::enumArity()]; for(unsigned int ii = 0;ii < ATT_NAMES_DERIVED_CLASS::enumArity();++ii) _atts[ii] = false; _atts[ATT_NAMES_DERIVED_CLASS::ATT_VERTPOSITION] = posactivated; } static RenderingAtts unionSet(const RenderingAtts& a,const RenderingAtts& b) { RenderingAtts res; for(unsigned int ii = 0; ii < ATT_NAMES_DERIVED_CLASS::enumArity();++ii) res[ii] = a[ii] || b[ii]; return res; } static RenderingAtts complementSet(const RenderingAtts& a,const RenderingAtts& b) { /*TRUTH TABLE*/ //this[ATT_NAMES] | rq[ATT_NAMES] | res // true | true | false // true | false | true // false | true | false // false | false | false RenderingAtts res = a; for(unsigned int ii = 0; ii < ATT_NAMES_DERIVED_CLASS::enumArity();++ii) { if (res[ii]) res[ii] = !(b[ii]); } return res; } static RenderingAtts intersectionSet(const RenderingAtts& a,const RenderingAtts& b) { RenderingAtts res; for(unsigned int ii = 0; ii < ATT_NAMES_DERIVED_CLASS::enumArity();++ii) res[ii] = a[ii] && b[ii]; return res; } //template //static void computeARequestedAttributesSetCompatibleWithMesh(const MESHTYPE& mesh,const PRIMITIVE_MODALITY_MASK,RenderingAtts& rqatt) //{ // if (mesh.VN() == 0) // { // rqatt.reset(); // return; // } // rqatt[ATT_NAMES_DERIVED_CLASS::ATT_VERTPOSITION] = true; // rqatt[ATT_NAMES_DERIVED_CLASS::ATT_VERTNORMAL] = rqatt[ATT_NAMES_DERIVED_CLASS::ATT_VERTNORMAL] && vcg::tri::HasPerVertexNormal(mesh); // rqatt[ATT_NAMES_DERIVED_CLASS::ATT_FACENORMAL] = rqatt[ATT_NAMES_DERIVED_CLASS::ATT_FACENORMAL] && vcg::tri::HasPerFaceNormal(mesh); // rqatt[ATT_NAMES_DERIVED_CLASS::ATT_VERTCOLOR] = rqatt[ATT_NAMES_DERIVED_CLASS::ATT_VERTCOLOR] && vcg::tri::HasPerVertexColor(mesh); // rqatt[ATT_NAMES_DERIVED_CLASS::ATT_FACECOLOR] = rqatt[ATT_NAMES_DERIVED_CLASS::ATT_FACECOLOR] && vcg::tri::HasPerFaceColor(mesh); // rqatt[ATT_NAMES_DERIVED_CLASS::ATT_MESHCOLOR] = rqatt[ATT_NAMES_DERIVED_CLASS::ATT_MESHCOLOR]; // rqatt[ATT_NAMES_DERIVED_CLASS::ATT_VERTTEXTURE] = rqatt[ATT_NAMES_DERIVED_CLASS::ATT_VERTTEXTURE] && vcg::tri::HasPerVertexTexCoord(mesh); // rqatt[ATT_NAMES_DERIVED_CLASS::ATT_WEDGETEXTURE] = rqatt[ATT_NAMES_DERIVED_CLASS::ATT_WEDGETEXTURE] && vcg::tri::HasPerWedgeTexCoord(mesh); //} protected: /*an array of enumArity() bool values*/ bool _atts[ATT_NAMES_DERIVED_CLASS::ATT_ARITY]; }; typedef RenderingAtts RendAtts; //template //static void computeRenderingAttributesCompatibleWithMesh( const MESH_TYPE& mesh,const PRIMITIVE_MODALITY_MASK& inputpm,const RendAtts& inputatts, // PRIMITIVE_MODALITY_MASK& outputpm,RendAtts& outputatts ) //{ // outputpm = 0; // outputatts.reset(); // if (mesh.VN() == 0) // return; // outputatts[ATT_NAMES::ATT_VERTPOSITION] = inputatts[ATT_NAMES::ATT_VERTPOSITION]; // bool validfaces = (mesh.FN() > 0); // if (!validfaces) // { // outputpm = (unsigned int) PR_POINTS; // return; // } // outputpm = inputpm; // if ((inputpm & vcg::GLMeshAttributesInfo::PR_WIREFRAME_EDGES) && (!vcg::tri::HasPerVertexFlags(mesh))) // outputpm = outputpm & (!vcg::GLMeshAttributesInfo::PR_WIREFRAME_EDGES); // outputatts[ATT_NAMES::ATT_VERTNORMAL] = inputatts[ATT_NAMES::ATT_VERTNORMAL] && vcg::tri::HasPerVertexNormal(mesh); // outputatts[ATT_NAMES::ATT_FACENORMAL] = inputatts[ATT_NAMES::ATT_FACENORMAL] && vcg::tri::HasPerFaceNormal(mesh) && validfaces; // outputatts[ATT_NAMES::ATT_VERTCOLOR] = inputatts[ATT_NAMES::ATT_VERTCOLOR] && vcg::tri::HasPerVertexColor(mesh); // outputatts[ATT_NAMES::ATT_FACECOLOR] = inputatts[ATT_NAMES::ATT_FACECOLOR] && vcg::tri::HasPerFaceColor(mesh) && validfaces; // outputatts[ATT_NAMES::ATT_MESHCOLOR] = inputatts[ATT_NAMES::ATT_MESHCOLOR]; // //horrible trick caused by MeshLab GUI. In MeshLab exists just a button turning on/off the texture visualization. // //Unfortunately the RenderMode::textureMode member field is not just a boolean value but and enum one. // //The enum-value depends from the enabled attributes of input mesh. // bool wedgetexture = vcg::tri::HasPerWedgeTexCoord(mesh) && validfaces; // outputatts[ATT_NAMES::ATT_VERTTEXTURE] = inputatts[ATT_NAMES::ATT_VERTTEXTURE] && (vcg::tri::HasPerVertexTexCoord(mesh) && (!wedgetexture)); // outputatts[ATT_NAMES::ATT_WEDGETEXTURE] = inputatts[ATT_NAMES::ATT_WEDGETEXTURE] && wedgetexture; //} protected: struct INT_ATT_NAMES : public ATT_NAMES { /*WARNING!!!!!! the edges index bo it's just used only by the edges and quads meshes, NOT by the triangle meshes. Triangles meshes use just the vertex index array*/ /*WHY? cause quads meshes need both index arrays. One to render the "usual" mesh, the other one to render the wireframe quadrangulation on top of it*/ /*A triangles meshes rendered in wireframe or in solid wireframe, in order to save GPU memory, use the glPolygonMode approach*/ /*Edges meshes uses the edges index array just for a matter of coherence*/ /*WARNING!!!! to be changed whit ATT_NAMES::enumArity() + 1 (and so on...) as soon as constexpr will be supported by most of the old c++ compilers*/ static const unsigned int ATT_VERTINDICES = 8; static const unsigned int ATT_EDGEINDICES = 9; enum {ATT_ARITY = 10}; INT_ATT_NAMES() :ATT_NAMES() { } INT_ATT_NAMES(unsigned int att) :ATT_NAMES() { if ((att < INT_ATT_NAMES::ATT_VERTPOSITION) || (att >= INT_ATT_NAMES::enumArity())) throw GLBOException("Out of range value\n"); else _val = att; } static unsigned int enumArity() { return ATT_ARITY; } operator unsigned int() const { return _val; } }; class InternalRendAtts : public RenderingAtts { public: InternalRendAtts() :RenderingAtts() { } InternalRendAtts(const RendAtts& reqatt) :RenderingAtts() { for(unsigned int ii = 0;ii < ATT_NAMES::enumArity();++ii) { (*this)[ii] = reqatt[ii]; } (*this)[INT_ATT_NAMES::ATT_VERTINDICES] = false; (*this)[INT_ATT_NAMES::ATT_EDGEINDICES] = false; } InternalRendAtts(const RendAtts& reqatt,PRIMITIVE_MODALITY pm) :RenderingAtts() { for(unsigned int ii = 0;ii < ATT_NAMES::enumArity();++ii) (*this)[ii] = reqatt[ii]; (*this)[INT_ATT_NAMES::ATT_VERTINDICES] = isVertexIndexingRequired(reqatt,pm); (*this)[INT_ATT_NAMES::ATT_EDGEINDICES] = isEdgeIndexingRequired(pm); } InternalRendAtts(const RendAtts& reqatt,PRIMITIVE_MODALITY_MASK pm) :RenderingAtts() { for(unsigned int ii = 0;ii < ATT_NAMES::enumArity();++ii) (*this)[ii] = reqatt[ii]; (*this)[INT_ATT_NAMES::ATT_VERTINDICES] = isVertexIndexingRequired(reqatt,pm); (*this)[INT_ATT_NAMES::ATT_EDGEINDICES] = isEdgeIndexingRequired(pm); } InternalRendAtts(const RenderingAtts& r) :RenderingAtts(r) { } static InternalRendAtts create(const RendAtts& rqatts,PRIMITIVE_MODALITY_MASK pm) { return InternalRendAtts(rqatts,pm); } //upcast from InternalRendAtts to RendAtts operator RendAtts() const { RendAtts rendatt; for(unsigned int ii = 0;ii < ATT_NAMES::enumArity();++ii) rendatt[ii] = _atts[ii]; return rendatt; } static bool isPerVertexAttribute(INT_ATT_NAMES name) { return ((name == INT_ATT_NAMES::ATT_VERTPOSITION) || (name == INT_ATT_NAMES::ATT_VERTNORMAL) || (name == INT_ATT_NAMES::ATT_VERTCOLOR) || (name == INT_ATT_NAMES::ATT_VERTTEXTURE)); } static bool replicatedPipelineNeeded(const RendAtts& rqatt) { return (rqatt[INT_ATT_NAMES::ATT_FACENORMAL] || rqatt[INT_ATT_NAMES::ATT_FACECOLOR] || rqatt[INT_ATT_NAMES::ATT_WEDGETEXTURE]); } static bool isVertexIndexingRequired(const RendAtts& rqatt,PRIMITIVE_MODALITY pm) { return (!replicatedPipelineNeeded(rqatt) && ((pm == PR_SOLID) || (pm == PR_WIREFRAME_TRIANGLES))); } static bool isVertexIndexingRequired(const RendAtts& rqatt,PRIMITIVE_MODALITY_MASK pm) { bool required = false; if (pm & PR_POINTS) required = required || isVertexIndexingRequired(rqatt,PR_POINTS); if (pm & PR_WIREFRAME_EDGES) required = required || isVertexIndexingRequired(rqatt,PR_WIREFRAME_EDGES); if (pm & PR_WIREFRAME_TRIANGLES) required = required || isVertexIndexingRequired(rqatt,PR_WIREFRAME_TRIANGLES); if (pm & PR_SOLID) required = required || isVertexIndexingRequired(rqatt,PR_SOLID); if (pm & PR_BBOX) required = required || isVertexIndexingRequired(rqatt,PR_BBOX); return required; } static bool isEdgeIndexingRequired(PRIMITIVE_MODALITY pm) { return (pm == PR_WIREFRAME_EDGES); } static bool isEdgeIndexingRequired(PRIMITIVE_MODALITY_MASK pm) { bool required = false; //if (pm & PR_POINTS) // required = isEdgeIndexingRequired(PR_POINTS); //if (pm & PR_WIREFRAME_TRIANGLES) // required = isEdgeIndexingRequired(PR_WIREFRAME_TRIANGLES); if (pm & PR_WIREFRAME_EDGES) required = isEdgeIndexingRequired(PR_WIREFRAME_EDGES); //if (pm & PR_SOLID) // required = isEdgeIndexingRequired(PR_SOLID); //if (pm & PR_BBOX) // required = isEdgeIndexingRequired(PR_BBOX); return required; } }; }; } #endif