/* * * Copyright (C) 2004, 2005, 2006 Mekensleep * * Mekensleep * 24 rue vieille du temple * 75004 Paris * licensing@mekensleep.com * * 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors: * Cedric PINSON * Loic Dachary * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef USE_NPROFILE #include #else // USE_NPROFILE #define NPROFILE_SAMPLE(a) #endif // USE_NPROFILE #ifdef WIN32 # include #endif // WIN32 #include #include #include #include using namespace osgCal; SubMeshSoftware::SubMeshSoftware() : _supportsPrimitiveFunctor(true), _invisible(false), _coreMeshId(0), _coreSubmeshId(0), _calModel(0) { } SubMeshSoftware::SubMeshSoftware(CalModel* calModel, int coreMeshId, int coreSubmeshId) : _supportsPrimitiveFunctor(true), _invisible(false), _coreMeshId(coreMeshId), _coreSubmeshId(coreSubmeshId), _calModel(calModel) { setSupportsDisplayList(false); } SubMeshSoftware::SubMeshSoftware(const SubMeshSoftware& submesh, const osg::CopyOp& copyop) : osg::Geometry(submesh, copyop), _supportsPrimitiveFunctor(submesh._supportsPrimitiveFunctor), _invisible(submesh._invisible), _coreMeshId(submesh._coreMeshId), _coreSubmeshId(submesh._coreSubmeshId), _calModel(submesh._calModel) { } SubMeshSoftware::~SubMeshSoftware() {} bool SubMeshSoftware::update(void) { #ifdef USE_NPROFILE NPROFILE_SAMPLE("SubMeshSoftware::update"); #endif // get bone vector of the skeleton std::vector& vectorBone = _calModel->getSkeleton()->getVectorBone(); CalCoreMesh* calCoreMesh = _calModel->getCoreModel()->getCoreMesh(_coreMeshId); if(calCoreMesh == NULL) { osg::notify(osg::FATAL) << "SubMeshSoftware::update could not find coreMesh for coreMeshId " << _coreMeshId << " : " << CalError::getLastErrorDescription() << std::endl; return false; } CalCoreSubmesh* calCoreSubmesh = calCoreMesh->getCoreSubmesh(_coreSubmeshId); if(calCoreSubmesh == NULL) { osg::notify(osg::FATAL) << "SubMeshSoftware::update could not find coreSubmesh for coreMeshId " << _coreMeshId << " coreSubmeshId " << _coreSubmeshId << " : " << CalError::getLastErrorDescription() << std::endl; return false; } std::vector& vectorVertex = calCoreSubmesh->getVectorVertex(); // // get vertex buffer pointer float * pVertexBuffer = (float*)(dynamic_cast(getVertexArray())->getDataPointer()); // // get normal buffer pointer float * pNormalBuffer = NULL; if(!_invisible) { pNormalBuffer = (float*)(dynamic_cast(getNormalArray())->getDataPointer()); } /* char *pColorBuffer = NULL; if(!_invisible) { #if OSG_VERSION_MAJOR != 1 pColorBuffer = (char*)(dynamic_cast(getColorArray())->getDataPointer()); #else // OSG_VERSION_MAJOR != 1 pColorBuffer = (char*)(dynamic_cast(getColorArray())->getDataPointer()); #endif // OSG_VERSION_MAJOR != 1 } */ memset(pVertexBuffer, 0, calCoreSubmesh->getVertexCount() * 3 * sizeof(float)); if (NULL != pNormalBuffer) { memset(pNormalBuffer, 0, calCoreSubmesh->getVertexCount() * 3 * sizeof(float)); } // calculate all submesh vertices int nbVertices = calCoreSubmesh->getVertexCount(); for (int vertexId = 0; vertexId < nbVertices; ++vertexId) { // get the vertex CalCoreSubmesh::Vertex& vertex = vectorVertex[vertexId]; // blend together all vertex influences unsigned int nbInfluences = vertex.vectorInfluence.size(); for(unsigned int influenceId = 0; influenceId < nbInfluences; ++influenceId) { // get the influence const CalCoreSubmesh::Influence & influence = vertex.vectorInfluence[influenceId]; // get the bone of the influence vertex CalBone * pBone = vectorBone[influence.boneId]; // transform vertex with current state of the bone const CalMatrix & tm = pBone->getTransformMatrix(); const CalVector & trans = pBone->getTranslationBoneSpace(); const float & vposx = vertex.position.x; const float & vposy = vertex.position.y; const float & vposz = vertex.position.z; pVertexBuffer[0] += (tm.dxdx * vposx + tm.dxdy * vposy + tm.dxdz * vposz + trans.x) * influence.weight; pVertexBuffer[1] += (tm.dydx * vposx + tm.dydy * vposy + tm.dydz * vposz + trans.y) * influence.weight; pVertexBuffer[2] += (tm.dzdx * vposx + tm.dzdy * vposy + tm.dzdz * vposz + trans.z) * influence.weight; if (NULL != pNormalBuffer) { // transform normal with current state of the bone const float & vnx = vertex.normal.x; const float & vny = vertex.normal.y; const float & vnz = vertex.normal.z; pNormalBuffer[0] += (tm.dxdx * vnx + tm.dxdy * vny + tm.dxdz * vnz) * influence.weight; pNormalBuffer[1] += (tm.dydx * vnx + tm.dydy * vny + tm.dydz * vnz) * influence.weight; pNormalBuffer[2] += (tm.dzdx * vnx + tm.dzdy * vny + tm.dzdz * vnz) * influence.weight; } } // save vertex position pVertexBuffer += 3; if (NULL != pNormalBuffer) { pNormalBuffer += 3; } /* if (NULL != pColorBuffer) { pColorBuffer += 4; } */ } dirtyBound(); dirtyDisplayList(); return true; } void SubMeshSoftware::drawImplementation(osg::State& state) const { #ifdef USE_NPROFILE NPROFILE_SAMPLE("SubMeshSoftware::drawImplementation"); #endif if(!_invisible) Geometry::drawImplementation(state); } #if OSG_VERSION_RELEASE != 9 && OSG_VERSION_MAJOR != 1 bool SubMeshSoftware::computeBound() const { if(_supportsPrimitiveFunctor) { bool res = Geometry::computeBound(); return res; } else { _bbox=_staticbbox; _bbox_computed = false; return true; } } #else // OSG_VERSION_RELEASE != 9 && OSG_VERSION_MAJOR != 1 osg::BoundingBox SubMeshSoftware::computeBound() const { if(_supportsPrimitiveFunctor) { return Geometry::computeBound(); } else { _boundingBox = _staticbbox; _boundingBoxComputed = false; return _boundingBox; } } #endif // OSG_VERSION_RELEASE != 9 && OSG_VERSION_MAJOR != 1 static int coreMeshId2MeshId(CalModel* calModel, int coreMeshId) { CalMesh* mesh = calModel->getMesh(coreMeshId); if(mesh == 0) { CalError::setLastError(CalError::NULL_BUFFER, __FILE__, __LINE__); return -1; } int meshId = -1; for(std::vector::iterator meshIt = calModel->getVectorMesh().begin(); meshIt != calModel->getVectorMesh().end(); meshIt++) { meshId++; if(*meshIt == mesh) break; } return meshId; } bool SubMeshSoftware::create(void) { int meshId = coreMeshId2MeshId(_calModel, _coreMeshId); if(meshId < 0) { osg::notify(osg::FATAL) << "SubMeshSoftware::create could not find meshId for coreMeshId " << _coreMeshId << " : " << CalError::getLastErrorDescription() << std::endl; return false; } int submeshId = _coreSubmeshId; CalRenderer* calRenderer = _calModel->getRenderer(); calRenderer->selectMeshSubmesh(meshId, submeshId); // vertexes { int count = calRenderer->getVertexCount(); osg::Vec3Array* array = new osg::Vec3Array(count); calRenderer->getVertices((float*)array->getDataPointer()); setVertexArray(array); } // normals if(!_invisible) { int count = calRenderer->getVertexCount(); osg::Vec3Array* array = new osg::Vec3Array(count); calRenderer->getNormals((float*)array->getDataPointer()); setNormalArray(array); setNormalBinding(osg::Geometry::BIND_PER_VERTEX); } // texture coordinates if(!_invisible) { int count = calRenderer->getVertexCount(); // for(int mapId = 0; mapId < calRenderer->getMapCount(); mapId++) { int end=calRenderer->getMapCount(); // if (end>1) // end=1; for(int mapId = 0; mapId < end; mapId++) { osg::Vec2Array* array = new osg::Vec2Array(count); calRenderer->getTextureCoordinates(mapId, (float*)array->getDataPointer()); setTexCoordArray(mapId, array); } } /* // vertex color if(!_invisible) { int count = calRenderer->getVertexCount(); #if OSG_VERSION_MAJOR != 1 osg::UByte4Array *array = new osg::UByte4Array(count); #else // OSG_VERSION_MAJOR != 1 osg::Vec4ubArray *array = new osg::Vec4ubArray(count); #endif // OSG_VERSION_MAJOR != 1 setColorArray(array); setColorBinding(osg::Geometry::BIND_PER_VERTEX); } */ // faces { int count = calRenderer->getFaceCount(); osg::PrimitiveSet* primitive; if(sizeof(CalIndex) == sizeof(GLushort)) { osg::DrawElementsUShort* primitiveUShort = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, count*3); primitive = primitiveUShort; calRenderer->getFaces((CalIndex*)&(primitiveUShort->front())); } else { osg::DrawElementsUInt* primitiveUInt = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, count*3); primitive = primitiveUInt; calRenderer->getFaces((CalIndex*)&(primitiveUInt->front())); } addPrimitiveSet(primitive); } return true; }