// $Id$ // // SuperTuxKart - a fun racing game with go-kart // Copyright (C) 2006 Joerg Henrichs // // This program 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 3 // 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 #include #include #include "user_config.hpp" #include "herring_manager.hpp" #include "file_manager.hpp" #include "loader.hpp" #include "material_manager.hpp" #include "material.hpp" #include "kart.hpp" #include "string_utils.hpp" #include "translation.hpp" #if defined(WIN32) && !defined(__CYGWIN__) # define snprintf _snprintf #endif /** Simple shadow class, only used here for default herrings. */ class Shadow { ssgBranch *sh ; public: Shadow ( float x1, float x2, float y1, float y2 ) ; ssgEntity *getRoot () { return sh ; } } ; // Shadow //----------------------------------------------------------------------------- Shadow::Shadow ( float x1, float x2, float y1, float y2 ) { ssgVertexArray *va = new ssgVertexArray () ; sgVec3 v ; ssgNormalArray *na = new ssgNormalArray () ; sgVec3 n ; ssgColourArray *ca = new ssgColourArray () ; sgVec4 c ; ssgTexCoordArray *ta = new ssgTexCoordArray () ; sgVec2 t ; sgSetVec4 ( c, 0.0f, 0.0f, 0.0f, 1.0f ) ; ca->add(c) ; sgSetVec3 ( n, 0.0f, 0.0f, 1.0f ) ; na->add(n) ; sgSetVec3 ( v, x1, y1, 0.10f ) ; va->add(v) ; sgSetVec3 ( v, x2, y1, 0.10f ) ; va->add(v) ; sgSetVec3 ( v, x1, y2, 0.10f ) ; va->add(v) ; sgSetVec3 ( v, x2, y2, 0.10f ) ; va->add(v) ; sgSetVec2 ( t, 0.0f, 0.0f ) ; ta->add(t) ; sgSetVec2 ( t, 1.0f, 0.0f ) ; ta->add(t) ; sgSetVec2 ( t, 0.0f, 1.0f ) ; ta->add(t) ; sgSetVec2 ( t, 1.0f, 1.0f ) ; ta->add(t) ; sh = new ssgBranch ; sh -> clrTraversalMaskBits ( SSGTRAV_ISECT|SSGTRAV_HOT ) ; sh -> setName ( "Shadow" ) ; ssgVtxTable *gs = new ssgVtxTable ( GL_TRIANGLE_STRIP, va, na, ta, ca ) ; gs -> clrTraversalMaskBits ( SSGTRAV_ISECT|SSGTRAV_HOT ) ; gs -> setState ( fuzzy_gst ) ; sh -> addKid ( gs ) ; sh -> ref () ; /* Make sure it doesn't get deleted by mistake */ } // Shadow //============================================================================= HerringManager* herring_manager; typedef std::map::const_iterator CI_type; HerringManager::HerringManager() { m_all_models.clear(); // The actual loading is done in loadDefaultHerrings } // HerringManager //----------------------------------------------------------------------------- void HerringManager::removeTextures() { for(AllHerringType::iterator i =m_all_herrings.begin(); i!=m_all_herrings.end(); i++) { delete *i; } m_all_herrings.clear(); for(CI_type i=m_all_models.begin(); i!=m_all_models.end(); ++i) { ssgDeRefDelete(i->second); } m_all_models.clear(); callback_manager->clear(CB_HERRING); } // removeTextures //----------------------------------------------------------------------------- HerringManager::~HerringManager() { for(CI_type i=m_all_models.begin(); i!=m_all_models.end(); ++i) { ssgDeRefDelete(i->second); } } // ~HerringManager //----------------------------------------------------------------------------- void HerringManager::loadDefaultHerrings() { // Load all models. This can't be done in the constructor, // since the file_manager isn't ready at that stage. // ------------------------------------------------------- std::set files; file_manager->listFiles(files, file_manager->getHerringDir(), /*is_full_path*/true, /*make_full_path*/true); for(std::set::iterator i = files.begin(); i != files.end(); ++i) { if(!StringUtils::has_suffix(*i, ".ac")) continue; ssgEntity* h = loader->load(*i, CB_HERRING, /*optimise*/true, /*full_path*/true); std::string shortName = StringUtils::basename(StringUtils::without_extension(*i)); h->ref(); h->setName(shortName.c_str()); m_all_models[shortName] = h; } // for i // Load the old, internal only models // ---------------------------------- sgVec3 yellow = { 1.0f, 1.0f, 0.4f }; CreateDefaultHerring(yellow, "OLD_GOLD" ); sgVec3 cyan = { 0.4f, 1.0f, 1.0f }; CreateDefaultHerring(cyan , "OLD_SILVER"); sgVec3 red = { 0.8f, 0.0f, 0.0f }; CreateDefaultHerring(red , "OLD_RED" ); sgVec3 green = { 0.0f, 0.8f, 0.0f }; CreateDefaultHerring(green , "OLD_GREEN" ); setDefaultHerringStyle(); } // loadDefaultHerrings //----------------------------------------------------------------------------- void HerringManager::setDefaultHerringStyle() { // This should go in an internal, system wide configuration file const std::string DEFAULT_NAMES[4] = {"bonusblock", "banana", "goldcoin", "silvercoin"}; bool bError=0; char msg[MAX_ERROR_MESSAGE_LENGTH]; for(int i=HE_RED; i<=HE_SILVER; i++) { m_herring_model[i] = m_all_models[DEFAULT_NAMES[i]]; if(!m_herring_model[i]) { snprintf(msg, sizeof(msg), "Herring model '%s' is missing (see herring_manager)!\n", DEFAULT_NAMES[i].c_str()); bError=1; break; } // if !m_herring_model } // for i if(bError) { fprintf(stderr, "The following models are available:\n"); for(CI_type i=m_all_models.begin(); i!=m_all_models.end(); ++i) { if(i->second) { if(i->first.substr(0,3)=="OLD") { fprintf(stderr," %s internally only.\n",i->first.c_str()); } else { fprintf(stderr, " %s in models/herrings/%s.ac.\n", i->first.c_str(), i->first.c_str()); } } // if i->second } throw std::runtime_error(msg); exit(-1); } // if bError } // setDefaultHerringStyle //----------------------------------------------------------------------------- Herring* HerringManager::newHerring(herringType type, const Vec3& xyz) { Herring* h = new Herring(type, xyz, m_herring_model[type]); m_all_herrings.push_back(h); return h; } // newHerring //----------------------------------------------------------------------------- void HerringManager::hitHerring(Kart* kart) { for(AllHerringType::iterator i =m_all_herrings.begin(); i!=m_all_herrings.end(); i++) { if((*i)->wasEaten()) continue; if((*i)->hitKart(kart)) { (*i)->isEaten(); kart->collectedHerring(*i); } // if hit } // for m_all_herrings } // hitHerring //----------------------------------------------------------------------------- /** Remove all herring instances, and the track specific models. This is used * just before a new track is loaded and a race is started. */ void HerringManager::cleanup() { for(AllHerringType::iterator i =m_all_herrings.begin(); i!=m_all_herrings.end(); i++) { delete *i; } m_all_herrings.clear(); setDefaultHerringStyle(); // Then load the default style from the user_config file // ----------------------------------------------------- // This way if a herring is not defined in the herringstyle-file, the // default (i.e. old herring) is used. try { // FIXME: This should go in a system-wide configuration file, // and only one of this and the hard-coded settings in // setDefaultHerringStyle are necessary!!! loadHerringStyle(user_config->m_herring_style); } catch(std::runtime_error) { fprintf(stderr,"The herring style '%s' in your configuration file does not exist.\nIt is ignored.\n", user_config->m_herring_style.c_str()); user_config->m_herring_style=""; } try { loadHerringStyle(m_user_filename); } catch(std::runtime_error) { fprintf(stderr,"The herring style '%s' specified on the command line does not exist.\nIt is ignored.\n", m_user_filename.c_str()); m_user_filename=""; // reset to avoid further warnings. } } // cleanup //----------------------------------------------------------------------------- /** Remove all herring instances, and the track specific models. This is used * just before a new track is loaded and a race is started */ void HerringManager::reset() { for(AllHerringType::iterator i =m_all_herrings.begin(); i!=m_all_herrings.end(); i++) { (*i)->reset(); } // for i } // reset //----------------------------------------------------------------------------- void HerringManager::update(float delta) { for(AllHerringType::iterator i =m_all_herrings.begin(); i!=m_all_herrings.end(); i++) { (*i)->update(delta); } // for m_all_herrings } // delta //----------------------------------------------------------------------------- void HerringManager::CreateDefaultHerring(sgVec3 colour, std::string name) { ssgVertexArray *va = new ssgVertexArray () ; sgVec3 v ; ssgNormalArray *na = new ssgNormalArray () ; sgVec3 n ; ssgColourArray *ca = new ssgColourArray () ; sgVec4 c ; ssgTexCoordArray *ta = new ssgTexCoordArray () ; sgVec2 t ; sgSetVec3(v, -0.5f, 0.0f, 0.0f ) ; va->add(v) ; sgSetVec3(v, 0.5f, 0.0f, 0.0f ) ; va->add(v) ; sgSetVec3(v, -0.5f, 0.0f, 0.5f ) ; va->add(v) ; sgSetVec3(v, 0.5f, 0.0f, 0.5f ) ; va->add(v) ; sgSetVec3(v, -0.5f, 0.0f, 0.0f ) ; va->add(v) ; sgSetVec3(v, 0.5f, 0.0f, 0.0f ) ; va->add(v) ; sgSetVec3(n, 0.0f, 1.0f, 0.0f ) ; na->add(n) ; sgCopyVec3 ( c, colour ) ; c[ 3 ] = 1.0f ; ca->add(c) ; sgSetVec2(t, 0.0f, 0.0f ) ; ta->add(t) ; sgSetVec2(t, 1.0f, 0.0f ) ; ta->add(t) ; sgSetVec2(t, 0.0f, 1.0f ) ; ta->add(t) ; sgSetVec2(t, 1.0f, 1.0f ) ; ta->add(t) ; sgSetVec2(t, 0.0f, 0.0f ) ; ta->add(t) ; sgSetVec2(t, 1.0f, 0.0f ) ; ta->add(t) ; ssgLeaf *gset = new ssgVtxTable ( GL_TRIANGLE_STRIP, va, na, ta, ca ) ; gset->setState(material_manager->getMaterial("herring.rgb")->getState()) ; Shadow* sh = new Shadow ( -0.5f, 0.5f, -0.25f, 0.25f ) ; ssgTransform* tr = new ssgTransform () ; tr -> addKid ( sh -> getRoot () ) ; tr -> addKid ( gset ) ; tr -> ref () ; /* Make sure it doesn't get deleted by mistake */ m_all_models[name] = tr; } // CreateDefaultHerring //----------------------------------------------------------------------------- void HerringManager::loadHerringStyle(const std::string filename) { if(filename.length()==0) return; const lisp::Lisp* root = 0; lisp::Parser parser; root = parser.parse(file_manager->getConfigFile(filename + ".herring")); const lisp::Lisp* herring_node = root->getLisp("herring"); if(!herring_node) { char msg[MAX_ERROR_MESSAGE_LENGTH]; snprintf(msg, sizeof(msg), "Couldn't load map '%s': no herring node.", filename.c_str()); delete root; throw std::runtime_error(msg); delete root; } setHerring(herring_node, "red", HE_RED ); setHerring(herring_node, "green", HE_GREEN ); setHerring(herring_node, "gold" ,HE_GOLD ); setHerring(herring_node, "silver",HE_SILVER); delete root; } // loadHerringStyle //----------------------------------------------------------------------------- void HerringManager::setHerring(const lisp::Lisp *herring_node, const char *colour, herringType type) { std::string name; herring_node->get(colour, name); if(name.size()>0) { m_herring_model[type]=m_all_models[name]; } } // setHerring