1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-03 19:52:10 +01:00

1249 lines
36 KiB
C++
Raw Normal View History

/****************************************************************************
This file is part of the GLC-lib library.
Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
Version 2.0.0, packaged on July 2010.
http://glc-lib.sourceforge.net
GLC-lib is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
GLC-lib 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GLC-lib; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
//! \file glc_mesh.cpp Implementation for the GLC_Mesh class.
#include "glc_mesh.h"
#include "../glc_renderstatistics.h"
// Class chunk id
quint32 GLC_Mesh::m_ChunkId= 0xA701;
GLC_Mesh::GLC_Mesh()
:GLC_Geometry("Mesh", false)
, m_NextPrimitiveLocalId(1)
, m_PrimitiveGroups()
, m_DefaultMaterialId(0)
, m_NumberOfVertice(0)
, m_NumberOfNormals(0)
, m_ColorPearVertex(false)
, m_MeshData()
, m_CurrentLod(0)
{
}
GLC_Mesh::GLC_Mesh(const GLC_Mesh& mesh)
:GLC_Geometry(mesh)
, m_NextPrimitiveLocalId(mesh.m_NextPrimitiveLocalId)
, m_PrimitiveGroups(mesh.m_PrimitiveGroups)
, m_DefaultMaterialId(mesh.m_DefaultMaterialId)
, m_NumberOfVertice(mesh.m_NumberOfVertice)
, m_NumberOfNormals(mesh.m_NumberOfNormals)
, m_ColorPearVertex(mesh.m_ColorPearVertex)
, m_MeshData(mesh.m_MeshData)
, m_CurrentLod(0)
{
// Make a copy of m_PrimitiveGroups with new material id
PrimitiveGroupsHash::const_iterator iPrimitiveGroups= mesh.m_PrimitiveGroups.constBegin();
while (mesh.m_PrimitiveGroups.constEnd() != iPrimitiveGroups)
{
LodPrimitiveGroups* pPrimitiveGroups= new LodPrimitiveGroups();
m_PrimitiveGroups.insert(iPrimitiveGroups.key(), pPrimitiveGroups);
LodPrimitiveGroups::const_iterator iPrimitiveGroup= iPrimitiveGroups.value()->constBegin();
while (iPrimitiveGroups.value()->constEnd() != iPrimitiveGroup)
{
GLC_PrimitiveGroup* pPrimitiveGroup= new GLC_PrimitiveGroup(*(iPrimitiveGroup.value()), iPrimitiveGroup.key());
pPrimitiveGroups->insert(iPrimitiveGroup.key(), pPrimitiveGroup);
++iPrimitiveGroup;
}
++iPrimitiveGroups;
}
}
// Overload "=" operator
GLC_Mesh& GLC_Mesh::operator=(const GLC_Mesh& mesh)
{
if (this != &mesh)
{
// Call the operator of the super class
GLC_Geometry::operator=(mesh);
// Clear the mesh
clearMeshWireAndBoundingBox();
// Copy members
m_NextPrimitiveLocalId= mesh.m_NextPrimitiveLocalId;
m_PrimitiveGroups= mesh.m_PrimitiveGroups;
m_DefaultMaterialId= mesh.m_DefaultMaterialId;
m_NumberOfVertice= mesh.m_NumberOfVertice;
m_NumberOfNormals= mesh.m_NumberOfNormals;
m_ColorPearVertex= mesh.m_ColorPearVertex;
m_MeshData= mesh.m_MeshData;
m_CurrentLod= 0;
// Make a copy of m_PrimitiveGroups with new material id
PrimitiveGroupsHash::const_iterator iPrimitiveGroups= mesh.m_PrimitiveGroups.constBegin();
while (mesh.m_PrimitiveGroups.constEnd() != iPrimitiveGroups)
{
LodPrimitiveGroups* pPrimitiveGroups= new LodPrimitiveGroups();
m_PrimitiveGroups.insert(iPrimitiveGroups.key(), pPrimitiveGroups);
LodPrimitiveGroups::const_iterator iPrimitiveGroup= iPrimitiveGroups.value()->constBegin();
while (iPrimitiveGroups.value()->constEnd() != iPrimitiveGroup)
{
GLC_PrimitiveGroup* pPrimitiveGroup= new GLC_PrimitiveGroup(*(iPrimitiveGroup.value()), iPrimitiveGroup.key());
pPrimitiveGroups->insert(iPrimitiveGroup.key(), pPrimitiveGroup);
++iPrimitiveGroup;
}
++iPrimitiveGroups;
}
}
return *this;
}
// Destructor
GLC_Mesh::~GLC_Mesh()
{
PrimitiveGroupsHash::iterator iGroups= m_PrimitiveGroups.begin();
while (iGroups != m_PrimitiveGroups.constEnd())
{
LodPrimitiveGroups::iterator iGroup= iGroups.value()->begin();
while (iGroup != iGroups.value()->constEnd())
{
delete iGroup.value();
++iGroup;
}
delete iGroups.value();
++iGroups;
}
}
//////////////////////////////////////////////////////////////////////
// Get Functions
//////////////////////////////////////////////////////////////////////
// Return the class Chunk ID
quint32 GLC_Mesh::chunckID()
{
return m_ChunkId;
}
// Get number of faces
unsigned int GLC_Mesh::faceCount(int lod) const
{
return m_MeshData.trianglesCount(lod);
}
// Get number of vertex
unsigned int GLC_Mesh::VertexCount() const
{
return m_NumberOfVertice;
}
// return the mesh bounding box
const GLC_BoundingBox& GLC_Mesh::boundingBox()
{
if (NULL == m_pBoundingBox)
{
//qDebug() << "GLC_Mesh2::boundingBox create boundingBox";
m_pBoundingBox= new GLC_BoundingBox();
if (m_MeshData.positionVectorHandle()->isEmpty())
{
qDebug() << "GLC_ExtendedMesh::getBoundingBox empty m_Positions";
}
else
{
GLfloatVector* pVertexVector= m_MeshData.positionVectorHandle();
const int max= pVertexVector->size();
for (int i= 0; i < max; i= i + 3)
{
GLC_Vector3d vector((*pVertexVector)[i], (*pVertexVector)[i + 1], (*pVertexVector)[i + 2]);
m_pBoundingBox->combine(vector);
}
}
// Combine with the wiredata bounding box
m_pBoundingBox->combine(m_WireData.boundingBox());
}
return *m_pBoundingBox;
}
// Return a copy of the Mesh as GLC_Geometry pointer
GLC_Geometry* GLC_Mesh::clone() const
{
return new GLC_Mesh(*this);
}
// Return true if the mesh contains triangles
bool GLC_Mesh::containsTriangles(int lod, GLC_uint materialId) const
{
// Check if the lod exist and material exists
Q_ASSERT(m_PrimitiveGroups.contains(lod));
if (!m_PrimitiveGroups.value(lod)->contains(materialId)) return false;
else return m_PrimitiveGroups.value(lod)->value(materialId)->containsTriangles();
}
// Return the specified index
QVector<GLuint> GLC_Mesh::getTrianglesIndex(int lod, GLC_uint materialId) const
{
// Check if the mesh contains triangles
Q_ASSERT(containsTriangles(lod, materialId));
GLC_PrimitiveGroup* pPrimitiveGroup= m_PrimitiveGroups.value(lod)->value(materialId);
int offset= 0;
if (GLC_State::vboUsed())
{
offset= static_cast<int>(reinterpret_cast<GLsizeiptr>(pPrimitiveGroup->trianglesIndexOffset()) / sizeof(GLuint));
}
else
{
offset= pPrimitiveGroup->trianglesIndexOffseti();
}
const int size= pPrimitiveGroup->trianglesIndexSize();
QVector<GLuint> resultIndex(size);
memcpy((void*)resultIndex.data(), &(m_MeshData.indexVector(lod).data())[offset], size * sizeof(GLuint));
return resultIndex;
}
// Return the number of triangles
int GLC_Mesh::numberOfTriangles(int lod, GLC_uint materialId) const
{
// Check if the lod exist and material exists
if (!m_PrimitiveGroups.contains(lod))return 0;
else if (!m_PrimitiveGroups.value(lod)->contains(materialId)) return 0;
else return m_PrimitiveGroups.value(lod)->value(materialId)->trianglesIndexSize();
}
// Return true if the mesh contains trips
bool GLC_Mesh::containsStrips(int lod, GLC_uint materialId) const
{
// Check if the lod exist and material exists
if (!m_PrimitiveGroups.contains(lod))return false;
else if (!m_PrimitiveGroups.value(lod)->contains(materialId)) return false;
else return m_PrimitiveGroups.value(lod)->value(materialId)->containsStrip();
}
// Return the strips index
QList<QVector<GLuint> > GLC_Mesh::getStripsIndex(int lod, GLC_uint materialId) const
{
// Check if the mesh contains trips
Q_ASSERT(containsStrips(lod, materialId));
GLC_PrimitiveGroup* pPrimitiveGroup= m_PrimitiveGroups.value(lod)->value(materialId);
QList<int> offsets;
QList<int> sizes;
int stripsCount;
if (GLC_State::vboUsed())
{
stripsCount= pPrimitiveGroup->stripsOffset().size();
for (int i= 0; i < stripsCount; ++i)
{
offsets.append(static_cast<int>(reinterpret_cast<GLsizeiptr>(pPrimitiveGroup->stripsOffset().at(i)) / sizeof(GLuint)));
sizes.append(static_cast<int>(pPrimitiveGroup->stripsSizes().at(i)));
}
}
else
{
stripsCount= pPrimitiveGroup->stripsOffseti().size();
for (int i= 0; i < stripsCount; ++i)
{
offsets.append(static_cast<int>(pPrimitiveGroup->stripsOffseti().at(i)));
sizes.append(static_cast<int>(pPrimitiveGroup->stripsSizes().at(i)));
}
}
// The result list of vector
QList<QVector<GLuint> > result;
// The copy of the mesh Data LOD index vector
QVector<GLuint> SourceIndex(m_MeshData.indexVector(lod));
for (int i= 0; i < stripsCount; ++i)
{
QVector<GLuint> currentStrip(sizes.at(i));
memcpy((void*)currentStrip.data(), &(SourceIndex.data())[offsets.at(i)], sizes.at(i) * sizeof(GLuint));
result.append(currentStrip);
}
return result;
}
// Return the number of strips
int GLC_Mesh::numberOfStrips(int lod, GLC_uint materialId) const
{
// Check if the lod exist and material exists
if (!m_PrimitiveGroups.contains(lod))return 0;
else if (!m_PrimitiveGroups.value(lod)->contains(materialId)) return 0;
else return m_PrimitiveGroups.value(lod)->value(materialId)->stripsSizes().size();
}
// Return true if the mesh contains fans
bool GLC_Mesh::containsFans(int lod, GLC_uint materialId) const
{
// Check if the lod exist and material exists
if (!m_PrimitiveGroups.contains(lod))return false;
else if (!m_PrimitiveGroups.value(lod)->contains(materialId)) return false;
else return m_PrimitiveGroups.value(lod)->value(materialId)->containsFan();
}
//! Return the number of fans
int GLC_Mesh::numberOfFans(int lod, GLC_uint materialId) const
{
// Check if the lod exist and material exists
if(!m_PrimitiveGroups.contains(lod))return 0;
else if (!m_PrimitiveGroups.value(lod)->contains(materialId)) return 0;
else return m_PrimitiveGroups.value(lod)->value(materialId)->fansSizes().size();
}
// Return the strips index
QList<QVector<GLuint> > GLC_Mesh::getFansIndex(int lod, GLC_uint materialId) const
{
// Check if the mesh contains trips
Q_ASSERT(containsFans(lod, materialId));
GLC_PrimitiveGroup* pPrimitiveGroup= m_PrimitiveGroups.value(lod)->value(materialId);
QList<int> offsets;
QList<int> sizes;
int fansCount;
if (GLC_State::vboUsed())
{
fansCount= pPrimitiveGroup->fansOffset().size();
for (int i= 0; i < fansCount; ++i)
{
offsets.append(static_cast<int>(reinterpret_cast<GLsizeiptr>(pPrimitiveGroup->fansOffset().at(i)) / sizeof(GLuint)));
sizes.append(static_cast<int>(pPrimitiveGroup->fansSizes().at(i)));
}
}
else
{
fansCount= pPrimitiveGroup->fansOffseti().size();
for (int i= 0; i < fansCount; ++i)
{
offsets.append(static_cast<int>(pPrimitiveGroup->fansOffseti().at(i)));
sizes.append(static_cast<int>(pPrimitiveGroup->fansSizes().at(i)));
}
}
// The result list of vector
QList<QVector<GLuint> > result;
// The copy of the mesh Data LOD index vector
QVector<GLuint> SourceIndex(m_MeshData.indexVector(lod));
for (int i= 0; i < fansCount; ++i)
{
QVector<GLuint> currentFan(sizes.at(i));
memcpy((void*)currentFan.data(), &(SourceIndex.data())[offsets.at(i)], sizes.at(i) * sizeof(GLuint));
result.append(currentFan);
}
return result;
}
//////////////////////////////////////////////////////////////////////
// Set Functions
//////////////////////////////////////////////////////////////////////
// Clear the content of the mesh and super class GLC_Geometry
void GLC_Mesh::clear()
{
// Clear the mesh content
clearMeshWireAndBoundingBox();
// Clear the super class GLC_Geometry
GLC_Geometry::clear();
}
// Clear the content off the mesh and makes it empty
void GLC_Mesh::clearMeshWireAndBoundingBox()
{
// Reset primitive local id
m_NextPrimitiveLocalId= 1;
// Remove all primitive groups
PrimitiveGroupsHash::iterator iGroups= m_PrimitiveGroups.begin();
while (iGroups != m_PrimitiveGroups.constEnd())
{
LodPrimitiveGroups::iterator iGroup= iGroups.value()->begin();
while (iGroup != iGroups.value()->constEnd())
{
delete iGroup.value();
++iGroup;
}
delete iGroups.value();
++iGroups;
}
m_PrimitiveGroups.clear();
m_DefaultMaterialId= 0;
m_NumberOfVertice= 0;
m_NumberOfNormals= 0;
m_IsSelected= false;
m_ColorPearVertex= false;
// Clear data of the mesh
m_MeshData.clear();
m_CurrentLod= 0;
GLC_Geometry::clearWireAndBoundingBox();
}
// Add triangles
GLC_uint GLC_Mesh::addTriangles(GLC_Material* pMaterial, const IndexList& indexList, const int lod, double accuracy)
{
GLC_uint groupId= setCurrentMaterial(pMaterial, lod, accuracy);
Q_ASSERT(m_PrimitiveGroups.value(lod)->contains(groupId));
Q_ASSERT(!indexList.isEmpty());
GLC_uint id= 0;
if (0 == lod)
{
id= m_NextPrimitiveLocalId++;
}
m_MeshData.trianglesAdded(lod, indexList.size() / 3);
m_PrimitiveGroups.value(lod)->value(groupId)->addTriangles(indexList, id);
// Invalid the geometry
m_GeometryIsValid = false;
return id;
}
// Add triangles Strip ans return his id
GLC_uint GLC_Mesh::addTrianglesStrip(GLC_Material* pMaterial, const IndexList& indexList, const int lod, double accuracy)
{
GLC_uint groupId= setCurrentMaterial(pMaterial, lod, accuracy);
Q_ASSERT(m_PrimitiveGroups.value(lod)->contains(groupId));
Q_ASSERT(!indexList.isEmpty());
GLC_uint id= 0;
if (0 == lod)
{
id= m_NextPrimitiveLocalId++;
}
m_MeshData.trianglesAdded(lod, indexList.size() - 2);
m_PrimitiveGroups.value(lod)->value(groupId)->addTrianglesStrip(indexList, id);
// Invalid the geometry
m_GeometryIsValid = false;
return id;
}
// Add triangles Fan
GLC_uint GLC_Mesh::addTrianglesFan(GLC_Material* pMaterial, const IndexList& indexList, const int lod, double accuracy)
{
GLC_uint groupId= setCurrentMaterial(pMaterial, lod, accuracy);
Q_ASSERT(m_PrimitiveGroups.value(lod)->contains(groupId));
Q_ASSERT(!indexList.isEmpty());
GLC_uint id= 0;
if (0 == lod)
{
id= m_NextPrimitiveLocalId++;
}
m_MeshData.trianglesAdded(lod, indexList.size() - 2);
m_PrimitiveGroups.value(lod)->value(groupId)->addTrianglesFan(indexList, id);
// Invalid the geometry
m_GeometryIsValid = false;
return id;
}
// Reverse mesh normal
void GLC_Mesh::reverseNormals()
{
GLfloatVector* pNormalVector= m_MeshData.normalVectorHandle();
if (pNormalVector->isEmpty())
{
(*m_MeshData.normalVectorHandle())= m_MeshData.normalVector();
}
const int size= pNormalVector->size();
for (int i= 0; i < size; ++i)
{
(*pNormalVector)[i]= - pNormalVector->at(i);
}
// Invalid the geometry
m_GeometryIsValid = false;
}
// Copy index list in a vector for Vertex Array Use
void GLC_Mesh::finish()
{
boundingBox();
m_MeshData.finishLod();
if (GLC_State::vboUsed())
{
finishVbo();
}
else
{
finishNonVbo();
}
//qDebug() << "Mesh mem size= " << memmorySize();
}
// Set the lod Index
void GLC_Mesh::setCurrentLod(const int value)
{
if (value)
{
const int numberOfLod= m_MeshData.lodCount() - 1;
// Clamp value to number of load
m_CurrentLod= qRound(static_cast<int>((static_cast<double>(value) / 100.0) * numberOfLod));
}
else
{
m_CurrentLod= 0;
}
}
// Replace the Master material
void GLC_Mesh::replaceMasterMaterial(GLC_Material* pMat)
{
if (hasMaterial())
{
GLC_uint oldId= firstMaterial()->id();
replaceMaterial(oldId, pMat);
}
else
{
addMaterial(pMat);
}
}
// Replace the material specified by id with another one
void GLC_Mesh::replaceMaterial(const GLC_uint oldId, GLC_Material* pMat)
{
Q_ASSERT(containsMaterial(oldId));
Q_ASSERT(!containsMaterial(pMat->id()) || (pMat->id() == oldId));
if (pMat->id() != oldId)
{
// Iterate over Level of detail
PrimitiveGroupsHash::const_iterator iGroups= m_PrimitiveGroups.constBegin();
while (m_PrimitiveGroups.constEnd() != iGroups)
{
LodPrimitiveGroups* pPrimitiveGroups= iGroups.value();
// Iterate over material group
LodPrimitiveGroups::iterator iGroup= pPrimitiveGroups->begin();
while (pPrimitiveGroups->constEnd() != iGroup)
{
if (iGroup.key() == oldId)
{
GLC_PrimitiveGroup* pGroup= iGroup.value();
// Erase old group pointer
pPrimitiveGroups->erase(iGroup);
// Change the group ID
pGroup->setId(pMat->id());
// Add the group with new ID
pPrimitiveGroups->insert(pMat->id(), pGroup);
iGroup= pPrimitiveGroups->end();
}
else
{
++iGroup;
}
}
++iGroups;
}
}
if (pMat != m_MaterialHash.value(oldId))
{
// Remove old material
removeMaterial(oldId);
addMaterial(pMat);
}
}
void GLC_Mesh::copyVboToClientSide()
{
m_MeshData.copyVboToClientSide();
GLC_Geometry::copyVboToClientSide();
}
void GLC_Mesh::releaseVboClientSide(bool update)
{
m_MeshData.releaseVboClientSide(update);
GLC_Geometry::releaseVboClientSide(update);
}
// Load the mesh from binary data stream
void GLC_Mesh::loadFromDataStream(QDataStream& stream, const MaterialHash& materialHash, const QHash<GLC_uint, GLC_uint>& materialIdMap)
{
quint32 chunckId;
stream >> chunckId;
Q_ASSERT(chunckId == m_ChunkId);
// The mesh name
QString meshName;
stream >> meshName;
setName(meshName);
// The wire data
stream >> GLC_Geometry::m_WireData;
// The mesh next primitive local id
GLC_uint localId;
stream >> localId;
setNextPrimitiveLocalId(localId);
// Retrieve geom mesh data
stream >> m_MeshData;
// Retrieve primitiveGroupLodList
QList<int> primitiveGroupLodList;
stream >> primitiveGroupLodList;
// Retrieve primitiveGroup list
QList<QList<GLC_PrimitiveGroup> > primitiveListOfGroupList;
stream >> primitiveListOfGroupList;
// Construct mesh primitiveGroupHash
const int lodCount= primitiveGroupLodList.size();
for (int i= 0; i < lodCount; ++i)
{
GLC_Mesh::LodPrimitiveGroups* pCurrentPrimitiveGroup= new GLC_Mesh::LodPrimitiveGroups();
m_PrimitiveGroups.insert(primitiveGroupLodList.at(i), pCurrentPrimitiveGroup);
const int groupCount= primitiveListOfGroupList.at(i).size();
for (int iGroup= 0; iGroup < groupCount; ++iGroup)
{
Q_ASSERT(materialIdMap.contains(primitiveListOfGroupList.at(i).at(iGroup).id()));
const GLC_uint newId= materialIdMap.value(primitiveListOfGroupList.at(i).at(iGroup).id());
// Test if the mesh contains the material
if (!containsMaterial(newId))
{
addMaterial(materialHash.value(newId));
}
GLC_PrimitiveGroup* pGroup= new GLC_PrimitiveGroup(primitiveListOfGroupList.at(i).at(iGroup), newId);
Q_ASSERT(! m_PrimitiveGroups.value(primitiveGroupLodList.at(i))->contains(newId));
m_PrimitiveGroups.value(primitiveGroupLodList.at(i))->insert(newId, pGroup);
}
}
stream >> m_NumberOfVertice;
stream >> m_NumberOfNormals;
finishSerialized();
//qDebug() << "Mesh mem size= " << memmorySize();
}
// Save the mesh to binary data stream
void GLC_Mesh::saveToDataStream(QDataStream& stream) const
{
quint32 chunckId= m_ChunkId;
stream << chunckId;
// The mesh name
stream << name();
// The wire data
stream << m_WireData;
// The mesh next primitive local id
stream << nextPrimitiveLocalId();
// Mesh data serialisation
stream << m_MeshData;
// Primitive groups serialisation
QList<int> primitiveGroupLodList;
QList<QList<GLC_PrimitiveGroup> > primitiveListOfGroupList;
GLC_Mesh::PrimitiveGroupsHash::const_iterator iGroupsHash= m_PrimitiveGroups.constBegin();
while (m_PrimitiveGroups.constEnd() != iGroupsHash)
{
primitiveGroupLodList.append(iGroupsHash.key());
QList<GLC_PrimitiveGroup> primitiveGroupList;
GLC_Mesh::LodPrimitiveGroups::const_iterator iGroups= iGroupsHash.value()->constBegin();
while (iGroupsHash.value()->constEnd() != iGroups)
{
primitiveGroupList.append(*(iGroups.value()));
++iGroups;
}
primitiveListOfGroupList.append(primitiveGroupList);
++iGroupsHash;
}
stream << primitiveGroupLodList;
stream << primitiveListOfGroupList;
stream << m_NumberOfVertice;
stream << m_NumberOfNormals;
}
//////////////////////////////////////////////////////////////////////
// OpenGL Functions
//////////////////////////////////////////////////////////////////////
// Virtual interface for OpenGL Geometry set up.
void GLC_Mesh::glDraw(const GLC_RenderProperties& renderProperties)
{
Q_ASSERT(m_GeometryIsValid || !m_MeshData.normalVectorHandle()->isEmpty());
const bool vboIsUsed= GLC_State::vboUsed();
if (m_IsSelected && (renderProperties.renderingMode() == glc::PrimitiveSelected) && !GLC_State::isInSelectionMode()
&& !renderProperties.setOfSelectedPrimitiveIdIsEmpty())
{
m_CurrentLod= 0;
}
if (vboIsUsed)
{
m_MeshData.createVBOs();
// Create VBO and IBO
if (!m_GeometryIsValid && !m_MeshData.positionVectorHandle()->isEmpty())
{
fillVbosAndIbos();
}
else if (!m_GeometryIsValid && !m_MeshData.normalVectorHandle()->isEmpty())
{
// Normals has been inversed update normal vbo
m_MeshData.useVBO(true, GLC_MeshData::GLC_Normal);
GLfloatVector* pNormalVector= m_MeshData.normalVectorHandle();
const GLsizei dataNbr= static_cast<GLsizei>(pNormalVector->size());
const GLsizeiptr dataSize= dataNbr * sizeof(GLfloat);
glBufferData(GL_ARRAY_BUFFER, dataSize, pNormalVector->data(), GL_STATIC_DRAW);
m_MeshData.normalVectorHandle()->clear();
}
// Activate mesh VBOs and IBO of the current LOD
activateVboAndIbo();
}
else
{
activateVertexArray();
}
if (GLC_State::isInSelectionMode())
{
if (renderProperties.renderingMode() == glc::PrimitiveSelection)
{
primitiveSelectionRenderLoop(vboIsUsed);
}
else if (renderProperties.renderingMode() == glc::BodySelection)
{
bodySelectionRenderLoop(vboIsUsed);
}
else
{
normalRenderLoop(renderProperties, vboIsUsed);
}
}
else if (m_IsSelected)
{
if (renderProperties.renderingMode() == glc::PrimitiveSelected)
{
if (!renderProperties.setOfSelectedPrimitiveIdIsEmpty())
{
primitiveSelectedRenderLoop(renderProperties, vboIsUsed);
}
else
{
m_IsSelected= false;
if ((m_CurrentLod == 0) && (renderProperties.savedRenderingMode() == glc::OverwritePrimitiveMaterial) && !renderProperties.hashOfOverwritePrimitiveMaterialsIsEmpty())
primitiveRenderLoop(renderProperties, vboIsUsed);
else
normalRenderLoop(renderProperties, vboIsUsed);
m_IsSelected= true;
}
}
else
{
normalRenderLoop(renderProperties, vboIsUsed);
}
}
else
{
// Choose the accurate render loop
switch (renderProperties.renderingMode())
{
case glc::NormalRenderMode:
normalRenderLoop(renderProperties, vboIsUsed);
break;
case glc::OverwriteMaterial:
OverwriteMaterialRenderLoop(renderProperties, vboIsUsed);
break;
case glc::OverwriteTransparency:
OverwriteTransparencyRenderLoop(renderProperties, vboIsUsed);
break;
case glc::OverwritePrimitiveMaterial:
if ((m_CurrentLod == 0) && !renderProperties.hashOfOverwritePrimitiveMaterialsIsEmpty())
primitiveRenderLoop(renderProperties, vboIsUsed);
else
normalRenderLoop(renderProperties, vboIsUsed);
break;
default:
Q_ASSERT(false);
break;
}
}
// Restore client state
if (vboIsUsed)
{
m_MeshData.useIBO(false);
m_MeshData.useVBO(false, GLC_MeshData::GLC_Normal);
}
if (m_ColorPearVertex && !m_IsSelected && !GLC_State::isInSelectionMode())
{
glDisableClientState(GL_COLOR_ARRAY);
glDisable(GL_COLOR_MATERIAL);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// Draw mesh's wire if necessary
if ((renderProperties.renderingFlag() == glc::WireRenderFlag) && !m_WireData.isEmpty() && !GLC_Geometry::typeIsWire())
{
if (!GLC_State::isInSelectionMode())
{
glDisable(GL_LIGHTING);
// Set polyline colors
GLfloat color[4]= {static_cast<float>(m_WireColor.redF()),
static_cast<float>(m_WireColor.greenF()),
static_cast<float>(m_WireColor.blueF()),
static_cast<float>(m_WireColor.alphaF())};
glColor4fv(color);
m_WireData.glDraw(renderProperties);
glEnable(GL_LIGHTING);
}
else
{
m_WireData.glDraw(renderProperties);
}
}
// Update statistics
GLC_RenderStatistics::addBodies(1);
GLC_RenderStatistics::addTriangles(m_MeshData.trianglesCount(m_CurrentLod));
}
//////////////////////////////////////////////////////////////////////
// Private services Functions
//////////////////////////////////////////////////////////////////////
// Set the current material
GLC_uint GLC_Mesh::setCurrentMaterial(GLC_Material* pMaterial, int lod, double accuracy)
{
// Test if a primitive group hash exists for the specified lod
if (!m_PrimitiveGroups.contains(lod))
{
m_PrimitiveGroups.insert(lod, new LodPrimitiveGroups());
m_MeshData.appendLod(accuracy);
}
GLC_uint returnId;
if (NULL == pMaterial)
{
returnId= m_DefaultMaterialId; // Default material id
// Test if the material has been already load
if (m_DefaultMaterialId == 0)
{
pMaterial= new GLC_Material();
// Add the material to the mesh
addMaterial(pMaterial);
m_DefaultMaterialId= pMaterial->id();
returnId= m_DefaultMaterialId;
}
// Test if a primitive group for this material exist
if (!m_PrimitiveGroups.value(lod)->contains(returnId))
{
m_PrimitiveGroups.value(lod)->insert(returnId, new GLC_PrimitiveGroup(returnId));
}
}
else
{
returnId= pMaterial->id();
// Test if the material has been already load
if (!containsMaterial(returnId))
{
// Add the material to the mesh
addMaterial(pMaterial);
m_PrimitiveGroups.value(lod)->insert(returnId, new GLC_PrimitiveGroup(returnId));
}
else if (!m_PrimitiveGroups.value(lod)->contains(returnId))
{
// Add the material to the group
m_PrimitiveGroups.value(lod)->insert(returnId, new GLC_PrimitiveGroup(returnId));
}
}
return returnId;
}
// Fill VBOs and IBOs
void GLC_Mesh::fillVbosAndIbos()
{
// Create VBO of vertices
m_MeshData.fillVbo(GLC_MeshData::GLC_Vertex);
// Create VBO of normals
m_MeshData.fillVbo(GLC_MeshData::GLC_Normal);
// Create VBO of texel if needed
m_MeshData.fillVbo(GLC_MeshData::GLC_Texel);
// Create VBO of color if needed
m_MeshData.fillVbo(GLC_MeshData::GLC_Color);
const int lodNumber= m_MeshData.lodCount();
for (int i= 0; i < lodNumber; ++i)
{
//Create LOD IBO
if (!m_MeshData.indexVectorHandle(i)->isEmpty())
{
QVector<GLuint>* pIndexVector= m_MeshData.indexVectorHandle(i);
m_MeshData.useIBO(true, i);
const GLsizei indexNbr= static_cast<GLsizei>(pIndexVector->size());
const GLsizeiptr indexSize = indexNbr * sizeof(GLuint);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexSize, pIndexVector->data(), GL_STATIC_DRAW);
}
}
// Remove client side data
m_MeshData.finishVbo();
}
// set primitive group offset
void GLC_Mesh::finishSerialized()
{
if (GLC_State::vboUsed())
{
PrimitiveGroupsHash::iterator iGroups= m_PrimitiveGroups.begin();
while (iGroups != m_PrimitiveGroups.constEnd())
{
LodPrimitiveGroups::iterator iGroup= iGroups.value()->begin();
while (iGroup != iGroups.value()->constEnd())
{
iGroup.value()->changeToVboMode();
++iGroup;
}
++iGroups;
}
}
}
// Move Indexs from the primitive groups to the mesh Data LOD and Set IBOs offsets
void GLC_Mesh::finishVbo()
{
PrimitiveGroupsHash::iterator iGroups= m_PrimitiveGroups.begin();
while (iGroups != m_PrimitiveGroups.constEnd())
{
int currentLod= iGroups.key();
LodPrimitiveGroups::iterator iGroup= iGroups.value()->begin();
while (iGroup != iGroups.value()->constEnd())
{
// Add group triangles index to mesh Data LOD triangles index vector
if (iGroup.value()->containsTriangles())
{
iGroup.value()->setTrianglesOffset(BUFFER_OFFSET(m_MeshData.indexVectorSize(currentLod) * sizeof(GLuint)));
(*m_MeshData.indexVectorHandle(currentLod))+= iGroup.value()->trianglesIndex().toVector();
}
// Add group strip index to mesh Data LOD strip index vector
if (iGroup.value()->containsStrip())
{
iGroup.value()->setBaseTrianglesStripOffset(BUFFER_OFFSET(m_MeshData.indexVectorSize(currentLod) * sizeof(GLuint)));
(*m_MeshData.indexVectorHandle(currentLod))+= iGroup.value()->stripsIndex().toVector();
}
// Add group fan index to mesh Data LOD fan index vector
if (iGroup.value()->containsFan())
{
iGroup.value()->setBaseTrianglesFanOffset(BUFFER_OFFSET(m_MeshData.indexVectorSize(currentLod) * sizeof(GLuint)));
(*m_MeshData.indexVectorHandle(currentLod))+= iGroup.value()->fansIndex().toVector();
}
iGroup.value()->finish();
++iGroup;
}
++iGroups;
}
}
// Move Indexs from the primitive groups to the mesh Data LOD and Set Index offsets
void GLC_Mesh::finishNonVbo()
{
//qDebug() << "GLC_Mesh::finishNonVbo()";
PrimitiveGroupsHash::iterator iGroups= m_PrimitiveGroups.begin();
while (iGroups != m_PrimitiveGroups.constEnd())
{
int currentLod= iGroups.key();
LodPrimitiveGroups::iterator iGroup= iGroups.value()->begin();
while (iGroup != iGroups.value()->constEnd())
{
// Add group triangles index to mesh Data LOD triangles index vector
if (iGroup.value()->containsTriangles())
{
iGroup.value()->setTrianglesOffseti(m_MeshData.indexVectorSize(currentLod));
(*m_MeshData.indexVectorHandle(currentLod))+= iGroup.value()->trianglesIndex().toVector();
}
// Add group strip index to mesh Data LOD strip index vector
if (iGroup.value()->containsStrip())
{
iGroup.value()->setBaseTrianglesStripOffseti(m_MeshData.indexVectorSize(currentLod));
(*m_MeshData.indexVectorHandle(currentLod))+= iGroup.value()->stripsIndex().toVector();
}
// Add group fan index to mesh Data LOD fan index vector
if (iGroup.value()->containsFan())
{
iGroup.value()->setBaseTrianglesFanOffseti(m_MeshData.indexVectorSize(currentLod));
(*m_MeshData.indexVectorHandle(currentLod))+= iGroup.value()->fansIndex().toVector();
}
iGroup.value()->finish();
++iGroup;
}
++iGroups;
}
}
// The normal display loop
void GLC_Mesh::normalRenderLoop(const GLC_RenderProperties& renderProperties, bool vboIsUsed)
{
const bool isTransparent= (renderProperties.renderingFlag() == glc::TransparentRenderFlag);
if ((!m_IsSelected || !isTransparent) || GLC_State::isInSelectionMode())
{
LodPrimitiveGroups::iterator iGroup= m_PrimitiveGroups.value(m_CurrentLod)->begin();
while (iGroup != m_PrimitiveGroups.value(m_CurrentLod)->constEnd())
{
GLC_PrimitiveGroup* pCurrentGroup= iGroup.value();
GLC_Material* pCurrentMaterial= m_MaterialHash.value(pCurrentGroup->id());
// Test if the current material is renderable
bool materialIsrenderable = (pCurrentMaterial->isTransparent() == isTransparent);
// Choose the material to render
if ((materialIsrenderable || m_IsSelected) && !GLC_State::isInSelectionMode())
{
// Execute current material
pCurrentMaterial->glExecute();
if (m_IsSelected) GLC_SelectionMaterial::glExecute();
}
// Choose the primitives to render
if (m_IsSelected || GLC_State::isInSelectionMode() || materialIsrenderable)
{
if (vboIsUsed)
vboDrawPrimitivesOf(pCurrentGroup);
else
vertexArrayDrawPrimitivesOf(pCurrentGroup);
}
++iGroup;
}
}
}
// The overwrite material render loop
void GLC_Mesh::OverwriteMaterialRenderLoop(const GLC_RenderProperties& renderProperties, bool vboIsUsed)
{
// Get the overwrite material
GLC_Material* pOverwriteMaterial= renderProperties.overwriteMaterial();
Q_ASSERT(NULL != pOverwriteMaterial);
pOverwriteMaterial->glExecute();
if (m_IsSelected) GLC_SelectionMaterial::glExecute();
LodPrimitiveGroups::iterator iGroup= m_PrimitiveGroups.value(m_CurrentLod)->begin();
while (iGroup != m_PrimitiveGroups.value(m_CurrentLod)->constEnd())
{
GLC_PrimitiveGroup* pCurrentGroup= iGroup.value();
// Test if the current material is renderable
bool materialIsrenderable = (pOverwriteMaterial->isTransparent() == (renderProperties.renderingFlag() == glc::TransparentRenderFlag));
// Choose the primitives to render
if (m_IsSelected || materialIsrenderable)
{
if (vboIsUsed)
vboDrawPrimitivesOf(pCurrentGroup);
else
vertexArrayDrawPrimitivesOf(pCurrentGroup);
}
++iGroup;
}
}
// The overwrite transparency render loop
void GLC_Mesh::OverwriteTransparencyRenderLoop(const GLC_RenderProperties& renderProperties, bool vboIsUsed)
{
// Get transparency value
const float alpha= renderProperties.overwriteTransparency();
Q_ASSERT(-1.0f != alpha);
// Test if the current material is renderable
bool materialIsrenderable = (renderProperties.renderingFlag() == glc::TransparentRenderFlag);
if (materialIsrenderable || m_IsSelected)
{
LodPrimitiveGroups::iterator iGroup= m_PrimitiveGroups.value(m_CurrentLod)->begin();
while (iGroup != m_PrimitiveGroups.value(m_CurrentLod)->constEnd())
{
GLC_PrimitiveGroup* pCurrentGroup= iGroup.value();
GLC_Material* pCurrentMaterial= m_MaterialHash.value(pCurrentGroup->id());
// Execute current material
pCurrentMaterial->glExecute(alpha);
if (m_IsSelected) GLC_SelectionMaterial::glExecute();
// Choose the primitives to render
if (m_IsSelected || materialIsrenderable)
{
if (vboIsUsed)
vboDrawPrimitivesOf(pCurrentGroup);
else
vertexArrayDrawPrimitivesOf(pCurrentGroup);
}
++iGroup;
}
}
}
// The body selection render loop
void GLC_Mesh::bodySelectionRenderLoop(bool vboIsUsed)
{
Q_ASSERT(GLC_State::isInSelectionMode());
LodPrimitiveGroups::iterator iGroup= m_PrimitiveGroups.value(m_CurrentLod)->begin();
while (iGroup != m_PrimitiveGroups.value(m_CurrentLod)->constEnd())
{
GLC_PrimitiveGroup* pCurrentGroup= iGroup.value();
if (vboIsUsed)
vboDrawPrimitivesOf(pCurrentGroup);
else
vertexArrayDrawPrimitivesOf(pCurrentGroup);
++iGroup;
}
}
// The primitive selection render loop
void GLC_Mesh::primitiveSelectionRenderLoop(bool vboIsUsed)
{
Q_ASSERT(GLC_State::isInSelectionMode());
LodPrimitiveGroups::iterator iGroup= m_PrimitiveGroups.value(m_CurrentLod)->begin();
while (iGroup != m_PrimitiveGroups.value(m_CurrentLod)->constEnd())
{
GLC_PrimitiveGroup* pCurrentGroup= iGroup.value();
if (vboIsUsed)
vboDrawInSelectionModePrimitivesOf(pCurrentGroup);
else
vertexArrayDrawInSelectionModePrimitivesOf(pCurrentGroup);
++iGroup;
}
}
// The primitive rendeder loop
void GLC_Mesh::primitiveRenderLoop(const GLC_RenderProperties& renderProperties, bool vboIsUsed)
{
const bool isTransparent= (renderProperties.renderingFlag() == glc::TransparentRenderFlag);
LodPrimitiveGroups::iterator iGroup= m_PrimitiveGroups.value(m_CurrentLod)->begin();
while (iGroup != m_PrimitiveGroups.value(m_CurrentLod)->constEnd())
{
GLC_PrimitiveGroup* pCurrentGroup= iGroup.value();
GLC_Material* pCurrentMaterial= m_MaterialHash.value(pCurrentGroup->id());
// Test if the current material is renderable
const bool materialIsrenderable = (pCurrentMaterial->isTransparent() == isTransparent);
if (materialIsrenderable)
{
pCurrentMaterial->glExecute();
}
if (vboIsUsed)
vboDrawPrimitivesGroupOf(pCurrentGroup, pCurrentMaterial, materialIsrenderable, isTransparent, renderProperties.hashOfOverwritePrimitiveMaterials());
else
vertexArrayDrawPrimitivesGroupOf(pCurrentGroup, pCurrentMaterial, materialIsrenderable, isTransparent, renderProperties.hashOfOverwritePrimitiveMaterials());
++iGroup;
}
}
// The primitive Selected render loop
void GLC_Mesh::primitiveSelectedRenderLoop(const GLC_RenderProperties& renderProperties, bool vboIsUsed)
{
const bool isTransparent= (renderProperties.renderingFlag() == glc::TransparentRenderFlag);
LodPrimitiveGroups::iterator iGroup= m_PrimitiveGroups.value(m_CurrentLod)->begin();
while (iGroup != m_PrimitiveGroups.value(m_CurrentLod)->constEnd())
{
GLC_PrimitiveGroup* pCurrentGroup= iGroup.value();
GLC_Material* pCurrentMaterial= m_MaterialHash.value(pCurrentGroup->id());
// Test if the current material is renderable
const bool materialIsrenderable = (pCurrentMaterial->isTransparent() == isTransparent);
if (materialIsrenderable)
{
pCurrentMaterial->glExecute();
}
if (vboIsUsed)
vboDrawSelectedPrimitivesGroupOf(pCurrentGroup, pCurrentMaterial, materialIsrenderable, isTransparent, renderProperties);
else
vertexArrayDrawSelectedPrimitivesGroupOf(pCurrentGroup, pCurrentMaterial, materialIsrenderable, isTransparent, renderProperties);
++iGroup;
}
}