// ============================================================== // This file is part of Glest Shared Library (www.glest.org) // // Copyright (C) 2001-2008 Martio Figueroa // // You can redistribute this code 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 // ============================================================== #include "model.h" #include #include #include #include "interpolation.h" #include "conversion.h" #include "util.h" #include "platform_common.h" #include "opengl.h" #include "leak_dumper.h" using namespace Shared::Platform; using namespace Shared::PlatformCommon; using namespace Shared::Graphics::Gl; using namespace std; namespace Shared{ namespace Graphics{ using namespace Util; // ===================================================== // class Mesh // ===================================================== // ==================== constructor & destructor ==================== Mesh::Mesh() { textureManager = NULL; frameCount= 0; vertexCount= 0; indexCount= 0; texCoordFrameCount = 0; vertices= NULL; normals= NULL; texCoords= NULL; tangents= NULL; indices= NULL; interpolationData= NULL; for(int i=0; igetPath().c_str(),i); textureManager->endTexture(textures[i]); textures[i] = NULL; } } } textureManager = NULL; } // ========================== shadows & interpolation ========================= void Mesh::buildInterpolationData(){ interpolationData= new InterpolationData(this); } void Mesh::updateInterpolationData(float t, bool cycle) { if(interpolationData != NULL) { interpolationData->update(t, cycle); } } void Mesh::updateInterpolationVertices(float t, bool cycle) { if(interpolationData != NULL) { interpolationData->updateVertices(t, cycle); } } void Mesh::BuildVBOs() { if(getVBOSupported() == true) { if(hasBuiltVBOs == false) { //printf("In [%s::%s Line: %d] setting up a VBO...\n",__FILE__,__FUNCTION__,__LINE__); // Generate And Bind The Vertex Buffer glGenBuffersARB( 1, &m_nVBOVertices ); // Get A Valid Name glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices ); // Bind The Buffer // Load The Data glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(Vec3f)*frameCount*vertexCount, getInterpolationData()->getVertices(), GL_STATIC_DRAW_ARB ); glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); // Generate And Bind The Texture Coordinate Buffer glGenBuffersARB( 1, &m_nVBOTexCoords ); // Get A Valid Name glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords ); // Bind The Buffer // Load The Data glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(Vec2f)*vertexCount, texCoords, GL_STATIC_DRAW_ARB ); glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); // Generate And Bind The Normal Buffer glGenBuffersARB( 1, &m_nVBONormals ); // Get A Valid Name glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBONormals ); // Bind The Buffer // Load The Data glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(Vec3f)*frameCount*vertexCount, getInterpolationData()->getNormals(), GL_STATIC_DRAW_ARB ); glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); // Generate And Bind The Index Buffer glGenBuffersARB( 1, &m_nVBOIndexes ); // Get A Valid Name glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_nVBOIndexes ); // Bind The Buffer // Load The Data glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(uint32)*indexCount, indices, GL_STATIC_DRAW_ARB ); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); // Our Copy Of The Data Is No Longer Necessary, It Is Safe In The Graphics Card delete [] vertices; vertices = NULL; delete [] texCoords; texCoords = NULL; delete [] normals; normals = NULL; delete [] indices; indices = NULL; delete interpolationData; interpolationData = NULL; hasBuiltVBOs = true; } } } void Mesh::ReleaseVBOs() { if(getVBOSupported() == true) { if(hasBuiltVBOs == true) { glDeleteBuffersARB( 1, &m_nVBOVertices ); // Get A Valid Name glDeleteBuffersARB( 1, &m_nVBOTexCoords ); // Get A Valid Name glDeleteBuffersARB( 1, &m_nVBONormals ); // Get A Valid Name glDeleteBuffersARB( 1, &m_nVBOIndexes ); // Get A Valid Name hasBuiltVBOs = false; } } } // ==================== load ==================== void Mesh::loadV2(const string &dir, FILE *f, TextureManager *textureManager,bool deletePixMapAfterLoad) { this->textureManager = textureManager; //read header MeshHeaderV2 meshHeader; size_t readBytes = fread(&meshHeader, sizeof(MeshHeaderV2), 1, f); if(meshHeader.normalFrameCount!=meshHeader.vertexFrameCount){ throw runtime_error("Old model: vertex frame count different from normal frame count"); } if(meshHeader.texCoordFrameCount!=1){ throw runtime_error("Old model: texture coord frame count is not 1"); } //init frameCount= meshHeader.vertexFrameCount; vertexCount= meshHeader.pointCount; indexCount= meshHeader.indexCount; texCoordFrameCount = meshHeader.texCoordFrameCount; init(); //misc twoSided= false; customColor= false; if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Load v2, this = %p Found meshHeader.hasTexture = %d, texName [%s] mtDiffuse = %d\n",this,meshHeader.hasTexture,toLower(reinterpret_cast(meshHeader.texName)).c_str(),mtDiffuse); textureFlags= 0; if(meshHeader.hasTexture == true) { textureFlags= 1; } //texture if(meshHeader.hasTexture && textureManager!=NULL){ texturePaths[mtDiffuse]= toLower(reinterpret_cast(meshHeader.texName)); string texPath= dir; if(texPath != "") { texPath += "/"; } texPath += texturePaths[mtDiffuse]; textures[mtDiffuse]= static_cast(textureManager->getTexture(texPath)); if(textures[mtDiffuse]==NULL){ textures[mtDiffuse]= textureManager->newTexture2D(); textures[mtDiffuse]->load(texPath); texturesOwned[mtDiffuse]=true; // M.V. Test textures[mtDiffuse]->init(textureManager->getTextureFilter(),textureManager->getMaxAnisotropy()); if(deletePixMapAfterLoad == true) { textures[mtDiffuse]->deletePixels(); } } } //read data readBytes = fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); readBytes = fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); if(textures[mtDiffuse]!=NULL){ readBytes = fread(texCoords, sizeof(Vec2f)*vertexCount, 1, f); } readBytes = fread(&diffuseColor, sizeof(Vec3f), 1, f); readBytes = fread(&opacity, sizeof(float32), 1, f); fseek(f, sizeof(Vec4f)*(meshHeader.colorFrameCount-1), SEEK_CUR); readBytes = fread(indices, sizeof(uint32)*indexCount, 1, f); } void Mesh::loadV3(const string &dir, FILE *f, TextureManager *textureManager,bool deletePixMapAfterLoad) { this->textureManager = textureManager; //read header MeshHeaderV3 meshHeader; size_t readBytes = fread(&meshHeader, sizeof(MeshHeaderV3), 1, f); if(meshHeader.normalFrameCount!=meshHeader.vertexFrameCount){ throw runtime_error("Old model: vertex frame count different from normal frame count"); } //init frameCount= meshHeader.vertexFrameCount; vertexCount= meshHeader.pointCount; indexCount= meshHeader.indexCount; texCoordFrameCount = meshHeader.texCoordFrameCount; init(); //misc twoSided= (meshHeader.properties & mp3TwoSided) != 0; customColor= (meshHeader.properties & mp3CustomColor) != 0; textureFlags= 0; if((meshHeader.properties & mp3NoTexture) != mp3NoTexture) { textureFlags= 1; } if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Load v3, this = %p Found meshHeader.properties = %d, textureFlags = %d, texName [%s] mtDiffuse = %d\n",this,meshHeader.properties,textureFlags,toLower(reinterpret_cast(meshHeader.texName)).c_str(),mtDiffuse); //texture if((meshHeader.properties & mp3NoTexture) != mp3NoTexture && textureManager!=NULL){ texturePaths[mtDiffuse]= toLower(reinterpret_cast(meshHeader.texName)); string texPath= dir; if(texPath != "") { texPath += "/"; } texPath += texturePaths[mtDiffuse]; textures[mtDiffuse]= static_cast(textureManager->getTexture(texPath)); if(textures[mtDiffuse]==NULL){ textures[mtDiffuse]= textureManager->newTexture2D(); textures[mtDiffuse]->load(texPath); texturesOwned[mtDiffuse]=true; // M.V. Test textures[mtDiffuse]->init(textureManager->getTextureFilter(),textureManager->getMaxAnisotropy()); if(deletePixMapAfterLoad == true) { textures[mtDiffuse]->deletePixels(); } } } //read data readBytes = fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); readBytes = fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); if(textures[mtDiffuse]!=NULL){ for(unsigned int i=0; i(textureManager->getTexture(textureFile)); if(texture == NULL) { texture = textureManager->newTexture2D(); if(textureChannelCount != -1) { texture->getPixmap()->init(textureChannelCount); } texture->load(textureFile); textureOwned = true; texture->init(textureManager->getTextureFilter(),textureManager->getMaxAnisotropy()); if(deletePixMapAfterLoad == true) { texture->deletePixels(); } } return texture; } void Mesh::load(const string &dir, FILE *f, TextureManager *textureManager, bool deletePixMapAfterLoad) { this->textureManager = textureManager; //read header MeshHeader meshHeader; size_t readBytes = fread(&meshHeader, sizeof(MeshHeader), 1, f); name = reinterpret_cast(meshHeader.name); //printf("Load, Found meshTextureCount = %d, meshHeader.textures = %d\n",meshTextureCount,meshHeader.textures); //init frameCount= meshHeader.frameCount; vertexCount= meshHeader.vertexCount; indexCount= meshHeader.indexCount; init(); //properties customColor= (meshHeader.properties & mpfCustomColor) != 0; twoSided= (meshHeader.properties & mpfTwoSided) != 0; //material diffuseColor= Vec3f(meshHeader.diffuseColor); specularColor= Vec3f(meshHeader.specularColor); specularPower= meshHeader.specularPower; opacity= meshHeader.opacity; textureFlags= meshHeader.textures; if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Load v4, this = %p Found meshHeader.textures = %d\n",this,meshHeader.textures); //maps uint32 flag= 1; for(int i=0; i(cMapPath)); string mapFullPath= dir; if(mapFullPath != "") { mapFullPath += "/"; } mapFullPath += mapPath; textures[i] = loadMeshTexture(textureManager, mapFullPath, meshTextureChannelCount[i],texturesOwned[i],deletePixMapAfterLoad); } flag*= 2; } //read data readBytes = fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); readBytes = fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); if(meshHeader.textures!=0){ readBytes = fread(texCoords, sizeof(Vec2f)*vertexCount, 1, f); } readBytes = fread(indices, sizeof(uint32)*indexCount, 1, f); //tangents if(textures[mtNormal]!=NULL){ computeTangents(); } } void Mesh::save(const string &dir, FILE *f, TextureManager *textureManager, string convertTextureToFormat, std::map &textureDeleteList) { MeshHeader meshHeader; memset(&meshHeader, 0, sizeof(struct MeshHeader)); strncpy((char*)meshHeader.name, (char*)name.c_str(), name.length()); meshHeader.frameCount= frameCount; meshHeader.vertexCount= vertexCount; meshHeader.indexCount = indexCount; //material memcpy((float32*)meshHeader.diffuseColor, (float32*)diffuseColor.ptr(), sizeof(float32) * 3); memcpy((float32*)meshHeader.specularColor, (float32*)specularColor.ptr(), sizeof(float32) * 3); meshHeader.specularPower = specularPower; meshHeader.opacity = opacity; //properties meshHeader.properties = 0; if(customColor) { meshHeader.properties |= mpfCustomColor; } if(twoSided) { meshHeader.properties |= mpfTwoSided; } meshHeader.textures = textureFlags; fwrite(&meshHeader, sizeof(MeshHeader), 1, f); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, this = %p, Found meshTextureCount = %d, meshHeader.textures = %d\n",this,meshTextureCount,meshHeader.textures); //maps uint32 flag= 1; for(int i=0; i< meshTextureCount; ++i) { if((meshHeader.textures & flag)) { uint8 cMapPath[mapPathSize]; memset(&cMapPath[0],0,mapPathSize); Texture2D *texture = textures[i]; if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, [%d] mesh texture ptr [%p]\n",i,texture); if(texture != NULL) { string file = toLower(texture->getPath()); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, Found mesh texture [%s]\n",file.c_str()); if(toLower(convertTextureToFormat) != "" && EndsWith(file, "." + convertTextureToFormat) == false) { string fileExt = extractExtension(file); replaceAll(file, "." + fileExt, "." + convertTextureToFormat); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, Convert from [%s] to [%s]\n",texture->getPath().c_str(),file.c_str()); if(convertTextureToFormat == "tga") { texture->getPixmap()->saveTga(file); textureDeleteList[texture->getPath()] = textureDeleteList[texture->getPath()] + 1; } else if(convertTextureToFormat == "bmp") { texture->getPixmap()->saveBmp(file); textureDeleteList[texture->getPath()] = textureDeleteList[texture->getPath()] + 1; } //else if(convertTextureToFormat == "jpg") { // texture->getPixmap()->saveJpg(file); //} else if(convertTextureToFormat == "png") { texture->getPixmap()->savePng(file); textureDeleteList[texture->getPath()] = textureDeleteList[texture->getPath()] + 1; } else { throw runtime_error("Unsuppoted texture format: [" + convertTextureToFormat + "]"); } //textureManager->endTexture(texture); texture = loadMeshTexture(textureManager,file, meshTextureChannelCount[i], texturesOwned[i], false); } file = extractFileFromDirectoryPath(texture->getPath()); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, new texture file [%s]\n",file.c_str()); memcpy(&cMapPath[0],file.c_str(),file.length()); } fwrite(cMapPath, mapPathSize, 1, f); } flag*= 2; } //read data fwrite(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); fwrite(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); if(meshHeader.textures != 0) { fwrite(texCoords, sizeof(Vec2f)*vertexCount, 1, f); } fwrite(indices, sizeof(uint32)*indexCount, 1, f); } void Mesh::computeTangents(){ delete [] tangents; tangents= new Vec3f[vertexCount]; for(unsigned int i=0; ideletePixels(); } } } // =============================================== // class Model // =============================================== // ==================== constructor & destructor ==================== Model::Model() { meshCount = 0; meshes = NULL; textureManager = NULL; lastTData = -1; lastCycleData = false; lastTVertex = -1; lastCycleVertex = false; } Model::~Model() { delete [] meshes; meshes = NULL; } // ==================== data ==================== void Model::buildInterpolationData() const{ for(unsigned int i=0; ifileName = path; } void Model::save(const string &path, string convertTextureToFormat) { string extension= path.substr(path.find_last_of('.')+1); if(extension=="g3d" ||extension=="G3D") { saveG3d(path,convertTextureToFormat); } else{ throw runtime_error("Unknown model format: " + extension); } } //load a model from a g3d file void Model::loadG3d(const string &path, bool deletePixMapAfterLoad) { try{ FILE *f=fopen(path.c_str(),"rb"); if (f == NULL) { printf("In [%s::%s] cannot load file = [%s]\n",__FILE__,__FUNCTION__,path.c_str()); throw runtime_error("Error opening g3d model file [" + path + "]"); } string dir= extractDirectoryPathFromFile(path); //file header FileHeader fileHeader; size_t readBytes = fread(&fileHeader, sizeof(FileHeader), 1, f); if(strncmp(reinterpret_cast(fileHeader.id), "G3D", 3) != 0) { printf("In [%s::%s] file = [%s] fileheader.id = [%s][%c]\n",__FILE__,__FUNCTION__,path.c_str(),reinterpret_cast(fileHeader.id),fileHeader.id[0]); throw runtime_error("Not a valid G3D model"); } fileVersion= fileHeader.version; if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Load model, fileVersion = %d\n",fileVersion); //version 4 if(fileHeader.version == 4) { //model header ModelHeader modelHeader; readBytes = fread(&modelHeader, sizeof(ModelHeader), 1, f); meshCount= modelHeader.meshCount; if(SystemFlags::VERBOSE_MODE_ENABLED) printf("meshCount = %d\n",meshCount); if(modelHeader.type != mtMorphMesh) { throw runtime_error("Invalid model type"); } //load meshes meshes= new Mesh[meshCount]; for(uint32 i=0; i textureDeleteList; for(uint32 i = 0; i < meshCount; ++i) { meshes[i].save(path, f, textureManager,convertTextureToFormat,textureDeleteList); } // Now delete old textures since they were converted to a new format for(std::map::iterator iterMap = textureDeleteList.begin(); iterMap != textureDeleteList.end(); ++iterMap) { } } else { throw runtime_error("Invalid model version: "+ intToStr(fileHeader.version)); } fclose(f); } void Model::deletePixels() { for(uint32 i = 0; i < meshCount; ++i) { meshes[i].deletePixels(); } } }}//end namespace