#include "BBCEntity.h" namespace BBC { Entity::Entity(): references(0) // initialize references to 0 { createSubEntity(); } Entity::~Entity() { } void Entity::createSubEntity() { SubEntityPtr subEntityPtr((SubEntity*)new SubEntity()); mSubEntityList.push_back(subEntityPtr); } void Entity::addSubEntity(SubEntityPtr value) { mSubEntityList.push_back(value); } SubEntityPtr Entity::getSubEntity(unsigned int index) { return mSubEntityList[index]; } void Entity::removeSubEntity(unsigned int index) { mSubEntityList.erase(mSubEntityList.begin()+index); } void Entity::setSubEntitiesDistinctVertexColours() { for (unsigned int iSubEntity = 0; iSubEntity < mSubEntityList.size(); iSubEntity++) { mSubEntityList[iSubEntity]->enableVertexColors(true); float fRed = Ogre::Math::RangeRandom(0.0,1.0); float fGreen = Ogre::Math::RangeRandom(0.0,1.0); float fBlue = Ogre::Math::RangeRandom(0.0,1.0); Ogre::ColourValue subEntityColour = Ogre::ColourValue(1.0,fRed,fGreen,fBlue); for (unsigned int iVertex = 0; iVertex < mSubEntityList[iSubEntity]->getNumVertices(); iVertex++) { mSubEntityList[iSubEntity]->setVertexColor(iVertex, subEntityColour.getAsRGBA()); } } } MeshPtr Entity::getMesh() { return mMesh; } void Entity::setMesh(MeshPtr value) { mMesh = value; } unsigned int Entity::getEntityHandle() { return mEntityHandle; } void Entity::setEntityHandle(unsigned int value) { mEntityHandle = value; } void Entity::loadMesh(bool mergeSubMeshes = false) { Ogre::Vector3 position = Ogre::Vector3::ZERO; Ogre::Quaternion orient = Ogre::Quaternion(1.0,1.0,1.0,1.0); Ogre::Vector3 scale = Ogre::Vector3::ZERO; unsigned int coordset = 0; unsigned short dimTexCoord = 2; getMeshPositions(position,orient,scale,mergeSubMeshes); getMeshNormals(orient,scale,mergeSubMeshes); getMeshVertexColours(mergeSubMeshes); getMeshTexCoords(mergeSubMeshes); //getMeshFacesVerticesID(mergeSubMeshes); } void Entity::sincronizeNumSubEntities() { if (this->getNumSubEntities() < mMesh->get()->getNumSubMeshes()) { while (this->getNumSubEntities() < mMesh->get()->getNumSubMeshes()) { this->createSubEntity(); } } if (this->getNumSubEntities() > mMesh->get()->getNumSubMeshes()) { while (this->getNumSubEntities() > mMesh->get()->getNumSubMeshes()) { this->removeSubEntity(this->getNumSubEntities()-1); } } } void Entity::getMeshPositions(Ogre::Vector3 position, Ogre::Quaternion orient, Ogre::Vector3 scale, bool mergeSubMeshes) { bool added_shared = false; size_t current_offset = 0; size_t shared_offset = 0; size_t next_offset = 0; size_t index_offset = 0; size_t vertex_count, index_count; vertex_count = index_count = 0; unsigned int numSubMeshes = mMesh->get()->getNumSubMeshes(); sincronizeNumSubEntities(); // Calculate how many vertices and indices we're going to need for(int i = 0; i < mMesh->get()->getNumSubMeshes(); i++) { Ogre::SubMesh* submesh = mMesh->get()->getSubMesh(i); // We only need to add the shared vertices once if(submesh->useSharedVertices) { if(!added_shared) { Ogre::VertexData* vertex_data = mMesh->get()->sharedVertexData; vertex_count += vertex_data->vertexCount; added_shared = true; } } else { Ogre::VertexData* vertex_data = submesh->vertexData; vertex_count += vertex_data->vertexCount; } // Add the indices Ogre::IndexData* index_data = submesh->indexData; index_count += index_data->indexCount; } unsigned int* indices = NULL; if (mergeSubMeshes) { indices = new unsigned[index_count]; } added_shared = false; for (unsigned short i = 0; i < mMesh->get()->getNumSubMeshes(); i++) { Ogre::SubMesh* subMesh = mMesh->get()->getSubMesh(i); Ogre::VertexData* vertexData = subMesh->useSharedVertices ? mMesh->get()->sharedVertexData : subMesh->vertexData; if (!mergeSubMeshes) { // Add the indices Ogre::IndexData* index_data = subMesh->indexData; index_count = index_data->indexCount; if (indices != NULL) { delete [] indices; } indices = new unsigned[index_count]; } if ((!subMesh->useSharedVertices) || (subMesh->useSharedVertices && !added_shared)) { if (subMesh->useSharedVertices) { added_shared = true; shared_offset = current_offset; } const Ogre::VertexElement* positionElem = vertexData->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); Ogre::HardwareVertexBufferSharedPtr vbuf = vertexData->vertexBufferBinding->getBuffer(positionElem->getSource()); unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); float* pReal; for(size_t j = 0; j < vertexData->vertexCount; ++j, vertex += vbuf->getVertexSize()) { positionElem->baseVertexPointerToElement(vertex, &pReal); Ogre::Vector3 position(pReal[0], pReal[1], pReal[2]); if (!mergeSubMeshes) { UniqueVertex uniqueVertex; uniqueVertex.position = position; this->getSubEntity(i)->addUniqueVertex(uniqueVertex); } else { UniqueVertex uniqueVertex; uniqueVertex.position = position; this->getSubEntity(0)->addUniqueVertex(uniqueVertex); } } vbuf->unlock(); next_offset += vertexData->vertexCount; Ogre::IndexData* index_data = subMesh->indexData; size_t numTris = index_data->indexCount / 3; unsigned short* pShort; unsigned int* pInt; Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer; bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT); if (use32bitindexes) pInt = static_cast(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); else pShort = static_cast(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); index_offset = 0; for(size_t k = 0; k < numTris; ++k) { size_t offset; if (!mergeSubMeshes) { offset = (subMesh->useSharedVertices)?shared_offset:0; } else { offset = (subMesh->useSharedVertices)?shared_offset:current_offset; } unsigned int vindex = use32bitindexes? *pInt++ : *pShort++; indices[index_offset + 0] = vindex + offset; vindex = use32bitindexes? *pInt++ : *pShort++; indices[index_offset + 1] = vindex + offset; vindex = use32bitindexes? *pInt++ : *pShort++; indices[index_offset + 2] = vindex + offset; index_offset += 3; } for(size_t k = 0; k < index_count; k = k + 3) { if (!mergeSubMeshes) { this->getSubEntity(i)->addFaceVerticesIDs(Ogre::Vector3(indices[k], indices[k+1], indices[k+2])); } else { this->getSubEntity(0)->addFaceVerticesIDs(Ogre::Vector3(indices[k], indices[k+1], indices[k+2])); } } ibuf->unlock(); current_offset = next_offset; } } delete [] indices; } void Entity::getMeshNormals(Ogre::Quaternion orient, Ogre::Vector3 scale, bool mergeSubMeshes) { bool added_shared = false; size_t current_offset = 0; size_t shared_offset = 0; size_t next_offset = 0; unsigned int numSubMeshes = mMesh->get()->getNumSubMeshes(); sincronizeNumSubEntities(); added_shared = false; for (unsigned short i = 0; i < mMesh->get()->getNumSubMeshes(); i++) { Ogre::SubMesh* subMesh = mMesh->get()->getSubMesh(i); Ogre::VertexData* vertexData = subMesh->useSharedVertices ? mMesh->get()->sharedVertexData : subMesh->vertexData; if ((!subMesh->useSharedVertices) || (subMesh->useSharedVertices && !added_shared)) { if (subMesh->useSharedVertices) { added_shared = true; shared_offset = current_offset; } const Ogre::VertexElement* normalElem = vertexData->vertexDeclaration->findElementBySemantic(Ogre::VES_NORMAL); Ogre::HardwareVertexBufferSharedPtr vbuf = vertexData->vertexBufferBinding->getBuffer(normalElem->getSource()); unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); float* pReal; for(size_t j = 0; j < vertexData->vertexCount; ++j, vertex += vbuf->getVertexSize()) { normalElem->baseVertexPointerToElement(vertex, &pReal); Ogre::Vector3 normal(pReal[0], pReal[1], pReal[2]); if (!mergeSubMeshes) { this->getSubEntity(i)->setNormal(j,normal); } else { this->getSubEntity(0)->setNormal(j,normal); } } vbuf->unlock(); next_offset += vertexData->vertexCount; } } current_offset = next_offset; } void Entity::getMeshVertexColours(bool mergeSubMeshes) { bool added_shared = false; size_t current_offset = 0; size_t shared_offset = 0; size_t next_offset = 0; unsigned int numSubMeshes = mMesh->get()->getNumSubMeshes(); sincronizeNumSubEntities(); added_shared = false; for (unsigned short i = 0; i < mMesh->get()->getNumSubMeshes(); i++) { Ogre::SubMesh* subMesh = mMesh->get()->getSubMesh(i); Ogre::VertexData* vertexData = subMesh->useSharedVertices ? mMesh->get()->sharedVertexData : subMesh->vertexData; if ((!subMesh->useSharedVertices) || (subMesh->useSharedVertices && !added_shared)) { if (subMesh->useSharedVertices) { added_shared = true; shared_offset = current_offset; } const Ogre::VertexElement* colourElem = vertexData->vertexDeclaration->findElementBySemantic(Ogre::VES_DIFFUSE); if (colourElem) { //Ogre::LogManager::getSingleton().logMessage("Has vertex colours!"); Ogre::HardwareVertexBufferSharedPtr vbuf = vertexData->vertexBufferBinding->getBuffer(colourElem->getSource()); unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); Ogre::ARGB *pSrcARGB; for(size_t j = 0; j < vertexData->vertexCount; ++j, vertex += vbuf->getVertexSize()) { if (colourElem) { colourElem->baseVertexPointerToElement(vertex, &pSrcARGB); Ogre::ColourValue colour; Ogre::ARGB rc = *pSrcARGB++; colour.b = (rc & 0xFF) / 255.0f; rc >>= 8; colour.g = (rc & 0xFF) / 255.0f; rc >>= 8; colour.r = (rc & 0xFF) / 255.0f; rc >>= 8; colour.a = (rc & 0xFF) / 255.0f; //colour.setAsARGB(pSrcARGB[0]); if (!mergeSubMeshes) { this->getSubEntity(i)->setVertexColor(j,colour.getAsARGB()); } else { this->getSubEntity(0)->setVertexColor(j,colour.getAsARGB()); } } } vbuf->unlock(); next_offset += vertexData->vertexCount; if (!mergeSubMeshes) { this->getSubEntity(i)->enableVertexColors(true); } else { this->getSubEntity(0)->enableVertexColors(true); } } } } current_offset = next_offset; } void Entity::getMeshTexCoords(bool mergeSubMeshes) { bool added_shared = false; size_t current_offset = 0; size_t shared_offset = 0; size_t next_offset = 0; unsigned int numSubMeshes = mMesh->get()->getNumSubMeshes(); sincronizeNumSubEntities(); added_shared = false; for (unsigned short i = 0; i < mMesh->get()->getNumSubMeshes(); i++) { Ogre::SubMesh* subMesh = mMesh->get()->getSubMesh(i); Ogre::VertexData* vertexData = subMesh->useSharedVertices ? mMesh->get()->sharedVertexData : subMesh->vertexData; if ((!subMesh->useSharedVertices) || (subMesh->useSharedVertices && !added_shared)) { if (subMesh->useSharedVertices) { added_shared = true; shared_offset = current_offset; } const Ogre::VertexElement* texcoordElem = NULL; texcoordElem = vertexData->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES); if (texcoordElem != NULL) { Ogre::HardwareVertexBufferSharedPtr vbuf = vertexData->vertexBufferBinding->getBuffer(texcoordElem->getSource()); unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); Ogre::VertexDeclaration* decl = vertexData->vertexDeclaration; Ogre::VertexBufferBinding* bind = vertexData->vertexBufferBinding; Ogre::VertexBufferBinding::VertexBufferBindingMap::const_iterator b, bend; bend = bind->getBindings().end(); // Iterate over buffers for (b = bind->getBindings().begin(); b != bend; ++b) { const Ogre::HardwareVertexBufferSharedPtr vbuf = b->second; unsigned short bufferIdx = b->first; // Get all the elements that relate to this buffer Ogre::VertexDeclaration::VertexElementList elems = decl->findElementsBySource(bufferIdx); Ogre::VertexDeclaration::VertexElementList::iterator it, itend; itend = elems.end(); // Skim over the elements to set up the general data unsigned short numTextureCoords = 0; std::vector baseTexCoordSetIndex; for (it = elems.begin(); it != itend; ++it) { Ogre::VertexElement& elem = *it; if (elem.getSemantic() == Ogre::VES_TEXTURE_COORDINATES) { if (numTextureCoords == 0) { baseTexCoordSetIndex.push_back(0); baseTexCoordSetIndex.push_back(Ogre::VertexElement::getTypeCount(elem.getType())); } ++numTextureCoords; } } elems.clear(); // There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double // as a second argument. So make it float, to avoid trouble when Ogre::Real will be // compiled/typedefed as double: // Ogre::Real* pReal; float* pReal; unsigned int baseTexCoord = 0; unsigned int texCoordSet = 0; unsigned int dimBaseTexCoord = 0; for (unsigned int texCoordSet = 0; texCoordSet < numTextureCoords; texCoordSet++) { for (unsigned int iTexCoordSet = 0; iTexCoordSet <= texCoordSet; iTexCoordSet++) { baseTexCoord = baseTexCoord + baseTexCoordSetIndex[iTexCoordSet]; } unsigned short dimTexCoord = (unsigned short)baseTexCoordSetIndex[texCoordSet+1]; for (size_t j = 0; j < vertexData->vertexCount; j++, vertex += vbuf->getVertexSize()) { texcoordElem->baseVertexPointerToElement(vertex, &pReal); Ogre::Vector3 texcoord; if (baseTexCoordSetIndex[texCoordSet+1] == 2) { texcoord = Ogre::Vector3(pReal[baseTexCoord + 0], pReal[baseTexCoord + 1], 0.0); dimBaseTexCoord = 2; } else if (baseTexCoordSetIndex[texCoordSet + 1] == 3) { texcoord = Ogre::Vector3(pReal[baseTexCoord + 0], pReal[baseTexCoord + 1], pReal[baseTexCoord + 2]); dimBaseTexCoord = 3; } if (!mergeSubMeshes) { this->getSubEntity(i)->setTexCoord(j,texCoordSet,texcoord); } else { this->getSubEntity(0)->setTexCoord(j,texCoordSet,texcoord); } } if (!mergeSubMeshes) { this->getSubEntity(i)->addTextureCoordSet(dimBaseTexCoord); } else { if (i == 0) { this->getSubEntity(0)->addTextureCoordSet(dimBaseTexCoord); } } } } vbuf->unlock(); next_offset += vertexData->vertexCount; } } } current_offset = next_offset; } void Entity::getMeshFacesVerticesID(bool mergeSubMeshes) { bool added_shared = false; size_t current_offset = 0; size_t shared_offset = 0; size_t next_offset = 0; size_t index_offset = 0; unsigned int numSubMeshes = mMesh->get()->getNumSubMeshes(); sincronizeNumSubEntities(); added_shared = false; // Run through the submeshes again, adding the data into the arrays for ( unsigned short i = 0; i < mMesh->get()->getNumSubMeshes(); ++i) { Ogre::SubMesh* submesh = mMesh->get()->getSubMesh(i); Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mMesh->get()->sharedVertexData : submesh->vertexData; if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared)) { if(submesh->useSharedVertices) { added_shared = true; shared_offset = current_offset; } const Ogre::VertexElement* texcoordElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(texcoordElem->getSource()); unsigned char* vertex = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); vbuf->unlock(); next_offset += vertex_data->vertexCount; } Ogre::IndexData* index_data = submesh->indexData; size_t numTris = index_data->indexCount / 3; Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer; bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT); unsigned long* pLong = static_cast(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); unsigned short* pShort = reinterpret_cast(pLong); size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset; if ( use32bitindexes ) { for ( size_t k = 0; k < numTris*3; k=k+3) { if (!mergeSubMeshes) { Ogre::Vector3 indices(k,k+1,k+2); this->getSubEntity(i)->addFaceVerticesIDs(indices); } else { Ogre::Vector3 indices = Ogre::Vector3(pLong[k] + static_cast(offset),pLong[k+1] + static_cast(offset),pLong[k+2] + static_cast(offset)); this->getSubEntity(0)->addFaceVerticesIDs(indices); } index_offset++; } } else { for ( size_t k = 0; k < numTris*3; k=k+3) { if (!mergeSubMeshes) { Ogre::Vector3 indices(k,k+1,k+2); this->getSubEntity(i)->addFaceVerticesIDs(indices); } else { Ogre::Vector3 indices = Ogre::Vector3(static_cast(pShort[k]) + static_cast(offset),static_cast(pShort[k+1]) + static_cast(offset),static_cast(pShort[k+2]) + static_cast(offset)); this->getSubEntity(0)->addFaceVerticesIDs(indices); } index_offset++; } } ibuf->unlock(); current_offset = next_offset; } } unsigned int Entity::getNumSubEntities() { return mSubEntityList.size(); } void Entity::mergeSubEntities() { if (mSubEntityList.size() > 1) { unsigned int currentMaxNumVertices = mSubEntityList[0]->getNumVertices(); unsigned int iIDVertex = currentMaxNumVertices; for (unsigned int iSubEntity = 1; iSubEntity < mSubEntityList.size(); iSubEntity++) { if (mSubEntityList[iSubEntity]->getNumTexCoordSets() == mSubEntityList[0]->getNumTexCoordSets()) { for (unsigned int iVertex = 0; iVertex < mSubEntityList[iSubEntity]->getNumVertices(); iVertex++) { mSubEntityList[0]->addUniqueVertex(mSubEntityList[iSubEntity]->getUniqueVertex(iVertex)); } // Vertices IDs go from [0,NUMVERT-1] -> First new vertex should be NUMVERT... for (unsigned int iFaceVerticesIDs = 0; iFaceVerticesIDs < mSubEntityList[iSubEntity]->getNumFaces(); iFaceVerticesIDs++) { mSubEntityList[0]->addFaceVerticesIDs(Ogre::Vector3(iIDVertex,iIDVertex+1,iIDVertex+2)); iIDVertex = iIDVertex + 3; } } else { Ogre::LogManager::getSingleton().logMessage("Error: The number of texture coord. sets is not the same in all the subentities..."); } } for (unsigned int iSubEntity = 1; iSubEntity < mSubEntityList.size(); iSubEntity) { mSubEntityList.erase(mSubEntityList.begin()+iSubEntity); } } } }