/* * PlanetPenguin Racer * Copyright (C) 2004-2005 Volker Stroebel * * Copyright (C) 1999-2001 Jasmin F. Patry * * 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 2 * 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 "hier.h" #include "hier_util.h" #include "ppogl/base/defs.h" #include #include std::map nodes; std::map materials; /* * State variables */ /* Default Material */ Material g_hier_default_material ={ ppogl::Color(0., 0., 1.), /* diffuse color = blue */ ppogl::Color(0., 0., 0.), /* specular color = black */ 0.0 /* specular exp. = 0.0 */ }; /* * Functions used to access and update the name-to-pointer hash tables */ /* Add a new node name to the node name hash table. node_name contains the child's name only. */ static bool add_scene_node( const std::string& parent_name, const std::string& node_name, SceneNode *node ) { //int newEntry; // Add the current node to the hash table std::string new_name; if(parent_name==":"){ new_name = ":" + node_name; } else { new_name = parent_name + ":" + node_name; } nodes[new_name]=node; return true; } /* Get node pointer from node name */ bool get_scene_node(const std::string& node_name, SceneNode **node ) { std::map::iterator it; if((it=nodes.find(node_name))!=nodes.end()){ *node = (*it).second; }else{ if(node_name==":"){ //the root has been specified *node = 0; }else{ return false; } } return true; } /* Add a new material name to the material name hash table. */ void add_material(const std::string& mat_name, Material *mat) { materials[mat_name]=mat; } /* Get material pointer from material name */ bool get_material(const std::string& mat_name, Material **mat ) { std::map::iterator it; if((it=materials.find(mat_name))!=materials.end()){ *mat = (*it).second; return true; }else{ return false; } } /* Creates a new node, add the node to the hash table, and inserts the node into the DAG. Default values are given to all fields except the type-specific ones (geom, param). */ std::string create_scene_node(const std::string& parent_name, const std::string& child_name, SceneNode **node ) { SceneNode *parent, *child; if(get_scene_node(parent_name, &parent) != true){ return "Parent node does not exist"; } child = new SceneNode; PP_CHECK_ALLOC(child); /* Initialize node */ child->parent = parent; child->next = NULL; child->child = NULL; child->mat = NULL; child->render_shadow = true; child->eye = false; child->trans.makeIdentity(); child->invtrans.makeIdentity(); if(add_scene_node(parent_name, child_name, child ) != true){ delete child; return "Child already exists"; } /* Add node to parent's children */ if ( parent != NULL ) { if ( parent->child == NULL ) { parent->child = child; } else { for (parent = parent->child; parent->next != NULL; parent = parent->next) {/* do nothing */} parent->next = child; } } *node = child; return ""; } void reset_scene_node(const std::string& node) { SceneNode *nodePtr; if(get_scene_node( node, &nodePtr )!= true){ // node doesn't exist return; } nodePtr->trans.makeIdentity(); nodePtr->invtrans.makeIdentity(); } std::string rotate_scene_node(const std::string& node, char axis, double angle ) { SceneNode *nodePtr; pp::Matrix rotMatrix; if (get_scene_node( node, &nodePtr ) != true){ return "No such node"; } rotMatrix.makeRotation( angle, axis ); nodePtr->trans=nodePtr->trans*rotMatrix; rotMatrix.makeRotation( -angle, axis ); nodePtr->invtrans=rotMatrix*nodePtr->invtrans; return ""; } std::string translate_scene_node(const std::string& node, const ppogl::Vec3d& vec ) { SceneNode *nodePtr; pp::Matrix xlateMatrix; if(get_scene_node( node, &nodePtr ) != true){ return "No such node"; } xlateMatrix.makeTranslation( vec.x(), vec.y(), vec.z() ); nodePtr->trans=nodePtr->trans*xlateMatrix; xlateMatrix.makeTranslation( -vec.x(), -vec.y(), -vec.z() ); nodePtr->invtrans=xlateMatrix*nodePtr->invtrans; return ""; } std::string scale_scene_node(const std::string& node, const ppogl::Vec3d& center, const ppogl::Vec3d& factor) { SceneNode *nodePtr; pp::Matrix matrix; if(get_scene_node( node, &nodePtr ) != true){ return "No such node"; } matrix.makeTranslation( -center.x(), -center.y(), -center.z() ); nodePtr->trans=nodePtr->trans*matrix; matrix.makeTranslation( center.x(), center.y(), center.z() ); nodePtr->invtrans=matrix*nodePtr->invtrans; matrix.makeScaling( factor.values[0], factor.values[1], factor.values[2] ); nodePtr->trans=nodePtr->trans*matrix; matrix.makeScaling( 1./factor.values[0], 1./factor.values[1], 1./factor.values[2] ); nodePtr->invtrans=matrix*nodePtr->invtrans; matrix.makeTranslation( center.x(), center.y(), center.z() ); nodePtr->trans=nodePtr->trans*matrix; matrix.makeTranslation( -center.x(), -center.y(), -center.z() ); nodePtr->invtrans=matrix*nodePtr->invtrans; return ""; } std::string transform_scene_node(const std::string& node, const pp::Matrix& mat, const pp::Matrix& invmat ) { SceneNode *nodePtr; if(get_scene_node( node, &nodePtr ) != true){ return "No such node"; } nodePtr->trans=nodePtr->trans*mat; nodePtr->invtrans=invmat*nodePtr->invtrans; return ""; } std::string set_scene_node_material(const std::string& node, const std::string& mat) { Material *matPtr; SceneNode *nodePtr; if(get_scene_node(node, &nodePtr) != true){ return "No such node"; } if(get_material( mat, &matPtr ) != true){ return "No such material"; } nodePtr->mat = matPtr; return ""; } std::string set_scene_node_shadow_state(const std::string& node, const std::string& state) { SceneNode *nodePtr; if(get_scene_node(node, &nodePtr) != true){ return "No such node"; } if(state=="off"){ nodePtr->render_shadow = false; }else if(state=="on"){ nodePtr->render_shadow = true; } else { return "Shadow state must be 'on' or 'off'"; } return ""; } std::string set_scene_node_eye(const std::string& node, const std::string& which_eye ) { SceneNode *nodePtr; if(get_scene_node(node, &nodePtr) != true){ return "No such node"; } if (which_eye=="right" ){ nodePtr->eye = true; nodePtr->which_eye = TuxRightEye; }else if(which_eye == "left"){ nodePtr->eye = true; nodePtr->which_eye = TuxLeftEye; }else{ return "'eye' must be right or left"; } return ""; } std::string create_tranform_node(const std::string& parent_name, const std::string& child_name ) { SceneNode *node; std::string msg = create_scene_node(parent_name, child_name, &node); if (!msg.empty()){ return msg; } node->geom = Empty; return msg; } std::string create_sphere_node(const std::string& parent_name, const std::string& child_name, double resolution ) { SceneNode *node; std::string msg = create_scene_node(parent_name, child_name, &node); if(!msg.empty()){ return msg; } node->geom = Sphere; node->param.sphere.radius = 1.0; node->param.sphere.divisions = MIN( MAX_SPHERE_DIVISIONS, MAX( MIN_SPHERE_DIVISIONS, ROUND_TO_NEAREST(PPConfig.getInt("tux_sphere_divisions") * resolution ) ) ); return msg; } void create_material(const std::string& mat, const ppogl::Color& diffuse, const ppogl::Color& specular, double specular_exp ) { Material *matPtr; matPtr = new Material; PP_CHECK_ALLOC(matPtr); matPtr->diffuse.r() = diffuse.r(); matPtr->diffuse.g() = diffuse.g(); matPtr->diffuse.b() = diffuse.b(); matPtr->diffuse.a() = 1.0; matPtr->specular.r() = specular.r(); matPtr->specular.g() = specular.g(); matPtr->specular.b() = specular.b(); matPtr->specular.a() = 1.0; matPtr->specular_exp = specular_exp; add_material( mat, matPtr ); } void initialize_scene_graph() { /* Initialize state */ g_hier_default_material.diffuse.r() = 0.0; g_hier_default_material.diffuse.g() = 0.0; g_hier_default_material.diffuse.b() = 1.0; g_hier_default_material.diffuse.a() = 1.0; g_hier_default_material.specular.r() = 0.0; g_hier_default_material.specular.g() = 0.0; g_hier_default_material.specular.b() = 0.0; g_hier_default_material.specular.a() = 1.0; g_hier_default_material.specular_exp = 0.0; } void draw_scene_graph(const std::string& node) { SceneNode *nodePtr; if(get_scene_node( node, &nodePtr ) != true){ PP_ERROR( "draw_scene_graph: No such node: " << node); } traverse_dag( nodePtr, &g_hier_default_material ); } bool collide(const std::string& node, const ppogl::Polyhedron& ph) { SceneNode *nodePtr; pp::Matrix mat, invmat; mat.makeIdentity(); invmat.makeIdentity(); if(get_scene_node(node, &nodePtr) != true){ PP_ERROR( "draw_scene_graph: No such node: " << node ); } return check_polyhedron_collision_with_dag( nodePtr, mat, invmat, ph ); }