Back to index

extremetuxracer  0.5beta
hier.cpp
Go to the documentation of this file.
00001 /* 
00002  * PPRacer 
00003  * Copyright (C) 2004-2005 Volker Stroebel <volker@planetpenguin.de>
00004  * 
00005  * Copyright (C) 1999-2001 Jasmin F. Patry
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020  */
00021 
00022 #include "hier.h"
00023 #include "hier_util.h"
00024 #include "game_config.h"
00025 
00026 #include "ppgltk/alg/defs.h"
00027 
00028 /*
00029  * These hash tables map from names to node pointers and material data, resp.
00030  */
00031 Tcl_HashTable g_hier_node_table;
00032 Tcl_HashTable g_hier_material_table;
00033 
00034 
00035 /*
00036  * State variables
00037  */
00038 
00039 
00040 /* Default Material */
00041 material_t g_hier_default_material ={ 
00042                             pp::Color(0., 0., 1.),  /* diffuse color  = blue */
00043                             pp::Color(0., 0., 0.),  /* specular color = black */
00044                             0.0              /* specular exp. = 0.0 */
00045                      };
00046 /*
00047  * Functions used to access and update the name-to-pointer hash tables
00048  */
00049 
00050 /* Add a new node name to the node name hash table.
00051    node_name contains the child's name only. */
00052 static int 
00053 add_scene_node( const char *parent_name, const char *node_name, scene_node_t *node ) 
00054 {
00055     Tcl_HashEntry *entry;
00056     int newEntry;
00057     char new_name[1024];
00058 
00059     /* Add the current node to the hash table 
00060     */
00061     if (0 == strcmp(parent_name,":")) {
00062         sprintf(new_name, ":%s", node_name);
00063     } else {
00064         sprintf(new_name, "%s:%s", parent_name, node_name);
00065     }
00066 
00067     node->name = (char*)malloc( strlen(new_name) + 1 );
00068     node->name = strcpy(node->name, new_name);
00069 
00070     entry = Tcl_CreateHashEntry(&g_hier_node_table,new_name,&newEntry);
00071 
00072     if (newEntry) { 
00073         Tcl_SetHashValue(entry, node);
00074     } else {
00075         return TCL_ERROR;
00076     }
00077 
00078     return TCL_OK;
00079 }
00080 
00081 /* Get node pointer from node name */
00082 int 
00083 get_scene_node( const char *node_name, scene_node_t **node ) 
00084 {
00085     Tcl_HashEntry *entry;
00086   
00087     entry = Tcl_FindHashEntry(&g_hier_node_table, node_name);
00088     if (0 == entry) {
00089         if(0 == strcmp(node_name, ":")) {
00090             /* the root has been specified 
00091              */
00092             *node = 0;
00093         } else {
00094             return TCL_ERROR;
00095         }
00096     } else {
00097         *node = (scene_node_t*)Tcl_GetHashValue(entry);
00098     }
00099 
00100     return TCL_OK;
00101 }
00102 
00103 /* Add a new material name to the material name hash table. */
00104 int 
00105 add_material( const char *mat_name, material_t *mat ) 
00106 {
00107     Tcl_HashEntry *entry;
00108     int newEntry;
00109 
00110     entry = Tcl_CreateHashEntry(&g_hier_material_table,mat_name,&newEntry);
00111     if (newEntry) {
00112         Tcl_SetHashValue(entry, mat);
00113     } else {
00114         return TCL_ERROR;
00115     }
00116 
00117     return TCL_OK;
00118 }
00119 
00120 /* Get material pointer from material name */
00121 int 
00122 get_material( const char *mat_name, material_t **mat ) 
00123 {
00124     Tcl_HashEntry *entry;
00125 
00126     entry = Tcl_FindHashEntry(&g_hier_material_table, mat_name);
00127     if (0 == entry) {
00128         return TCL_ERROR;
00129     } else {
00130         *mat = (material_t*)Tcl_GetHashValue(entry);
00131     }
00132 
00133     return TCL_OK;
00134 }
00135 
00136 /* Creates a new node, add the node to the hash table, and inserts the
00137    node into the DAG.  Default values are given to all fields except
00138    the type-specific ones (geom, param).  */
00139 char* create_scene_node( const char *parent_name, const char *child_name, 
00140                       scene_node_t **node )
00141 {
00142     scene_node_t *parent, *child;
00143     if ( get_scene_node( parent_name, &parent ) != TCL_OK ) {
00144         return "Parent node does not exist";
00145     } 
00146 
00147     /* Create node */
00148     child = (scene_node_t *)malloc( sizeof( scene_node_t ) );
00149 
00150     /* Initialize node */
00151     child->parent = parent;
00152     child->next = NULL;
00153     child->child = NULL;
00154     child->mat = NULL;
00155     child->render_shadow = true;
00156     child->eye = false;
00157     child->trans.makeIdentity();
00158     child->invtrans.makeIdentity();
00159 
00160     if ( add_scene_node( parent_name, child_name, child ) != TCL_OK ) {
00161         free( child );
00162         return "Child already exists";
00163     } 
00164 
00165 
00166     /* Add node to parent's children */
00167     if ( parent != NULL ) {
00168         if ( parent->child == NULL ) {
00169             parent->child = child;
00170         } else {
00171             for (parent = parent->child; parent->next != NULL; 
00172                  parent = parent->next) {/* do nothing */}
00173             parent->next = child;
00174         } 
00175     } 
00176 
00177     *node = child;
00178     return NULL;
00179 } 
00180 
00181 char*
00182 reset_scene_node( char *node ) 
00183 {  
00184     scene_node_t *nodePtr;
00185 
00186     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00187         return "No such node";
00188     } 
00189 
00190     nodePtr->trans.makeIdentity();
00191     nodePtr->invtrans.makeIdentity();
00192 
00193     return NULL;
00194 }
00195 
00196 char*
00197 rotate_scene_node( const char *node, char axis, double angle ) 
00198 {
00199     scene_node_t *nodePtr;
00200     pp::Matrix rotMatrix;
00201 
00202     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00203         return "No such node";
00204     } 
00205 
00206     rotMatrix.makeRotation( angle, axis );
00207     nodePtr->trans=nodePtr->trans*rotMatrix;
00208        
00209     rotMatrix.makeRotation( -angle, axis );
00210     nodePtr->invtrans=rotMatrix*nodePtr->invtrans;
00211 
00212     return NULL;
00213 }
00214 
00215 char*
00216 translate_scene_node( const char *node, pp::Vec3d vec ) 
00217 {
00218     scene_node_t *nodePtr;
00219     pp::Matrix xlateMatrix;
00220 
00221     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00222         return "No such node";
00223     } 
00224 
00225     xlateMatrix.makeTranslation( vec.x, vec.y, vec.z );
00226        nodePtr->trans=nodePtr->trans*xlateMatrix;
00227        
00228     xlateMatrix.makeTranslation( -vec.x, -vec.y, -vec.z );
00229     nodePtr->invtrans=xlateMatrix*nodePtr->invtrans;
00230 
00231     return NULL;
00232 }
00233 
00234 char*
00235 scale_scene_node( const char *node, pp::Vec3d center, double factor[3] ) 
00236 {
00237     scene_node_t *nodePtr;
00238     pp::Matrix matrix;
00239 
00240     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00241         return "No such node";
00242     } 
00243 
00244     matrix.makeTranslation( -center.x, -center.y, -center.z );
00245     nodePtr->trans=nodePtr->trans*matrix;
00246        
00247     matrix.makeTranslation( center.x, center.y, center.z );
00248     nodePtr->invtrans=matrix*nodePtr->invtrans;
00249 
00250     matrix.makeScaling( factor[0], factor[1], factor[2] );
00251     nodePtr->trans=nodePtr->trans*matrix;
00252        
00253     matrix.makeScaling( 1./factor[0], 1./factor[1], 1./factor[2] );
00254     nodePtr->invtrans=matrix*nodePtr->invtrans;
00255 
00256     matrix.makeTranslation( center.x, center.y, center.z );
00257     nodePtr->trans=nodePtr->trans*matrix;
00258        
00259     matrix.makeTranslation( -center.x, -center.y, -center.z );
00260     nodePtr->invtrans=matrix*nodePtr->invtrans;
00261 
00262     return NULL;
00263 }
00264 
00265 char*
00266 transform_scene_node( char *node, pp::Matrix mat, pp::Matrix invmat ) 
00267 {
00268     scene_node_t *nodePtr;
00269 
00270     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00271         return "No such node";
00272     } 
00273 
00274     nodePtr->trans=nodePtr->trans*mat;
00275     nodePtr->invtrans=invmat*nodePtr->invtrans;
00276 
00277     return NULL;
00278 }
00279 
00280 char*
00281 set_scene_node_material( const char *node, const char *mat ) 
00282 {
00283     material_t *matPtr;
00284     scene_node_t *nodePtr;
00285 
00286     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00287         return "No such node";
00288     } 
00289 
00290     if ( get_material( mat, &matPtr ) != TCL_OK ) {
00291         return "No such material";
00292     } 
00293 
00294     nodePtr->mat = matPtr;
00295 
00296     return NULL;
00297 }
00298 
00299 char*
00300 set_scene_node_shadow_state( const char *node, const char *state ) 
00301 {
00302     scene_node_t *nodePtr;
00303 
00304     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00305         return "No such node";
00306     } 
00307 
00308     if ( strcmp( state, "off" ) == 0 ) {
00309        nodePtr->render_shadow = false;
00310     } else if ( strcmp ( state, "on" ) == 0 ) {
00311        nodePtr->render_shadow = true;
00312     } else {
00313        return "Shadow state must be 'on' or 'off'";
00314     }
00315 
00316     return NULL;
00317 }
00318 
00319 char*
00320 set_scene_node_eye( const char *node, const char *which_eye )
00321 {
00322     scene_node_t *nodePtr;
00323 
00324     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00325         return "No such node";
00326     } 
00327 
00328     if ( strcmp( which_eye, "right" ) == 0 ) {
00329        nodePtr->eye = true;
00330        nodePtr->which_eye = TuxRightEye;
00331     } else if ( strcmp ( which_eye, "left" ) == 0 ) {
00332        nodePtr->eye = true;
00333        nodePtr->which_eye = TuxLeftEye;
00334     } else {
00335        return "'eye' must be right or left";
00336     }
00337 
00338     return NULL;
00339 }
00340 
00341 char*
00342 create_tranform_node( const char *parent_name, const char *child_name ) 
00343 {
00344     scene_node_t *node;
00345     char *msg;
00346 
00347     msg = create_scene_node(parent_name, child_name, &node);
00348     if ( msg != NULL ) {
00349         return msg;
00350     } 
00351 
00352     node->geom = Empty;
00353 
00354     return NULL;
00355 }
00356 
00357 char*
00358 create_sphere_node( const char *parent_name, const char *child_name, double resolution ) 
00359 {
00360     scene_node_t *node;
00361     char *msg;
00362 
00363     msg = create_scene_node(parent_name, child_name, &node);
00364     if ( msg != NULL ) {
00365         return msg;
00366     } 
00367 
00368     node->geom = Sphere;
00369     node->param.sphere.radius = 1.0;
00370     node->param.sphere.divisions = MIN( 
00371        MAX_SPHERE_DIVISIONS, MAX( 
00372            MIN_SPHERE_DIVISIONS, 
00373            ROUND_TO_NEAREST( getparam_tux_sphere_divisions() * resolution ) 
00374            ) );
00375 
00376     return NULL;
00377 }
00378 
00379 char*
00380 create_material( const char *mat, pp::Color diffuse, 
00381                pp::Color specular, double specular_exp ) 
00382 {
00383     material_t *matPtr;
00384 
00385     matPtr = (material_t *)malloc( sizeof( material_t ) );
00386 
00387     matPtr->diffuse.r = diffuse.r;
00388     matPtr->diffuse.g = diffuse.g;
00389     matPtr->diffuse.b = diffuse.b;
00390     matPtr->diffuse.a = 1.0;
00391 
00392     matPtr->specular.r = specular.r;
00393     matPtr->specular.g = specular.g;
00394     matPtr->specular.b = specular.b;
00395     matPtr->specular.a = 1.0;
00396 
00397     matPtr->specular_exp = specular_exp;
00398 
00399     if ( add_material( mat, matPtr ) != TCL_OK ) {
00400         free( matPtr );
00401         return "Material already exists";
00402     } 
00403 
00404     return NULL;
00405 }
00406 
00407 void initialize_scene_graph() 
00408 {
00409     /* Initialize state */
00410 
00411     g_hier_default_material.diffuse.r = 0.0;
00412     g_hier_default_material.diffuse.g = 0.0;
00413     g_hier_default_material.diffuse.b = 1.0;
00414     g_hier_default_material.diffuse.a = 1.0;
00415 
00416     g_hier_default_material.specular.r = 0.0;
00417     g_hier_default_material.specular.g = 0.0;
00418     g_hier_default_material.specular.b = 0.0;
00419     g_hier_default_material.specular.a = 1.0;
00420 
00421     g_hier_default_material.specular_exp = 0.0;
00422 
00423     Tcl_InitHashTable(&g_hier_node_table,TCL_STRING_KEYS);
00424     Tcl_InitHashTable(&g_hier_material_table,TCL_STRING_KEYS);
00425 }
00426 
00427 void draw_scene_graph( char *node )
00428 {
00429     scene_node_t *nodePtr;
00430 
00431     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00432         handle_error( 1, "draw_scene_graph: No such node `%s'", node );
00433     } 
00434 
00435     traverse_dag( nodePtr, &g_hier_default_material );
00436     
00437 } 
00438 
00439 bool collide( char *node, pp::Polyhedron ph )
00440 {
00441     scene_node_t *nodePtr;
00442     pp::Matrix mat, invmat;
00443 
00444     mat.makeIdentity();
00445     invmat.makeIdentity();
00446 
00447     if ( get_scene_node( node, &nodePtr ) != TCL_OK ) {
00448         handle_error( 1, "draw_scene_graph: No such node `%s'", node );
00449     } 
00450 
00451     return check_polyhedron_collision_with_dag( nodePtr, mat, invmat, ph );
00452 }