Back to index

supertuxkart  0.5+dfsg1
material_manager.cpp
Go to the documentation of this file.
00001 //  $Id: material_manager.cpp 2111 2008-05-31 07:04:30Z cosmosninja $
00002 //
00003 //  SuperTuxKart - a fun racing game with go-kart
00004 //  Copyright (C) 2004 Steve Baker <sjbaker1@airmail.net>
00005 //
00006 //  This program is free software; you can redistribute it and/or
00007 //  modify it under the terms of the GNU General Public License
00008 //  as published by the Free Software Foundation; either version 2
00009 //  of the License, or (at your option) any later version.
00010 //
00011 //  This program is distributed in the hope that it will be useful,
00012 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //  GNU General Public License for more details.
00015 //
00016 //  You should have received a copy of the GNU General Public License
00017 //  along with this program; if not, write to the Free Software
00018 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 
00020 #include <stdexcept>
00021 #include "file_manager.hpp"
00022 #include "material_manager.hpp"
00023 #include "material.hpp"
00024 #include "translation.hpp"
00025 #include "string_utils.hpp"
00026 
00027 #if defined(WIN32) && !defined(__CYGWIN__)
00028 #  define snprintf _snprintf
00029 #  define strdup _strdup
00030 #endif
00031 
00032 ssgState *fuzzy_gst;
00033 
00034 MaterialManager *material_manager=0;
00035 
00036 MaterialManager::MaterialManager()
00037 {
00038     /* Create list - and default material zero */
00039 
00040     m_materials.reserve(256);
00041     // We can't call init/loadMaterial here, since the global variable
00042     // material_manager has not yet been initialised, and
00043     // material_manager is used in the Material constructor.
00044     // Therefore, the code for loading the material had to
00045     // be moved into a separate function.
00046 }
00047 
00048 //-----------------------------------------------------------------------------
00049 int MaterialManager::addEntity(Material *m)
00050 {
00051     m_materials.push_back(m);
00052     return (int)m_materials.size()-1;
00053 }
00054 
00055 //-----------------------------------------------------------------------------
00056 void MaterialManager::reInit()
00057 {
00058     for(std::vector<Material*>::const_iterator i=m_materials.begin();
00059         i!=m_materials.end(); i++)
00060     {
00061         delete *i;
00062     }
00063     m_materials.clear();
00064     loadMaterial();
00065 }   // reInit
00066 
00067 //-----------------------------------------------------------------------------
00068 void MaterialManager::loadMaterial()
00069 {
00070     // Create the default/empty material.
00071     m_materials.push_back(new Material((int)m_materials.size()));
00072 
00073     // Use temp material for reading, but then set the shared
00074     // material index later, so that these materials are not popped
00075     const std::string fname     = "materials.dat";
00076     std::string       full_name = file_manager->getTextureFile(fname);
00077     addSharedMaterial(full_name);
00078 
00079     ssgSetAppStateCallback(getAppState);
00080     fuzzy_gst        = getMaterial("fuzzy.rgb")->getState();
00081     // Save index of shared textures
00082     m_shared_material_index = (int)m_materials.size();
00083 }   // MaterialManager
00084 
00085 //-----------------------------------------------------------------------------
00086 void MaterialManager::addSharedMaterial(const std::string& filename)
00087 {
00088     // Use temp material for reading, but then set the shared
00089     // material index later, so that these materials are not popped
00090     if(filename=="")
00091     {
00092         char msg[MAX_ERROR_MESSAGE_LENGTH];
00093         snprintf(msg, sizeof(msg), "FATAL: File '%s' not found\n", filename.c_str());
00094         throw std::runtime_error(msg);
00095     }
00096     if(!pushTempMaterial(filename))
00097     {
00098         char msg[MAX_ERROR_MESSAGE_LENGTH];
00099         snprintf(msg, sizeof(msg), "FATAL: Parsing error in '%s'\n", filename.c_str());
00100         throw std::runtime_error(msg);
00101     }
00102     m_shared_material_index = (int)m_materials.size();
00103 }   // addSharedMaterial
00104 
00105 //-----------------------------------------------------------------------------
00106 bool MaterialManager::pushTempMaterial(const std::string& filename)
00107 {
00108     FILE *fd = fopen(filename.c_str(), "r" );
00109 
00110     if ( fd == NULL ) return false;
00111 
00112     while ( parseMaterial ( fd ) )
00113         /* Read file */ ;
00114 
00115     fclose ( fd ) ;
00116     return true;
00117 }   // pushTempMaterial
00118 
00119 //-----------------------------------------------------------------------------
00120 void MaterialManager::popTempMaterial()
00121 {
00122     for(int i=(int)m_materials.size()-1; i>=this->m_shared_material_index; i--)
00123     {
00124         delete m_materials[i];
00125         m_materials.pop_back();
00126     }   // for i
00127 }   // popTempMaterial
00128 
00129 //-----------------------------------------------------------------------------
00130 char* MaterialManager::parseFileName(char **str)
00131 {
00132     char *p = *str ;
00133 
00134     /* Skip leading spaces */
00135     while ( *p <= ' ' && *p != '\0' ) p++ ;
00136 
00137     /* Skip blank lines and comments */
00138     if ( *p == '#' || *p == '\0' )
00139         return NULL ;
00140 
00141     if ( *p != '"' )
00142     {
00143         fprintf(stderr, "ERROR: Material file entries must start with '\"'\n"
00144                 "ERROR: Offending line is '%s'\n", *str);
00145         return NULL ;
00146     }
00147 
00148     /* Filename? */
00149     char *f = ++p ;
00150     while ( *p != '"' && *p != '\0' ) p++ ;
00151 
00152     if ( *p != '"' )
00153     {
00154         fprintf(stderr,
00155                 "ERROR: Unterminated string constant '%s' in materials file.\n", *str ) ;
00156         return NULL ;
00157     }
00158 
00159     *p = '\0' ;
00160     *str = ++p ;
00161 
00162     return f ;
00163 }   // parseFilename
00164 
00165 //-----------------------------------------------------------------------------
00166 int MaterialManager::parseMaterial ( FILE *fd )
00167 {
00168     char str [ 1024 ] ;
00169 
00170     while ( ! feof ( fd ) )
00171     {
00172         char *s = str ;
00173 
00174         if ( fgets ( s, 1024, fd ) == NULL )
00175             return false ;
00176 
00177         s [ strlen(s) - 1 ] = '\0' ;
00178 
00179         char *f = parseFileName ( & s ) ;
00180 
00181         if ( f != NULL )
00182         {
00183             m_materials.push_back(new Material (f, s, (int)m_materials.size() ));
00184             return true ;
00185         }
00186     }
00187 
00188     return false ;
00189 }   // parseMaterial
00190 
00191 //-----------------------------------------------------------------------------
00192 Material *MaterialManager::getMaterial ( ssgLeaf *l )
00193 {
00194     return m_materials[l -> getExternalPropertyIndex ()] ;
00195 }   // getMaterial
00196 
00197 //-----------------------------------------------------------------------------
00198 Material *MaterialManager::getMaterial(const std::string& fname, 
00199                                        bool is_full_path )
00200 {
00201     if(fname=="")
00202     {
00203         // This happens while reading the stk_config file, which contains
00204         // kart_properties information (but no icon file): since at this 
00205         // stage loadMaterial() hasn't been called, an exception can be
00206         // triggered here (as it happened with visual c++), when
00207         // m_materials[0] is accessed.
00208         if(m_materials.size()>=1) return m_materials[0];
00209         return NULL;
00210     }
00211 
00212     std::string basename=StringUtils::basename(fname);
00213 
00214     // Search backward so that temporary (track) textures are found first
00215     for(int i = (int)m_materials.size()-1; i>=0; i-- )
00216     {
00217         if(m_materials[i]->getTexFname()==basename) return m_materials[i];
00218     }
00219 
00220     // Add the new material
00221     Material* m=new Material(fname,"", (int)m_materials.size(), is_full_path);
00222     m_materials.push_back(m);
00223 
00224     return m ;
00225 }   // getMaterial
00226 
00227 //=============================================================================
00228 ssgState *getAppState ( char *fname )
00229 {
00230     Material *m = material_manager->getMaterial ( fname ) ;
00231     return ( m == NULL ) ? NULL : m -> getState () ;
00232 }   // getAppState
00233