db_anim.c

Go to the documentation of this file.
00001 /*                       D B _ A N I M . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1987-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup dbio */
00023 
00024 /*@{*/
00025 /** @file db_anim.c
00026  *  Routines to apply animation directives to geometry database.
00027  *
00028  *  Author -
00029  *      Michael John Muuss
00030  *
00031  *  Source -
00032  *      SECAD/VLD Computing Consortium, Bldg 394
00033  *      The U. S. Army Ballistic Research Laboratory
00034  *      Aberdeen Proving Ground, Maryland  21005-5066
00035  *
00036  */
00037 
00038 #ifndef lint
00039 static const char RCSanim[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/db_anim.c,v 14.11 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00040 #endif
00041 
00042 #include "common.h"
00043 
00044 #include <stdlib.h>
00045 #include <stdio.h>
00046 #ifdef HAVE_STRING_H
00047 #  include <string.h>
00048 #else
00049 #  include <strings.h>
00050 #endif
00051 #include <math.h>
00052 
00053 #include "machine.h"
00054 #include "vmath.h"
00055 #include "bu.h"
00056 #include "raytrace.h"
00057 #include "./debug.h"
00058 
00059 
00060 /**
00061  *                      D B _ A D D _ A N I M
00062  *
00063  *  Add a user-supplied animate structure to the end of the chain of such
00064  *  structures hanging from the directory structure of the last node of
00065  *  the path specifier.  When 'root' is non-zero, this matrix is
00066  *  located at the root of the tree itself, rather than an arc, and is
00067  *  stored differently.
00068  *
00069  *  In the future, might want to check to make sure that callers directory
00070  *  references are in the right database (dbip).
00071  */
00072 int
00073 db_add_anim(struct db_i *dbip, register struct animate *anp, int root)
00074 {
00075         register struct animate **headp;
00076         struct directory        *dp;
00077 
00078         /* Could validate an_type here */
00079 
00080         RT_CK_ANIMATE(anp);
00081         anp->an_forw = ANIM_NULL;
00082         if( root )  {
00083                 if( RT_G_DEBUG&DEBUG_ANIM )
00084                         bu_log("db_add_anim(x%x) root\n", anp);
00085                 headp = &(dbip->dbi_anroot);
00086         } else {
00087                 dp = DB_FULL_PATH_CUR_DIR(&anp->an_path);
00088                 if( RT_G_DEBUG&DEBUG_ANIM )
00089                         bu_log("db_add_anim(x%x) arc %s\n", anp,
00090                                 dp->d_namep);
00091                 headp = &(dp->d_animate);
00092         }
00093 
00094         /* Append to list */
00095         while( *headp != ANIM_NULL ) {
00096                 RT_CK_ANIMATE(*headp);
00097                 headp = &((*headp)->an_forw);
00098         }
00099         *headp = anp;
00100         return(0);                      /* OK */
00101 }
00102 
00103 static char     *db_anim_matrix_strings[] = {
00104         "(nope)",
00105         "ANM_RSTACK",
00106         "ANM_RARC",
00107         "ANM_LMUL",
00108         "ANM_RMUL",
00109         "ANM_RBOTH",
00110         "eh?"
00111 };
00112 
00113 /**
00114  *                      D B _ D O _ A N I M
00115  *
00116  *  Perform the one animation operation.
00117  *  Leave results in form that additional operations can be cascaded.
00118  *
00119  *  Note that 'materp' may be a null pointer, signifying that
00120  *  the region has already been finalized above this point in the tree.
00121  */
00122 int
00123 db_do_anim(register struct animate *anp, mat_t stack, mat_t arc, struct mater_info *materp)
00124 {
00125         mat_t   temp;
00126 
00127         if( RT_G_DEBUG&DEBUG_ANIM )
00128                 bu_log("db_do_anim(x%x) ", anp);
00129         if( RT_G_DEBUG&DEBUG_ANIM && !materp )  bu_log("(null materp) ");
00130         RT_CK_ANIMATE(anp);
00131         switch( anp->an_type )  {
00132         case RT_AN_MATRIX:
00133                 if( RT_G_DEBUG&DEBUG_ANIM )  {
00134                         int     op = anp->an_u.anu_m.anm_op;
00135                         if( op < 0 )  op = 0;
00136                         bu_log("matrix, op=%s (%d)\n",
00137                                 db_anim_matrix_strings[op], op);
00138                         if( RT_G_DEBUG&DEBUG_ANIM_FULL )  {
00139                                 bn_mat_print("on original arc", arc);
00140                                 bn_mat_print("on original stack", stack);
00141                         }
00142                 }
00143                 switch( anp->an_u.anu_m.anm_op )  {
00144                 case ANM_RSTACK:
00145                         MAT_COPY( stack, anp->an_u.anu_m.anm_mat );
00146                         break;
00147                 case ANM_RARC:
00148                         MAT_COPY( arc, anp->an_u.anu_m.anm_mat );
00149                         break;
00150                 case ANM_RBOTH:
00151                         MAT_COPY( stack, anp->an_u.anu_m.anm_mat );
00152                         MAT_IDN( arc );
00153                         break;
00154                 case ANM_LMUL:
00155                         /* arc = DELTA * arc */
00156                         bn_mat_mul( temp, anp->an_u.anu_m.anm_mat, arc );
00157                         MAT_COPY( arc, temp );
00158                         break;
00159                 case ANM_RMUL:
00160                         /* arc = arc * DELTA */
00161                         bn_mat_mul( temp, arc, anp->an_u.anu_m.anm_mat );
00162                         MAT_COPY( arc, temp );
00163                         break;
00164                 default:
00165                         return(-1);             /* BAD */
00166                 }
00167                 if( RT_G_DEBUG&DEBUG_ANIM_FULL )  {
00168                         bn_mat_print("arc result", arc);
00169                         bn_mat_print("stack result", stack);
00170                 }
00171                 break;
00172         case RT_AN_MATERIAL:
00173                 if( RT_G_DEBUG&DEBUG_ANIM )
00174                         bu_log("property\n");
00175                 /*
00176                  * if the caller does not care about property, a null
00177                  * mater pointer is given.
00178                  */
00179                 if (!materp)  {
00180                         char *sofar = db_path_to_string(&anp->an_path);
00181                         bu_log("ERROR db_do_anim(%s) property animation below region, ignored\n", sofar);
00182                         bu_free(sofar, "path string");
00183                         break;
00184                 }
00185                 if (anp->an_u.anu_p.anp_op == RT_ANP_REPLACE) {
00186                         if( materp->ma_shader ) bu_free( (genptr_t)materp->ma_shader, "ma_shader" );
00187                         materp->ma_shader = bu_vls_strdup(&anp->an_u.anu_p.anp_shader);
00188                 } else if (anp->an_u.anu_p.anp_op == RT_ANP_APPEND) {
00189                         struct bu_vls   str;
00190 
00191                         bu_vls_init(&str);
00192                         bu_vls_strcpy( &str, materp->ma_shader );
00193                         bu_vls_putc( &str, ' ' );
00194                         bu_vls_vlscat( &str, &anp->an_u.anu_p.anp_shader );
00195                         if( materp->ma_shader )  bu_free( (genptr_t)materp->ma_shader, "ma_shader" );
00196                         materp->ma_shader = bu_vls_strgrab( &str );
00197                         /* bu_vls_free( &str ) is done by bu_vls_strgrab() */
00198                 } else
00199                         bu_log("Unknown anp_op=%d\n", anp->an_u.anu_p.anp_op);
00200                 break;
00201         case RT_AN_COLOR:
00202                 if( RT_G_DEBUG&DEBUG_ANIM )
00203                         bu_log("color\n");
00204                 /*
00205                  * if the caller does not care about property, a null
00206                  * mater pointer is given.
00207                  */
00208                 if (!materp)  {
00209                         char *sofar = db_path_to_string(&anp->an_path);
00210                         bu_log("ERROR db_do_anim(%s) color animation below region, ignored\n", sofar);
00211                         bu_free(sofar, "path string");
00212                         break;
00213                 }
00214                 materp->ma_color_valid = 1;     /* XXX - really override? */
00215                 materp->ma_color[0] =
00216                     (((float)anp->an_u.anu_c.anc_rgb[0])+0.5)*bn_inv255;
00217                 materp->ma_color[1] =
00218                     (((float)anp->an_u.anu_c.anc_rgb[1])+0.5)*bn_inv255;
00219                 materp->ma_color[2] =
00220                     (((float)anp->an_u.anu_c.anc_rgb[2])+0.5)*bn_inv255;
00221                 break;
00222         case RT_AN_TEMPERATURE:
00223                 if( RT_G_DEBUG&DEBUG_ANIM )
00224                         bu_log("temperature = %g\n", anp->an_u.anu_t);
00225                 if (!materp)  {
00226                         char *sofar = db_path_to_string(&anp->an_path);
00227                         bu_log("ERROR db_do_anim(%s) temperature animation below region, ignored\n", sofar);
00228                         bu_free(sofar, "path string");
00229                         break;
00230                 }
00231                 materp->ma_temperature = anp->an_u.anu_t;
00232                 break;
00233         default:
00234                 if( RT_G_DEBUG&DEBUG_ANIM )
00235                         bu_log("unknown op\n");
00236                 /* Print something here? */
00237                 return(-1);                     /* BAD */
00238         }
00239         return(0);                              /* OK */
00240 }
00241 
00242 /**
00243  *                      D B _ F R E E _ 1 A N I M
00244  *
00245  *  Free one animation structure
00246  */
00247 void
00248 db_free_1anim( struct animate *anp )
00249 {
00250         RT_CK_ANIMATE( anp );
00251 
00252         switch( anp->an_type )  {
00253         case RT_AN_MATERIAL:
00254                 bu_vls_free( &anp->an_u.anu_p.anp_shader );
00255                 break;
00256         }
00257 
00258         db_free_full_path( &anp->an_path );
00259         bu_free( (char *)anp, "animate");
00260 }
00261 
00262 /**
00263  *                      D B _ F R E E _ A N I M
00264  *
00265  *  Release chain of animation structures
00266  *
00267  *  An unfortunate choice of name.
00268  */
00269 void
00270 db_free_anim(register struct db_i *dbip)
00271 {
00272         register struct animate *anp;
00273         register struct directory *dp;
00274         register int            i;
00275 
00276         /* Rooted animations */
00277         for( anp = dbip->dbi_anroot; anp != ANIM_NULL; )  {
00278                 register struct animate *nextanp;
00279                 RT_CK_ANIMATE(anp);
00280                 nextanp = anp->an_forw;
00281 
00282                 db_free_1anim( anp );
00283                 anp = nextanp;
00284         }
00285         dbip->dbi_anroot = ANIM_NULL;
00286 
00287         /* Node animations */
00288         for( i=0; i < RT_DBNHASH; i++ )  {
00289                 dp = dbip->dbi_Head[i];
00290                 for( ; dp != DIR_NULL; dp = dp->d_forw )  {
00291                         for( anp = dp->d_animate; anp != ANIM_NULL; )  {
00292                                 register struct animate *nextanp;
00293                                 RT_CK_ANIMATE(anp);
00294                                 nextanp = anp->an_forw;
00295 
00296                                 db_free_1anim( anp );
00297                                 anp = nextanp;
00298                         }
00299                         dp->d_animate = ANIM_NULL;
00300                 }
00301         }
00302 }
00303 
00304 /**
00305  *                      D B _ P A R S E _ 1 A N I M
00306  *
00307  *  Parse one "anim" type command into an "animate" structure.
00308  *  argv[1] must be the "a/b" path spec,
00309  *  argv[2] indicates what is to be animated on that arc.
00310  */
00311 struct animate  *
00312 db_parse_1anim(struct db_i *dbip, int argc, const char *argv[])
00313 {
00314         struct db_tree_state    ts;
00315         struct animate          *anp;
00316         int     i;
00317 
00318         BU_GETSTRUCT( anp, animate );
00319         anp->magic = ANIMATE_MAGIC;
00320 
00321         db_init_db_tree_state( &ts, dbip, &rt_uniresource );
00322         db_full_path_init( &anp->an_path );
00323         if( db_follow_path_for_state( &ts, &(anp->an_path), argv[1], LOOKUP_NOISY ) < 0 )
00324                 goto bad;
00325 
00326         if( strcmp( argv[2], "matrix" ) == 0 )  {
00327                 anp->an_type = RT_AN_MATRIX;
00328                 if( strcmp( argv[3], "rstack" ) == 0 )
00329                         anp->an_u.anu_m.anm_op = ANM_RSTACK;
00330                 else if( strcmp( argv[3], "rarc" ) == 0 )
00331                         anp->an_u.anu_m.anm_op = ANM_RARC;
00332                 else if( strcmp( argv[3], "lmul" ) == 0 )
00333                         anp->an_u.anu_m.anm_op = ANM_LMUL;
00334                 else if( strcmp( argv[3], "rmul" ) == 0 )
00335                         anp->an_u.anu_m.anm_op = ANM_RMUL;
00336                 else if( strcmp( argv[3], "rboth" ) == 0 )
00337                         anp->an_u.anu_m.anm_op = ANM_RBOTH;
00338                 else  {
00339                         bu_log("db_parse_1anim:  Matrix op '%s' unknown\n",
00340                                 argv[3]);
00341                         goto bad;
00342                 }
00343                 /* Allow some shorthands for the matrix spec */
00344                 if( strcmp( argv[4], "translate" ) == 0 ||
00345                     strcmp( argv[4], "xlate" ) == 0 )  {
00346                         if( argc < 5+2 )  {
00347                                 bu_log("db_parse_1anim:  matrix %s translate does not have enough arguments, only %d\n",
00348                                         argv[3], argc );
00349                                 goto bad;
00350                         }
00351                         MAT_IDN( anp->an_u.anu_m.anm_mat );
00352                         MAT_DELTAS( anp->an_u.anu_m.anm_mat,
00353                                 atof( argv[5+0] ),
00354                                 atof( argv[5+1] ),
00355                                 atof( argv[5+2] ) );
00356                 } else if( strcmp( argv[4], "rot" ) == 0 )  {
00357                         if( argc < 5+2 )  {
00358                                 bu_log("db_parse_1anim:  matrix %s rot does not have enough arguments, only %d\n",
00359                                         argv[3], argc );
00360                                 goto bad;
00361                         }
00362                         MAT_IDN( anp->an_u.anu_m.anm_mat );
00363                         bn_mat_angles( anp->an_u.anu_m.anm_mat,
00364                                 atof( argv[5+0] ),
00365                                 atof( argv[5+1] ),
00366                                 atof( argv[5+2] ) );
00367                 } else if( strcmp( argv[4], "scale" ) == 0 )  {
00368                         fastf_t scale;
00369                         if( argc < 5+0 )  {
00370                                 bu_log("db_parse_1anim:  matrix %s scale does not have enough arguments, only %d\n",
00371                                         argv[3], argc );
00372                                 goto bad;
00373                         }
00374                         scale = atof( argv[5+3] );
00375                         if( NEAR_ZERO( scale, SMALL ) )  {
00376                                 bu_log("db_parse_1anim:  matrix %s scale factor is zero\n",
00377                                         argv[3] );
00378                                 goto bad;
00379                         }
00380                         MAT_IDN( anp->an_u.anu_m.anm_mat );
00381                         anp->an_u.anu_m.anm_mat[15] = 1/scale;
00382                 } else if( strcmp( argv[4], "scale_about" ) == 0 )  {
00383                         point_t pt;
00384                         fastf_t scale;
00385                         if( argc < 5+3 )  {
00386                                 bu_log("db_parse_1anim:  matrix %s scale_about does not have enough arguments, only %d\n",
00387                                         argv[3], argc );
00388                                 goto bad;
00389                         }
00390                         VSET( pt,
00391                                 atof( argv[5+0] ),
00392                                 atof( argv[5+1] ),
00393                                 atof( argv[5+2] ) );
00394                         scale = atof( argv[5+3] );
00395                         if( bn_mat_scale_about_pt( anp->an_u.anu_m.anm_mat,
00396                             pt, scale ) < 0 )  {
00397                                 bu_log("db_parse_1anim: matrix %s scale_about (%g, %g, %g) scale=%g failed\n",
00398                                         argv[3], V3ARGS(pt), scale );
00399                                 goto bad;
00400                         }
00401                 } else {
00402                         /* No keyword, assume full 4x4 matrix */
00403                         for( i=0; i<16; i++ )
00404                                 anp->an_u.anu_m.anm_mat[i] = atof( argv[i+4] );
00405                 }
00406         } else if( strcmp( argv[2], "material" ) == 0 )  {
00407                 anp->an_type = RT_AN_MATERIAL;
00408                 bu_vls_init( &anp->an_u.anu_p.anp_shader );
00409                 if( (strcmp( argv[3], "replace" ) == 0) ||
00410                     (strcmp( argv[3], "rboth" ) == 0) )  {
00411                         bu_vls_from_argv( &anp->an_u.anu_p.anp_shader,
00412                                 argc-4, (const char **)&argv[4] );
00413                         anp->an_u.anu_p.anp_op = RT_ANP_REPLACE;
00414                 } else if( strcmp( argv[3], "append" ) == 0 )  {
00415                         bu_vls_from_argv( &anp->an_u.anu_p.anp_shader,
00416                                 argc-4, (const char **)&argv[4] );
00417                         anp->an_u.anu_p.anp_op = RT_ANP_APPEND;
00418                 } else {
00419                         bu_log("db_parse_1anim:  material animation '%s' unknown\n",
00420                                 argv[3]);
00421                         goto bad;
00422                 }
00423         } else if( strcmp( argv[2], "color" ) == 0 )  {
00424                 anp->an_type = RT_AN_COLOR;
00425                 anp->an_u.anu_c.anc_rgb[0] = atoi( argv[3+0] );
00426                 anp->an_u.anu_c.anc_rgb[1] = atoi( argv[3+1] );
00427                 anp->an_u.anu_c.anc_rgb[2] = atoi( argv[3+2] );
00428         } else if( strcmp( argv[2], "temperature" ) == 0 ||
00429                    strcmp( argv[2], "temp" ) == 0 )  {
00430                 anp->an_type = RT_AN_TEMPERATURE;
00431                 anp->an_u.anu_t = atof( argv[3] );
00432         } else {
00433                 bu_log("db_parse_1anim:  animation type '%s' unknown\n", argv[2]);
00434                 goto bad;
00435         }
00436         db_free_db_tree_state( &ts );
00437         return anp;
00438 bad:
00439         db_free_db_tree_state( &ts );
00440         db_free_1anim( anp );           /* Does db_free_full_path() for us */
00441         return (struct animate *)NULL;
00442 }
00443 
00444 /**
00445  *                      D B _ P A R S E _ A N I M
00446  *
00447  *  A common parser for mged and rt.
00448  *  Experimental.
00449  *  Not the best name for this.
00450  */
00451 int db_parse_anim(struct db_i   *dbip,
00452                 int             argc,
00453                 const char      **argv)
00454 {
00455         struct animate          *anp;
00456         int     at_root = 0;
00457 
00458         if( !(anp = db_parse_1anim( dbip, argc, argv )) )
00459                 return -1;      /* BAD */
00460 
00461         if( argv[1][0] == '/' )
00462                 at_root = 1;
00463 
00464         if( anp->an_path.fp_len > 1 )
00465                 at_root = 0;
00466 
00467         if( db_add_anim( dbip, anp, at_root ) < 0 )  {
00468                 return -1;      /* BAD */
00469         }
00470         return 0;               /* OK */
00471 }
00472 void
00473 db_write_anim(FILE *fop, struct animate *anp)
00474 {
00475         char *thepath;
00476         int i;
00477 
00478         RT_CK_ANIMATE(anp);
00479 
00480         thepath  = db_path_to_string(&(anp->an_path));
00481         if ( RT_G_DEBUG&DEBUG_ANIM) {
00482                 bu_log("db_write_anim: Writing %s\n", thepath);
00483         }
00484 
00485         fprintf(fop,"anim %s ", thepath);
00486         bu_free(thepath, "path string");
00487 
00488         switch (anp->an_type) {
00489         case RT_AN_MATRIX:
00490                 fputs("matrix ",fop);
00491                 switch (anp->an_u.anu_m.anm_op) {
00492                 case ANM_RSTACK:
00493                         fputs("rstack\n", fop);
00494                         break;
00495                 case ANM_RARC:
00496                         fputs("rarc\n", fop);
00497                         break;
00498                 case ANM_LMUL:
00499                         fputs("lmul\n", fop);
00500                         break;
00501                 case ANM_RMUL:
00502                         fputs("rmul\n", fop);
00503                         break;
00504                 case ANM_RBOTH:
00505                         fputs("rboth\n", fop);
00506                         break;
00507                 default:
00508                         fputs("unknown\n",fop);
00509                         bu_log("db_write_anim: unknown matrix operation\n");
00510                 }
00511                 for (i=0; i<16; i++) {
00512                         fprintf(fop, " %.15e", anp->an_u.anu_m.anm_mat[i]);
00513                         if ((i == 15) || ((i&3) == 3)) {
00514                                 fputs("\n",fop);
00515                         }
00516                 }
00517                 break;
00518         case RT_AN_MATERIAL:
00519                 fputs("material ",fop);
00520                 switch (anp->an_u.anu_p.anp_op) {
00521                 case RT_ANP_REPLACE:
00522                         fputs("replace ", fop);
00523                         break;
00524                 case RT_ANP_APPEND:
00525                         fputs("append ", fop);
00526                         break;
00527                 default:
00528                         bu_log("db_write_anim: unknown property operation.\n");
00529                         break;
00530                 }
00531                 break;
00532         case RT_AN_COLOR:
00533                 fprintf(fop,"color %d %d %d", anp->an_u.anu_c.anc_rgb[0],
00534                     anp->an_u.anu_c.anc_rgb[1], anp->an_u.anu_c.anc_rgb[2]);
00535                 break;
00536         case RT_AN_SOLID:
00537                 break;
00538         default:
00539                 bu_log("db_write_anim: Unknown animate type.\n");
00540         }
00541         fputs(";\n", fop);
00542         return;
00543 }
00544 
00545 /*@}*/
00546 /*
00547  * Local Variables:
00548  * mode: C
00549  * tab-width: 8
00550  * c-basic-offset: 4
00551  * indent-tabs-mode: t
00552  * End:
00553  * ex: shiftwidth=4 tabstop=8
00554  */

Generated on Mon Sep 18 01:24:49 2006 for BRL-CAD by  doxygen 1.4.6