#include #include #include "glext.h" #include "morphedMesh.h" #include "scene.h" /*-------------------------------------------------------------------------- * Constructor *--------------------------------------------------------------------------*/ MorphedMesh::MorphedMesh() : TriangleMesh() { dstMeshVerts = 0; dstMeshNormals = 0; srcVerts = 0; srcNormals = 0; hardwareVertexMorph = true; useExistingData = false; dstVertexBuffer = 0; dstNormalBuffer = 0; } /*-------------------------------------------------------------------------- * Destructor: delete vertex and normal buffers *--------------------------------------------------------------------------*/ MorphedMesh::~MorphedMesh() { if(!useExistingData) { if(dstMeshVerts) delete[] dstMeshVerts; if(dstMeshNormals) delete[] dstMeshNormals; } if(!hardwareVertexMorph) { if(srcVerts) delete[] srcVerts; if(srcNormals) delete[] srcNormals; } //vertices and normals deleted by parent } /*-------------------------------------------------------------------------- * LoadDstMesh: Sets the destination mesh on this morphed mesh. * @dst - destination mesh, must contain the same amount of vertices as this * mesh (which will act as the source) * @hwVertexMorphing - whether or not to use hardware vertex morphing * * If the dst mesh is NULL, compute the destination vertices on the bounding * sphere of the source mesh (this). * If this mesh is using a VBO, copy the data into buffer objects *--------------------------------------------------------------------------*/ void MorphedMesh::LoadDstMesh(TriangleMesh *dst, bool hwVertexMorphing) { hardwareVertexMorph = hwVertexMorphing; //if dst, then just use its vertices and normals //else, manually compute the destination vertices on the bounding sphere if(dst) { this->dstMeshVerts = dst->vertices; this->dstMeshNormals = dst->normals; useExistingData = true; } else { ComputeBoundingSphere(); this->dstMeshVerts = new Vex3[this->verticesN]; this->dstMeshNormals = new Vex3[this->verticesN]; float r = 0.0f; Vex3 direction; float newRadius = radius; for(int i = 0; i < verticesN; i++) { direction = vertices[i] - center; r = direction.Length(); dstMeshVerts[i] = vertices[i] + direction.UnitVector() * (newRadius - r); } //compute normals from the dst verts OutputNormals(this->dstMeshNormals, this->dstMeshVerts); } //if no hw vertex morph, copy vertices and normals into src buffers if(!hardwareVertexMorph) { srcVerts = new Vex3[this->verticesN]; srcNormals = new Vex3[this->verticesN]; memcpy(srcVerts, vertices, sizeof(float) * 3 * verticesN); memcpy(srcNormals, normals, sizeof(float) * 3 * verticesN); } //copy data into VBOs if(useVBO) { //------create the vertex buffer--------// glGenBuffersARB(1, &dstVertexBuffer); glBindBufferARB(GL_ARRAY_BUFFER_ARB, dstVertexBuffer); glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(float) * 3 * verticesN, (float*)this->dstMeshVerts, GL_STATIC_DRAW_ARB); //------create the normal buffer--------// glGenBuffersARB(1, &dstNormalBuffer); glBindBufferARB(GL_ARRAY_BUFFER_ARB, dstNormalBuffer); glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(float) * 3 * verticesN, (float*)this->dstMeshNormals, GL_STATIC_DRAW_ARB); //unbind the buffer glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } } /*-------------------------------------------------------------------------- * RenderHW: Renders the morphing mesh. Interpolates in software or hardware * @renderMode - type of rendering mode to use (e.g. wireframe, solid) *--------------------------------------------------------------------------*/ void MorphedMesh::RenderHW(RenderMode renderMode) { //if no mesh provided, default to the bounding sphere if(dstMeshVerts == NULL) { LoadDstMesh(NULL, true); } if(hardwareVertexMorph) { if(useVBO) { //enable destination vertices glClientActiveTexture(GL_TEXTURE0); glBindBufferARB(GL_ARRAY_BUFFER_ARB, dstVertexBuffer); glTexCoordPointer(3, GL_FLOAT, 0, NULL); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //enable destination normals glClientActiveTexture(GL_TEXTURE1); glBindBufferARB(GL_ARRAY_BUFFER_ARB, dstNormalBuffer); glTexCoordPointer(3, GL_FLOAT, 0, NULL); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } else { //enable destination vertices glClientActiveTexture(GL_TEXTURE0); glTexCoordPointer(3, GL_FLOAT, 0, (float*) dstMeshVerts); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //enable destination normals glClientActiveTexture(GL_TEXTURE1); glTexCoordPointer(3, GL_FLOAT, 0, (float*) dstMeshNormals); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } } else //no hw vertex blending, manually find the interoplated vertices { float blend = 0.0f; if(scene->cameraPath->PathLength() > 0) blend = (float)scene->cameraPath->PathIndex() / (float)scene->cameraPath->PathLength(); for(int i = 0; i < verticesN; i++) { vertices[i] = srcVerts[i] + (dstMeshVerts[i] - srcVerts[i]) * blend; normals[i] = srcNormals[i] + (dstMeshNormals[i] - srcNormals[i]) * blend; } } TriangleMesh::RenderHW(renderMode); //disable attributes if(hardwareVertexMorph) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } }