//////////////////////////////////////////////////////////////////////////////// // Scorched3D (c) 2000-2004 // // This file is part of Scorched3D. // // Scorched3D 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. // // Scorched3D 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 Scorched3D; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// #include <3dsparse/ModelRenderer.h> #include <3dsparse/ModelMaths.h> #include #include #include #include ModelRenderer::ModelRenderer(Model *model) : model_(model) { setup(); } ModelRenderer::~ModelRenderer() { while (!boneTypes_.empty()) { BoneType *type = boneTypes_.back(); boneTypes_.pop_back(); delete type; } while (!displayLists_.empty()) { unsigned int list = displayLists_.back(); displayLists_.pop_back(); glDeleteLists(list, 1); } } void ModelRenderer::setup() { currentFrame_ = (float) model_->getStartFrame(); std::vector &baseTypes = model_->getBaseBoneTypes(); std::vector::iterator itor; for (itor = baseTypes.begin(); itor != baseTypes.end(); itor++) { boneTypes_.push_back(new BoneType(*(*itor))); } for (unsigned int m=0; mgetMeshes().size(); m++) { displayLists_.push_back(0); lastCachedState_.push_back(0); } } void ModelRenderer::drawBottomAligned(float LOD) { glPushMatrix(); glTranslatef(0.0f, 0.0f, -model_->getMin()[2]); draw(LOD); glPopMatrix(); } void ModelRenderer::draw(float LOD) { for (unsigned int m=0; mgetMeshes().size(); m++) { Mesh *mesh = model_->getMeshes()[m]; drawMesh(m, mesh, mesh->getReferencesBones(), LOD); } } void ModelRenderer::simulate(float frameTime) { currentFrame_ += frameTime; if (currentFrame_ > (float) model_->getTotalFrames()) { currentFrame_ = (float) model_->getStartFrame(); } for (unsigned int b=0; bgetBones()[b]; BoneType *type = boneTypes_[b]; unsigned int posKeys = bone->getPositionKeys().size(); unsigned int rotKeys = bone->getRotationKeys().size(); if (posKeys == 0 && rotKeys == 0) { memcpy(type->final_, type->absolute_, sizeof(BoneMatrixType)); continue; } BoneMatrixType m; bone->getRotationAtTime(currentFrame_, m); Vector &pos = bone->getPositionAtTime(currentFrame_); m[0][3] = pos[0]; m[1][3] = pos[1]; m[2][3] = pos[2]; ModelMaths::concatTransforms(type->relative_, m, type->relativeFinal_); if (type->parent_ == -1) { memcpy(type->final_, type->relativeFinal_, sizeof(BoneMatrixType)); } else { BoneType *parent = boneTypes_[type->parent_]; ModelMaths::concatTransforms(parent->final_, type->relativeFinal_, type->final_); } } } void ModelRenderer::drawMesh(unsigned int m, Mesh *mesh, bool dontCache, float LOD) { bool useTextures = (!OptionsDisplay::instance()->getNoSkins() && mesh->getTexture()); unsigned state = GLState::TEXTURE_OFF; if (useTextures) { state = GLState::TEXTURE_ON; mesh->getTexture()->draw(); if (mesh->getSphereMap()) { state |= GLState::NORMALIZE_ON; glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGenf(GL_R, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); } } bool vertexLighting = OptionsDisplay::instance()->getNoModelLighting(); if (!vertexLighting) { state |= GLState::NORMALIZE_ON | GLState::LIGHTING_ON | GLState::LIGHT1_ON; if (useTextures) { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mesh->getAmbientColor()); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mesh->getDiffuseColor()); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mesh->getSpecularColor()); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mesh->getEmissiveColor()); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mesh->getShininessColor()); } else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mesh->getAmbientNoTexColor()); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mesh->getDiffuseNoTexColor()); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mesh->getSpecularNoTexColor()); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mesh->getEmissiveNoTexColor()); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mesh->getShininessColor()); } } GLState glState(state); if (dontCache) { drawVerts(m, mesh, LOD, vertexLighting); } else { unsigned int lastState = lastCachedState_[m]; unsigned int displayList = displayLists_[m]; if (lastState != state) { if (displayList != 0) { glDeleteLists(displayList, 1); displayList = 0; } lastCachedState_[m] = state; } if (!displayList) { glNewList(displayList = glGenLists(1), GL_COMPILE); drawVerts(m, mesh, LOD, vertexLighting); glEndList(); displayLists_[m] = displayList; } glCallList(displayList); GLInfo::addNoTriangles((int) mesh->getFaces().size()); } if (useTextures) { if (mesh->getSphereMap()) { glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_GEN_R); } } } void ModelRenderer::drawVerts(unsigned int m, Mesh *mesh, float LOD, bool vertexLighting) { Vector vec; glBegin(GL_TRIANGLES); int maxIndex = int(float(mesh->getVertexes().size()) * LOD); int faceVerts[3]; if (mesh->getCollapseMap().empty() && !mesh->getFaces().empty() && !OptionsDisplay::instance()->getNoModelLOD()) { mesh->setupCollapse(); } std::vector::iterator itor; for (itor = mesh->getFaces().begin(); itor != mesh->getFaces().end(); itor++) { Face *face = *itor; for (int i=0; i<3; i++) { int index = face->v[i]; if (!OptionsDisplay::instance()->getNoModelLOD() && LOD < 1.0f) { while (index > maxIndex) { index = mesh->getCollapseMap()[index]; } } faceVerts[i] = index; } if (faceVerts[0] != faceVerts[1] && faceVerts[1] != faceVerts[2] && faceVerts[0] != faceVerts[2]) { GLInfo::addNoTriangles(1); for (int i=0; i<3; i++) { Vertex *vertex = mesh->getVertex(faceVerts[i]); if (vertexLighting) { if (GLState::getState() & GLState::TEXTURE_OFF) { glColor3f( mesh->getDiffuseNoTexColor()[0] * vertex->lightintense[0], mesh->getDiffuseNoTexColor()[1] * vertex->lightintense[1], mesh->getDiffuseNoTexColor()[2] * vertex->lightintense[2]); } else { glColor3fv(vertex->lightintense); } } glTexCoord2f(face->tcoord[i][0], face->tcoord[i][1]); glNormal3fv(face->normal[i]); if (vertex->boneIndex != -1) { BoneType *type = boneTypes_[vertex->boneIndex]; // Note: Translation of MS to S3D coords Vector newPos, newVec; newPos[0] = vertex->position[0]; newPos[1] = vertex->position[2]; newPos[2] = vertex->position[1]; ModelMaths::vectorRotate(newPos, type->final_, newVec); vec[0] = newVec[0]; vec[1] = newVec[2]; vec[2] = newVec[1]; vec[0] += type->final_[0][3] + vertexTranslation_[0]; vec[1] += type->final_[2][3] + vertexTranslation_[1]; vec[2] += type->final_[1][3] + vertexTranslation_[2]; } else { vec[0] = vertex->position[0] + vertexTranslation_[0]; vec[1] = vertex->position[1] + vertexTranslation_[1]; vec[2] = vertex->position[2] + vertexTranslation_[2]; } glVertex3fv(vec); } } } glEnd(); /* // draw normals { glBegin(GL_LINES); for (itor = mesh->getFaces().begin(); itor != mesh->getFaces().end(); itor++) { Face *face = *itor; for (int i=0; i<3; i++) { int index = face->v[i]; if (!OptionsDisplay::instance()->getNoModelLOD() && LOD < 1.0f) { while (index > maxIndex) { index = mesh->getCollapseMap()[index]; } } faceVerts[i] = index; } if (faceVerts[0] != faceVerts[1] && faceVerts[1] != faceVerts[2] && faceVerts[0] != faceVerts[2]) { GLInfo::addNoTriangles(1); for (int i=0; i<3; i++) { Vertex *vertex = mesh->getVertex(faceVerts[i]); glColor3f(1.0f, 0.0f, 0.0f); if (vertex->boneIndex != -1) { BoneType *type = boneTypes_[vertex->boneIndex]; // Note: Translation of MS to S3D coords Vector newPos, newVec; newPos[0] = vertex->position[0]; newPos[1] = vertex->position[2]; newPos[2] = vertex->position[1]; ModelMaths::vectorRotate(newPos, type->final_, newVec); vec[0] = newVec[0]; vec[1] = newVec[2]; vec[2] = newVec[1]; vec[0] += type->final_[0][3] + vertexTranslation_[0]; vec[1] += type->final_[2][3] + vertexTranslation_[1]; vec[2] += type->final_[1][3] + vertexTranslation_[2]; } else { vec[0] = vertex->position[0] + vertexTranslation_[0]; vec[1] = vertex->position[1] + vertexTranslation_[1]; vec[2] = vertex->position[2] + vertexTranslation_[2]; } glVertex3fv(vec); glVertex3fv(vec + face->normal[i] * 2.0f); } } } glEnd(); } */ }