2007-05-27 12:01:53 -04:00
|
|
|
// $Id$
|
|
|
|
//
|
|
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
|
|
// Copyright (C) 2004 Steve Baker <sjbaker1@airmail.net>
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
2008-06-12 20:53:52 -04:00
|
|
|
// as published by the Free Software Foundation; either version 3
|
2007-05-27 12:01:53 -04:00
|
|
|
// 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
#include "material_manager.hpp"
|
2008-02-23 03:21:30 -05:00
|
|
|
|
2009-01-22 17:27:13 -05:00
|
|
|
#include <stdexcept>
|
2009-01-23 00:23:22 -05:00
|
|
|
#include <sstream>
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2009-01-22 17:27:13 -05:00
|
|
|
#include "file_manager.hpp"
|
|
|
|
#include "material.hpp"
|
2009-02-26 19:15:09 -05:00
|
|
|
#include "io/xml_node.hpp"
|
2009-01-22 17:27:13 -05:00
|
|
|
#include "utils/string_utils.hpp"
|
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
ssgState *fuzzy_gst;
|
|
|
|
|
|
|
|
MaterialManager *material_manager=0;
|
|
|
|
|
|
|
|
MaterialManager::MaterialManager()
|
|
|
|
{
|
|
|
|
/* Create list - and default material zero */
|
|
|
|
|
2008-02-28 22:26:07 -05:00
|
|
|
m_materials.reserve(256);
|
2007-05-27 12:01:53 -04:00
|
|
|
// We can't call init/loadMaterial here, since the global variable
|
|
|
|
// material_manager has not yet been initialised, and
|
|
|
|
// material_manager is used in the Material constructor.
|
|
|
|
// Therefore, the code for loading the material had to
|
|
|
|
// be moved into a separate function.
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
int MaterialManager::addEntity(Material *m)
|
|
|
|
{
|
|
|
|
m_materials.push_back(m);
|
2007-12-09 20:39:30 -05:00
|
|
|
return (int)m_materials.size()-1;
|
2007-05-27 12:01:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MaterialManager::reInit()
|
|
|
|
{
|
|
|
|
for(std::vector<Material*>::const_iterator i=m_materials.begin();
|
|
|
|
i!=m_materials.end(); i++)
|
|
|
|
{
|
|
|
|
delete *i;
|
|
|
|
}
|
|
|
|
m_materials.clear();
|
|
|
|
loadMaterial();
|
|
|
|
} // reInit
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MaterialManager::loadMaterial()
|
|
|
|
{
|
2008-02-23 03:21:30 -05:00
|
|
|
// Create the default/empty material.
|
2009-02-26 19:15:09 -05:00
|
|
|
m_materials.push_back(new Material(m_materials.size()));
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2008-02-28 22:26:07 -05:00
|
|
|
// Use temp material for reading, but then set the shared
|
|
|
|
// material index later, so that these materials are not popped
|
2009-02-26 19:15:09 -05:00
|
|
|
#ifdef HAVE_IRRLICHT
|
|
|
|
const std::string fname = "materials.xml";
|
|
|
|
#else
|
2008-02-28 22:26:07 -05:00
|
|
|
const std::string fname = "materials.dat";
|
2009-02-26 19:15:09 -05:00
|
|
|
#endif
|
2008-02-29 22:18:53 -05:00
|
|
|
std::string full_name = file_manager->getTextureFile(fname);
|
2008-03-04 21:09:50 -05:00
|
|
|
addSharedMaterial(full_name);
|
2009-02-26 19:15:09 -05:00
|
|
|
#ifndef HAVE_IRRLICHT
|
2008-03-04 21:09:50 -05:00
|
|
|
ssgSetAppStateCallback(getAppState);
|
|
|
|
fuzzy_gst = getMaterial("fuzzy.rgb")->getState();
|
2009-02-26 19:15:09 -05:00
|
|
|
#endif
|
2008-03-04 21:09:50 -05:00
|
|
|
// Save index of shared textures
|
|
|
|
m_shared_material_index = (int)m_materials.size();
|
|
|
|
} // MaterialManager
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MaterialManager::addSharedMaterial(const std::string& filename)
|
|
|
|
{
|
|
|
|
// Use temp material for reading, but then set the shared
|
|
|
|
// material index later, so that these materials are not popped
|
|
|
|
if(filename=="")
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2009-01-23 00:23:22 -05:00
|
|
|
std::ostringstream msg;
|
|
|
|
msg<<"FATAL: File '"<<filename<<"' not found\n";
|
|
|
|
throw std::runtime_error(msg.str());
|
2007-05-27 12:01:53 -04:00
|
|
|
}
|
2008-03-04 21:09:50 -05:00
|
|
|
if(!pushTempMaterial(filename))
|
2008-02-28 22:26:07 -05:00
|
|
|
{
|
2009-01-23 00:23:22 -05:00
|
|
|
std::ostringstream msg;
|
|
|
|
msg <<"FATAL: Parsing error in '"<<filename<<"'\n";
|
|
|
|
throw std::runtime_error(msg.str());
|
2008-02-28 22:26:07 -05:00
|
|
|
}
|
|
|
|
m_shared_material_index = (int)m_materials.size();
|
2008-03-04 21:09:50 -05:00
|
|
|
} // addSharedMaterial
|
2008-02-28 22:26:07 -05:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool MaterialManager::pushTempMaterial(const std::string& filename)
|
|
|
|
{
|
2009-02-26 19:15:09 -05:00
|
|
|
#ifdef HAVE_IRRLICHT
|
|
|
|
XMLReader *xml = file_manager->getXMLReader(filename);
|
|
|
|
for(unsigned int i=0; i<xml->getNumNodes(); i++)
|
|
|
|
{
|
|
|
|
const XMLNode *node = xml->getNode(i);
|
|
|
|
if(!node)
|
|
|
|
{
|
|
|
|
// We don't have access to the filename at this stage anymore :(
|
|
|
|
fprintf(stderr, "Unknown node in material.dat file\n");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
2009-03-11 01:10:56 -04:00
|
|
|
m_materials.push_back(new Material(node, m_materials.size()));
|
2009-02-26 19:15:09 -05:00
|
|
|
}
|
|
|
|
catch(std::exception& e)
|
|
|
|
{
|
|
|
|
// The message contains a '%s' for the filename
|
|
|
|
fprintf(stderr, e.what(), filename.c_str());
|
|
|
|
}
|
|
|
|
} // for i<xml->getNumNodes)(
|
|
|
|
return true;
|
|
|
|
#else
|
2008-02-28 22:26:07 -05:00
|
|
|
FILE *fd = fopen(filename.c_str(), "r" );
|
|
|
|
|
|
|
|
if ( fd == NULL ) return false;
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
while ( parseMaterial ( fd ) )
|
|
|
|
/* Read file */ ;
|
|
|
|
|
|
|
|
fclose ( fd ) ;
|
2008-02-28 22:26:07 -05:00
|
|
|
return true;
|
2009-02-26 19:15:09 -05:00
|
|
|
#endif
|
2008-02-28 22:26:07 -05:00
|
|
|
} // pushTempMaterial
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2008-02-28 22:26:07 -05:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MaterialManager::popTempMaterial()
|
|
|
|
{
|
|
|
|
for(int i=(int)m_materials.size()-1; i>=this->m_shared_material_index; i--)
|
|
|
|
{
|
|
|
|
delete m_materials[i];
|
|
|
|
m_materials.pop_back();
|
|
|
|
} // for i
|
|
|
|
} // popTempMaterial
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2009-02-26 19:15:09 -05:00
|
|
|
#ifndef HAVE_IRRLICHT
|
2007-05-27 12:01:53 -04:00
|
|
|
char* MaterialManager::parseFileName(char **str)
|
|
|
|
{
|
|
|
|
char *p = *str ;
|
|
|
|
|
|
|
|
/* Skip leading spaces */
|
|
|
|
while ( *p <= ' ' && *p != '\0' ) p++ ;
|
|
|
|
|
|
|
|
/* Skip blank lines and comments */
|
|
|
|
if ( *p == '#' || *p == '\0' )
|
|
|
|
return NULL ;
|
|
|
|
|
|
|
|
if ( *p != '"' )
|
|
|
|
{
|
|
|
|
fprintf(stderr, "ERROR: Material file entries must start with '\"'\n"
|
|
|
|
"ERROR: Offending line is '%s'\n", *str);
|
|
|
|
return NULL ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Filename? */
|
|
|
|
char *f = ++p ;
|
|
|
|
while ( *p != '"' && *p != '\0' ) p++ ;
|
|
|
|
|
|
|
|
if ( *p != '"' )
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"ERROR: Unterminated string constant '%s' in materials file.\n", *str ) ;
|
|
|
|
return NULL ;
|
|
|
|
}
|
|
|
|
|
|
|
|
*p = '\0' ;
|
|
|
|
*str = ++p ;
|
|
|
|
|
|
|
|
return f ;
|
2008-02-23 03:21:30 -05:00
|
|
|
} // parseFilename
|
2009-02-26 19:15:09 -05:00
|
|
|
#endif
|
2007-05-27 12:01:53 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2009-02-26 19:15:09 -05:00
|
|
|
#ifndef HAVE_IRRLICHT
|
2007-05-27 12:01:53 -04:00
|
|
|
int MaterialManager::parseMaterial ( FILE *fd )
|
|
|
|
{
|
|
|
|
char str [ 1024 ] ;
|
|
|
|
|
|
|
|
while ( ! feof ( fd ) )
|
|
|
|
{
|
|
|
|
char *s = str ;
|
|
|
|
|
|
|
|
if ( fgets ( s, 1024, fd ) == NULL )
|
|
|
|
return false ;
|
|
|
|
|
|
|
|
s [ strlen(s) - 1 ] = '\0' ;
|
|
|
|
|
|
|
|
char *f = parseFileName ( & s ) ;
|
|
|
|
|
|
|
|
if ( f != NULL )
|
|
|
|
{
|
2009-02-26 19:15:09 -05:00
|
|
|
m_materials.push_back(new Material (f, s, m_materials.size() ));
|
2007-05-27 12:01:53 -04:00
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false ;
|
2008-02-23 03:21:30 -05:00
|
|
|
} // parseMaterial
|
2009-02-26 19:15:09 -05:00
|
|
|
#endif
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Material *MaterialManager::getMaterial ( ssgLeaf *l )
|
|
|
|
{
|
|
|
|
return m_materials[l -> getExternalPropertyIndex ()] ;
|
2008-02-23 03:21:30 -05:00
|
|
|
} // getMaterial
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2008-11-18 21:08:00 -05:00
|
|
|
/** Returns the material of a given name, if it doesn't exist, it is loaded.
|
|
|
|
* Materials that are just loaded are not permanent, and so get deleted after
|
|
|
|
* a race (this is used to load temporary, track specific materials). To make
|
|
|
|
* material permanent, make_permanent must be set to true. This is used for
|
|
|
|
* the powerup_manager, since not all icons for the powerups are listed in the
|
|
|
|
* materials.dat file, causing the missing ones to be temporary only (and
|
|
|
|
* then get deleted after one race, causing the powerup_manager to have
|
|
|
|
* invalid pointers.
|
|
|
|
* \param fname Name of the material.
|
|
|
|
* \param is_full_path True if the name includes the path (defaults to false)
|
|
|
|
* \param make_permanent True if this material should be kept in memory
|
|
|
|
* (defaults to false)
|
|
|
|
*/
|
2008-02-28 22:26:07 -05:00
|
|
|
Material *MaterialManager::getMaterial(const std::string& fname,
|
2008-11-18 21:08:00 -05:00
|
|
|
bool is_full_path,
|
|
|
|
bool make_permanent)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2008-02-28 22:26:07 -05:00
|
|
|
if(fname=="")
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
|
|
|
// This happens while reading the stk_config file, which contains
|
|
|
|
// kart_properties information (but no icon file): since at this
|
|
|
|
// stage loadMaterial() hasn't been called, an exception can be
|
|
|
|
// triggered here (as it happened with visual c++), when
|
|
|
|
// m_materials[0] is accessed.
|
|
|
|
if(m_materials.size()>=1) return m_materials[0];
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-02-23 03:21:30 -05:00
|
|
|
std::string basename=StringUtils::basename(fname);
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2008-02-28 22:26:07 -05:00
|
|
|
// Search backward so that temporary (track) textures are found first
|
|
|
|
for(int i = (int)m_materials.size()-1; i>=0; i-- )
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2008-02-23 03:21:30 -05:00
|
|
|
if(m_materials[i]->getTexFname()==basename) return m_materials[i];
|
2007-05-27 12:01:53 -04:00
|
|
|
}
|
|
|
|
|
2008-02-23 03:21:30 -05:00
|
|
|
// Add the new material
|
2009-02-26 19:15:09 -05:00
|
|
|
#ifdef HAVE_IRRLICHT
|
|
|
|
Material* m=new Material(fname, m_materials.size(), is_full_path);
|
|
|
|
#else
|
|
|
|
Material* m=new Material(fname, "", m_materials.size(), is_full_path);
|
|
|
|
#endif
|
2008-02-23 03:21:30 -05:00
|
|
|
m_materials.push_back(m);
|
2008-11-18 21:08:00 -05:00
|
|
|
if(make_permanent) m_shared_material_index = (int)m_materials.size();
|
2007-08-27 09:11:06 -04:00
|
|
|
return m ;
|
2008-02-23 03:21:30 -05:00
|
|
|
} // getMaterial
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
//=============================================================================
|
2009-02-26 19:15:09 -05:00
|
|
|
#ifndef HAVE_IRRLICHT
|
2007-05-27 12:01:53 -04:00
|
|
|
ssgState *getAppState ( char *fname )
|
|
|
|
{
|
|
|
|
Material *m = material_manager->getMaterial ( fname ) ;
|
|
|
|
return ( m == NULL ) ? NULL : m -> getState () ;
|
2008-02-23 03:21:30 -05:00
|
|
|
} // getAppState
|
2009-02-26 19:15:09 -05:00
|
|
|
#endif
|
2007-05-27 12:01:53 -04:00
|
|
|
|