Graphics.UsingTheDougNodeTclCommand - lordmundi/wikidoctest GitHub Wiki

Using the Node Tcl Commands

« Using the FOV overlay | EDGE User’s Guide | Using the doug callback command »

EDGE provides an extensive tcl scripting ability to DSP.

The doug.node command can be used to manipulate or query any node in the scene.

Simple Directions

The doug.node commands are best explained via examples. The following example commands should illustrate most of the usage:

doug.node camA get
doug.node ONYX_morb2 set -cam_tilt 10 -x 32 -y 20 -z 300 -pitch 320.0 -order TPYR -flags "!HIDE ~FLASH HIGHLIGHT" -parent NULL -layer BACKGROUND
doug.node ORBITER_STRUCTURE set -flags "HIDETREE" -parent NULL -layer BACKGROUND
doug.node ONYX_morb2 set -cam_tilt 10 -x 32 -y 20 -z 300 -pitch 320.0 -order TPYR -user_flags "!1 3 ~4" -parent NULL -layer BACKGROUND
doug.node ONYX_morb2 set -tree_flags "!HIDE ~FLASH HIGHLIGHT" -mod_wash_col #ff0000 -mod_flash_col #0000ff
doug.node ONYX_morb2 set -parent "ONYX_morb2 0 0 0 180 0 180" -layer BACKGROUND
doug.node ONYX_morb2 map -cam_tilt tiltvar -x xvar -y yvar
doug.node ONYX_morb2 get -cam_tilt
doug.node camA get -cam_fov
doug.node camA set -cam_fov 55.0
doug.node ONYX_morb2 get -cam_zoom
doug.node ONYX_morb2 get -type
doug.node ONYX_morb2 get -parent
doug.node ONYX_morb2 get -flags
doug.node ONYX_morb2 get -user_flags
doug.node ONYX_morb2 get -parent
doug.node ONYX_morb2 test "HIDE FLASH"
doug.node ONYX_morb2 animate -x -units 0.3 -samples 10 -reverse 1 -enabled 1
doug.node camA limit -cam_fov -interval 5.0 72.1  -enabled 1
doug.node camA animate -cam_fov -units 7 -samples 120 -scalvar svar -enabled 1
doug.node JIMBO animate -rel_yaw   -unitvar rot_rate -scale -1 -samples 120 -enabled 1
doug.node JIMBO animate -rel_pitch -units 15 -samples 10 -enabled 1
doug.node JIMBO animate -rel_roll  -units 15 -samples 10 -enabled 1
doug.node JIMBO animate -rel_x     -units 32 -samples 10 -enabled 1
doug.node JIMBO animate -rel_y     -units 32 -samples 10 -enabled 1
doug.node JIMBO animate -rel_z     -units 32 -samples 10 -enabled 1
doug.node JIMBO animate -rel_z     -rate 32 -samples 120 -enabled 1
doug.node ONYX_morb2 limit -parent -enabled 1
doug.node ONYX_morb2 limit -x     -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -y     -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -z     -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -pitch -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -yaw   -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -roll  -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -cam_tilt  -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -cam_pan   -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -cam_spin  -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -cam_zoom  -interval .1 100 -enabled 1
doug.node camA get -state
doug.node camA set -state "xyzPYRtpszaf ......."
doug.node camA set -state "xyz 1"
doug.node LP_light1 set -lit_col #ffffff
doug.node JIMBO get -kids
doug.node JIMBO get -order

What's really going on

If the above examples are not enough info, or you need more information about a particular option, the source code implementing the doug.node command is below:

[Show DOUG_NODE_cmd source code][4]

int
DOUG_NODE_cmd( ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] )
{
#if 0
doug.node camA get
doug.node ONYX_morb2 set -cam_tilt 10 -x 32 -y 20 -z 300 -pitch 320.0 -order TPYR -flags "!HIDE ~FLASH HIGHLIGHT" -parent NULL -layer BACKGROUND
doug.node ORBITER_STRUCTURE set -flags "HIDETREE" -parent NULL -layer BACKGROUND
doug.node ONYX_morb2 set -cam_tilt 10 -x 32 -y 20 -z 300 -pitch 320.0 -order TPYR -user_flags "!1 3 ~4" -parent NULL -layer BACKGROUND
doug.node ONYX_morb2 set -tree_flags "!HIDE ~FLASH HIGHLIGHT" -mod_wash_col #ff0000 -mod_flash_col #0000ff
doug.node ONYX_morb2 set -parent "ONYX_morb2 0 0 0 180 0 180" -layer BACKGROUND
doug.node ONYX_morb2 map -cam_tilt tiltvar -x xvar -y yvar
doug.node ONYX_morb2 get -cam_tilt
doug.node camA get -cam_fov
doug.node camA set -cam_fov 55.0
doug.node ONYX_morb2 get -cam_zoom
doug.node ONYX_morb2 get -type
doug.node ONYX_morb2 get -parent
doug.node ONYX_morb2 get -flags
doug.node ONYX_morb2 get -user_flags
doug.node ONYX_morb2 get -parent
doug.node ONYX_morb2 test "HIDE FLASH"
doug.node ONYX_morb2 animate -x -units 0.3 -samples 10 -reverse 1 -enabled 1
doug.node camA limit -cam_fov -interval 5.0 72.1  -enabled 1
doug.node camA animate -cam_fov -units 7 -samples 120 -scalvar svar -enabled 1
doug.node JIMBO animate -rel_yaw   -unitvar rot_rate -scale -1 -samples 120 -enabled 1
doug.node JIMBO animate -rel_pitch -units 15 -samples 10 -enabled 1
doug.node JIMBO animate -rel_roll  -units 15 -samples 10 -enabled 1
doug.node JIMBO animate -rel_x     -units 32 -samples 10 -enabled 1
doug.node JIMBO animate -rel_y     -units 32 -samples 10 -enabled 1
doug.node JIMBO animate -rel_z     -units 32 -samples 10 -enabled 1
doug.node JIMBO animate -rel_z     -rate 32 -samples 120 -enabled 1
doug.node ONYX_morb2 limit -parent -enabled 1
doug.node ONYX_morb2 limit -x     -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -y     -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -z     -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -pitch -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -yaw   -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -roll  -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -cam_tilt  -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -cam_pan   -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -cam_spin  -interval -30 30 -enabled 1
doug.node ONYX_morb2 limit -cam_zoom  -interval .1 100 -enabled 1
doug.node camA get -state
doug.node camA set -state "xyzPYRtpszaf ......."
doug.node camA set -state "xyz 1.0 2.0 30.0"
#endif

#   define NODE_SET             0x0001
#   define NODE_GET             0x0002
#   define NODE_TEST            0x0003
#   define NODE_ANIMATE         0x0004
#   define NODE_LIMIT           0x0005
#   define NODE_MAP             0x0007
#   define NODE_INTERVAL        0x0100
#   define NODE_FLAGS           0x0200
#   define NODE_LAYER           0x0300
#   define NODE_TREE_FLAGS      0x0400
#   define NODE_USER_FLAGS      0x0800
#   define NODE_STATE           0x1000

#   define BYTE_OFFSET(P)       (((char*)(&node_str.P)) - ((char*)(&node_str)))
    static char buff[2048];
    static int first_pass = 1;
    static Tcl_HashTable commands;
    static Tcl_HashTable options;
    static Tcl_HashTable rel_params;
    static Tcl_HashTable double_params;
    static Tcl_HashTable double_camparams;
    static Tcl_HashTable proc_camparams;
    static Tcl_HashTable proc_nodeparams;
    static Tcl_HashTable proc_modparams;
    static Tcl_HashTable proc_litparams;
    static Tcl_HashTable int_params;
    static Tcl_HashTable fparams;
    static Tcl_HashTable fbits;
    static DSS_NODE node_str;
    DOUG_ANIMATE_CMD *panim;
    DOUG_LIMIT_PARAM *plim;
    int i, id, new_item;
    char *sep = " \n\t,;";
    char *tok_ptr;
    char *tok;
    DSS_NODE *pn;
    Tcl_HashEntry *entry;
    double *pdouble;
    float *pfloat;
    char *tcl_cmdstr;
    int *pint;
    int fval;
    int reltype;
    DOUG_NODE_VAR *pnvar;
	int	build_matrix = 0;

    Tcl_ResetResult( interp );

    if( first_pass )
    {
        Tcl_InitHashTable( &commands,           TCL_STRING_KEYS );
        Tcl_InitHashTable( &options,            TCL_STRING_KEYS );
        Tcl_InitHashTable( &double_params,      TCL_STRING_KEYS );
        Tcl_InitHashTable( &double_camparams,   TCL_STRING_KEYS );
        Tcl_InitHashTable( &proc_camparams,     TCL_STRING_KEYS );
        Tcl_InitHashTable( &proc_nodeparams,    TCL_STRING_KEYS );
        Tcl_InitHashTable( &proc_modparams,   	TCL_STRING_KEYS );
        Tcl_InitHashTable( &proc_litparams,     TCL_STRING_KEYS );
        Tcl_InitHashTable( &int_params,         TCL_STRING_KEYS );
        Tcl_InitHashTable( &fparams,            TCL_STRING_KEYS );
        Tcl_InitHashTable( &fbits,              TCL_STRING_KEYS );
        Tcl_InitHashTable( &rel_params,         TCL_STRING_KEYS );

		/* GENERIC NODE COMMANDS */
        Tcl_SetHashValue( Tcl_CreateHashEntry( &commands, "set",        &new_item ), NODE_SET                   );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &commands, "map",        &new_item ), NODE_MAP                   );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &commands, "get",        &new_item ), NODE_GET                   );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &commands, "test",       &new_item ), NODE_TEST                  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &commands, "animate",    &new_item ), NODE_ANIMATE               );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &commands, "limit",      &new_item ), NODE_LIMIT                 );

		/* GENERIC NODE PARAMETERS */
        Tcl_SetHashValue( Tcl_CreateHashEntry( &options, "-interval",   &new_item ), NODE_INTERVAL              );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &options, "-flags",      &new_item ), NODE_FLAGS                 );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &options, "-user_flags", &new_item ), NODE_USER_FLAGS            );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &options, "-tree_flags", &new_item ), NODE_TREE_FLAGS            );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &options, "-layer",      &new_item ), NODE_LAYER                 );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &options, "-state",      &new_item ), NODE_STATE                 );

		/* GENERIC NODE POSSITION/ATTITUDE PARAMETERS */
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_params,      "-x",         &new_item ), BYTE_OFFSET(x)     );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_params,      "-y",         &new_item ), BYTE_OFFSET(y)     );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_params,      "-z",         &new_item ), BYTE_OFFSET(z)     );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_params,      "-pitch",     &new_item ), BYTE_OFFSET(P)     );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_params,      "-yaw",       &new_item ), BYTE_OFFSET(Y)     );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_params,      "-roll",      &new_item ), BYTE_OFFSET(R)     );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_nodeparams,    "-x",         &new_item ), NODE_X             );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_nodeparams,    "-y",         &new_item ), NODE_Y             );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_nodeparams,    "-z",         &new_item ), NODE_Z             );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_nodeparams,    "-pitch",     &new_item ), NODE_PITCH         );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_nodeparams,    "-yaw",       &new_item ), NODE_YAW           );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_nodeparams,    "-roll",      &new_item ), NODE_ROLL          );

		/* MODEL SPECIFIC PARAMETERS */
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_wash_col",     &new_item ), MOD_WASH_COL      );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_wash_col_r",   &new_item ), MOD_WASH_COL_R    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_wash_col_g",   &new_item ), MOD_WASH_COL_G    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_wash_col_b",   &new_item ), MOD_WASH_COL_B    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_flash_col",    &new_item ), MOD_FLASH_COL     );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_flash_col_r",  &new_item ), MOD_FLASH_COL_R   );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_flash_col_g",  &new_item ), MOD_FLASH_COL_G   );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_flash_col_b",  &new_item ), MOD_FLASH_COL_B   );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_high_col",     &new_item ), MOD_HIGH_COL      );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_high_col_r",   &new_item ), MOD_HIGH_COL_R    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_high_col_g",   &new_item ), MOD_HIGH_COL_G    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_high_col_b",   &new_item ), MOD_HIGH_COL_B    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_coll_col",     &new_item ), MOD_COLL_COL      );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_coll_col_r",   &new_item ), MOD_COLL_COL_R    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_coll_col_g",   &new_item ), MOD_COLL_COL_G    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_coll_col_b",   &new_item ), MOD_COLL_COL_B    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_model_set",    &new_item ), MOD_MODEL_SET     );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_lod_override", &new_item ), MOD_LOD_OVERRIDE  );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_lod_select",   &new_item ), MOD_LOD_SELECT    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_priority",     &new_item ), MOD_PRIORITY      );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_anim_speed",   &new_item ), MOD_ANIM_SPEED    );
		Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_modparams,   	"-mod_anim_time",    &new_item ), MOD_ANIM_TIME     );

		/* CAMERA SPECIFIC PARAMETERS */
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_camparams,   "-cam_tilt", 	&new_item ), BYTE_OFFSET(data.cam.tilt) );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_camparams,   "-cam_pan",  	&new_item ), BYTE_OFFSET(data.cam.pan)  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_camparams,   "-cam_spin", 	&new_item ), BYTE_OFFSET(data.cam.spin) );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &double_camparams,   "-cam_zoom", 	&new_item ), BYTE_OFFSET(data.cam.zoom) );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_camparams,     "-cam_tilt",    &new_item ), CAM_TILT 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_camparams,     "-cam_pan",     &new_item ), CAM_PAN 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_camparams,     "-cam_spin",    &new_item ), CAM_SPIN 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_camparams,     "-cam_zoom",    &new_item ), CAM_ZOOM 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_camparams,     "-cam_fov",     &new_item ), CAM_FOV 					);

		/* LIGHT SPECIFIC PARAMETERS */
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_col",     &new_item ), LIT_COL 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_col_r",   &new_item ), LIT_COL_R 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_col_g",   &new_item ), LIT_COL_G 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_col_b",   &new_item ), LIT_COL_B 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_int",     &new_item ), LIT_INT 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_dir",     &new_item ), LIT_DIR 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_dir_x",   &new_item ), LIT_DIR_X 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_dir_y",   &new_item ), LIT_DIR_Y 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_dir_z",   &new_item ), LIT_DIR_Z 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_exp",     &new_item ), LIT_EXP 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_ang",     &new_item ), LIT_ANG 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &proc_litparams,     "-lit_type",    &new_item ), LIT_TYPE 					);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &int_params, 		"-parent",  	&new_item ), BYTE_OFFSET(parent_id)     );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &int_params, 		"-order",   	&new_item ), BYTE_OFFSET(order)         );

        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"LOCAL", 		&new_item ), BYTE_OFFSET(flags)    		);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"WIRE",    		&new_item ), BYTE_OFFSET(flags)         );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"SOLID", 		&new_item ), BYTE_OFFSET(flags)    		);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"POINT", 		&new_item ), BYTE_OFFSET(flags)    		);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"TRANSPARENT", 	&new_item ), BYTE_OFFSET(flags)         );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"BEST", 		&new_item ), BYTE_OFFSET(flags)    		);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"COLOR", 		&new_item ), BYTE_OFFSET(flags)    		);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"CULLED",  		&new_item ), BYTE_OFFSET(flags)         );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"COLORWASH", 	&new_item ), BYTE_OFFSET(flags)         );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"NOCULL",  		&new_item ), BYTE_OFFSET(flags)         );

        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"LOCAL",      	&new_item ), DSD_LOCAL_FLAG              );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"WIRE",      	&new_item ), DSD_WIRE_FLAG              );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"SOLID",      	&new_item ), DSD_SOLID_FLAG              );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"POINT",      	&new_item ), DSD_POINT_FLAG              );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"TRANSPARENT",  &new_item ), DSD_TRANSPARENT_FLAG       );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"BEST",  		&new_item ), DSD_BEST_FLAG       		);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"COLOR",  		&new_item ), DSD_COLOR_FLAG       		);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"CULLED",  		&new_item ), DSD_CULLED_FLAG       		);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"COLORWASH",   	&new_item ), DSD_COLORWASH_FLAG         );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"NOCULL",      	&new_item ), DSD_NOCULL_FLAG            );

        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"HIDE",     	&new_item ), BYTE_OFFSET(attrib)        );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"FLASH",     	&new_item ), BYTE_OFFSET(attrib)        );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"HIGHLIGHT", 	&new_item ), BYTE_OFFSET(attrib)        );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"COLLISION",  	&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"TRACE",   		&new_item ), BYTE_OFFSET(attrib)        );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"HIDETRACE",   	&new_item ), BYTE_OFFSET(attrib)        );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"HIDE_TRACE",   	&new_item ), BYTE_OFFSET(attrib)        );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"CAMINFO",  	&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"MATRIX",    	&new_item ), BYTE_OFFSET(attrib)        );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"MIRROR",  		&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"PROCESSED",	&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"DOUBLE",		&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"TEXTUREMATRIX", &new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"TEXTURE_MATRIX", &new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"STATIC",  		&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"DYNAMIC",  	&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"CROSSHAIR",  	&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"LOADMETER",  	&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"SIGSCREEN",   	&new_item ), BYTE_OFFSET(attrib)        );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"NOZOOM",  		&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"NOOVERLAY",  	&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"UPDATECOLOR", 	&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"UPDATE_COLOR", 	&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"INHIBITCONTROL",&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"INHIBIT_CONTROL",&new_item ), BYTE_OFFSET(attrib)    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fparams, 			"HIDETREE",     &new_item ), BYTE_OFFSET(attrib)        );

        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"HIDE",      	&new_item ), DSD_HIDE_ATTRIB            );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"FLASH",     	&new_item ), DSD_FLASH_ATTRIB           );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"HIGHLIGHT", 	&new_item ), DSD_HIGHLIGHT_ATTRIB       );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"COLLISION", 	&new_item ), DSD_COLLISION_ATTRIB       );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"TRACE",   		&new_item ), DSD_TRACE_ATTRIB      		);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"HIDETRACE",   	&new_item ), DSD_HIDE_TRACE_ATTRIB      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"HIDET_RACE",  	&new_item ), DSD_HIDE_TRACE_ATTRIB      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"CAMINFO",   	&new_item ), DSD_CAMINFO_ATTRIB      	);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"MATRIX",    	&new_item ), DSD_MATRIX_ATTRIB          );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"MIRROR",    	&new_item ), DSD_MIRROR_ATTRIB          );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"PROCESSED",   	&new_item ), DSD_PROCESSED_ATTRIB       );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"DOUBLE",   	&new_item ), DSD_DOUBLE_ATTRIB          );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"TEXTUREMATRIX", &new_item ), DSD_TEXTURE_MATRIX_ATTRIB  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"TEXTURE_MATRIX", &new_item ), DSD_TEXTURE_MATRIX_ATTRIB  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"STATIC",   	&new_item ), DSD_STATIC_ATTRIB  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"DYNAMIC",   	&new_item ), DSD_DYNAMIC_ATTRIB  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"CROSSHAIR",   	&new_item ), DSD_CROSSHAIR_ATTRIB  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"LOADMETER",   	&new_item ), DSD_LOADMETER_ATTRIB  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"SIGSCREEN",   	&new_item ), DSD_SIGSCREEN_ATTRIB      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"NOZOOM",   	&new_item ), DSD_NOZOOM_ATTRIB      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"NOOVERLAY",   	&new_item ), DSD_NOOVERLAY_ATTRIB      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"UPDATECOLOR",  &new_item ), DSD_UPDATE_COLOR_ATTRIB      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"UPDATE_COLOR",  &new_item ), DSD_UPDATE_COLOR_ATTRIB      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"INHIBITCONTROL",  &new_item ), DSD_INHIBIT_CONTROL_ATTRIB  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"INHIBIT_CONTROL",  &new_item ), DSD_INHIBIT_CONTROL_ATTRIB  );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &fbits, 				"HIDETREE",     &new_item ), DSD_HIDETREE_ATTRIB        );

        Tcl_SetHashValue( Tcl_CreateHashEntry( &rel_params, 		"-rel_x",   	&new_item ), REL_X                      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &rel_params, 		"-rel_y",   	&new_item ), REL_Y                      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &rel_params, 		"-rel_z",   	&new_item ), REL_Z                      );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &rel_params, 		"-rel_pitch",	&new_item ), REL_PITCH                 	);
        Tcl_SetHashValue( Tcl_CreateHashEntry( &rel_params, 		"-rel_yaw", 	&new_item ), REL_YAW                    );
        Tcl_SetHashValue( Tcl_CreateHashEntry( &rel_params, 		"-rel_roll",	&new_item ), REL_ROLL                   );

        first_pass = 0;
    }

    /* PROCESS INCREMENT */
    /* IF VALID NODE SPECIFIED */
    i = 1;
    if( (id = DSF_GetNodeID( Tcl_GetString( objv[i] ) )) > -1 )
    {
        pn = DSV_scene->node_list + id;
        i++;
        tcl_cmdstr = Tcl_GetString( objv[i] );
        if( entry = Tcl_FindHashEntry( &commands, tcl_cmdstr ) )
        {
            i++;
            switch( (int)Tcl_GetHashValue( entry ) )
            {
            case NODE_SET: /* PARSE SET COMMANDS */
                {
					DSF_BgnModifyScene( DSV_scene );

                    while( i < objc )
                    {
                        tcl_cmdstr = Tcl_GetString( objv[i] );
                        if( entry = Tcl_FindHashEntry( &options, tcl_cmdstr ) )
                        {
                            i++;
                            switch( (int)Tcl_GetHashValue( entry ) )
                            {
                            case NODE_FLAGS:
                                strcpy( buff, Tcl_GetString( objv[i] ) );
                                i++;
                                tok_ptr = 0;
                                tok = DSF_strtok_r( buff, sep, &tok_ptr );
                                while( tok )
                                {
                                    /* IF CLEAR/TOGGLE FLAG */
                                    if( tok[0] == '!' || tok[0] == '~' )
                                    {
                                        if( entry = Tcl_FindHashEntry( &fbits, &tok[1] ) )
                                        {
                                            fval = (int)Tcl_GetHashValue( entry );
                                        }
                                        else
                                        {
                                            Tcl_AppendResult( interp, "doug.node ", pn->name, " set -flags (unknown flag \"", &tok[1], "\")", NULL );
											DSF_EndModifyScene( DSV_scene );
                                            return TCL_ERROR;
                                        }

                                        if( entry = Tcl_FindHashEntry( &fparams, &tok[1] ) )
                                        {
                                            pint = (int*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

                                            /* IF CLEAR FLAG */
                                            if( tok[0] == '!' )
                                                *pint &= ~fval;
                                            /* ELSE TOGGLE FLAG */
                                            else
                                                *pint = (*pint & ~fval) | ((~(*pint)) & fval);
                                        }
                                    }
                                    /* SET FLAG */
                                    else
                                    {
                                        if( entry = Tcl_FindHashEntry( &fbits, tok ) )
                                        {
                                            fval = (int)Tcl_GetHashValue( entry );
                                        }
                                        else
                                        {
                                            Tcl_AppendResult( interp, "doug.node ", pn->name, " set -flags (unknown flag \"", &tok[1], "\")", NULL );
											DSF_EndModifyScene( DSV_scene );
                                            return TCL_ERROR;
                                        }

                                        if( entry = Tcl_FindHashEntry( &fparams, tok ) )
                                        {
                                            pint = (int*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));
                                            *pint |= fval;
                                        }
                                    }

                                    tok = DSF_strtok_r( 0L, sep, &tok_ptr );
                                }
								build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);
								DSF_ModifiedNode( id, DSD_FLAGS_MODIFIED|DSD_ATTRIB_MODIFIED );
                                break;

                            case NODE_USER_FLAGS:
                                strcpy( buff, Tcl_GetString( objv[i] ) );
                                i++;
                                tok_ptr = 0;
                                tok = DSF_strtok_r( buff, sep, &tok_ptr );
                                while( tok )
                                {
                                    /* IF CLEAR/TOGGLE FLAG */
                                    if( tok[0] == '!' || tok[0] == '~' )
                                    {
										fval = (0x1 << atoi(&tok[1]));

										/* IF CLEAR FLAG */
										if( tok[0] == '!' )
											pn->user_flags &= ~fval;

										/* ELSE TOGGLE FLAG */
										else
											pn->user_flags = (pn->user_flags & ~fval) | ((~(pn->user_flags)) & fval);
                                    }
                                    /* SET FLAG */
                                    else
                                    {
										fval = (0x1 << atoi(tok));
										pn->user_flags |= fval;
                                    }

                                    tok = DSF_strtok_r( 0L, sep, &tok_ptr );
                                }
								build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);
								DSF_ModifiedNode( id, DSD_USERFLAGS_MODIFIED|DSD_ATTRIB_MODIFIED );
                                break;


                            case NODE_TREE_FLAGS:
                                strcpy( buff, Tcl_GetString( objv[i] ) );
                                i++;
                                tok_ptr = 0;
                                tok = DSF_strtok_r( buff, sep, &tok_ptr );
                                while( tok )
                                {
                                    /* IF CLEAR/TOGGLE FLAG */
                                    if( tok[0] == '!' || tok[0] == '~' )
                                    {
                                        if( entry = Tcl_FindHashEntry( &fbits, &tok[1] ) )
                                        {
                                            fval = (int)Tcl_GetHashValue( entry );
                                        }
                                        else
                                        {
                                            Tcl_AppendResult( interp, "doug.node ", pn->name, " set -flags (unknown flag \"", &tok[1], "\")", NULL );
											DSF_EndModifyScene( DSV_scene );
                                            return TCL_ERROR;
                                        }

                                        if( entry = Tcl_FindHashEntry( &fparams, &tok[1] ) )
                                        {
                                            /* IF CLEAR FLAG */
                                            if( tok[0] == '!' )
                                                DOUG_ClearTreeFlag( id, (int)Tcl_GetHashValue(entry), fval );

                                            /* ELSE TOGGLE FLAG */
                                            else
                                                DOUG_ToggleTreeFlag( id, (int)Tcl_GetHashValue(entry), fval );
                                        }
                                    }
                                    /* SET FLAG */
                                    else
                                    {
                                        if( entry = Tcl_FindHashEntry( &fbits, tok ) )
                                        {
                                            fval = (int)Tcl_GetHashValue( entry );
                                        }
                                        else
                                        {
                                            Tcl_AppendResult( interp, "doug.node ", pn->name, " set -flags (unknown flag \"", &tok[1], "\")", NULL );
											DSF_EndModifyScene( DSV_scene );
                                            return TCL_ERROR;
                                        }

                                        if( entry = Tcl_FindHashEntry( &fparams, tok ) )
                                            DOUG_SetTreeFlag( id, (int)Tcl_GetHashValue(entry), fval );
                                    }

                                    tok = DSF_strtok_r( 0L, sep, &tok_ptr );
                                }
                                break;

                            case NODE_LAYER:
                                /* NOT DONE */
                                break;

                            case NODE_STATE:
								{
									int ii;
									char *tok2;
									char cmd;
									char cmdstr[30];

									strcpy( buff, Tcl_GetString( objv[i] ) );
									i++;

									/* INITIALIZE TO BASE STATE FIRST */
									pn->x = pn->y = pn->z = pn->P = pn->Y = pn->R = 0;
									pn->attrib = pn->flags = pn->user_flags = 0;
									if( pn->type & DSD_IS_MODEL )
									{
										pn->data.mod.lod_override = -1;
									}
									if( pn->type & DSD_IS_LIGHT )
									{
										pn->data.lit.type = DSD_IS_DIRECT_LIGHT;
										pn->data.lit.intensity = 0;
										pn->data.lit.col[0] = 0;
										pn->data.lit.col[1] = 0;
										pn->data.lit.col[2] = 0;
										pn->data.lit.sp_dir[0] = 0;
										pn->data.lit.sp_dir[1] = 0;
										pn->data.lit.sp_dir[2] = 0;
										pn->data.lit.sp_exp = 0;
										pn->data.lit.sp_ang = 0;
									}
									if( pn->type & DSD_IS_CAMERA )
									{
										pn->data.cam.tilt = 0;
										pn->data.cam.pan = 0;
										pn->data.cam.spin = 0;
										pn->data.cam.zoom = 0;
									}
									tok_ptr = 0;
									ii = 0;
									tok = DSF_strtok_r( buff, " \n\t", &tok_ptr );
									strcpy( cmdstr, tok );
									while( cmd = cmdstr[ii] )
									{
										tok2 = DSF_strtok_r( 0L, " \n\t", &tok_ptr );
										switch( cmd )
										{
										case 'x':
											pn->x = atof(tok2);
											DSF_ModifiedNode( id, DSD_XYZ_MODIFIED );
											break;
										case 'y':
											pn->y = atof(tok2);
											DSF_ModifiedNode( id, DSD_XYZ_MODIFIED );
											break;
										case 'z':
											pn->z = atof(tok2);
											DSF_ModifiedNode( id, DSD_XYZ_MODIFIED );
											break;
										case 'P':
											pn->P = atof(tok2);
											DSF_ModifiedNode( id, DSD_PYR_MODIFIED );
											break;
										case 'Y':
											pn->Y = atof(tok2);
											DSF_ModifiedNode( id, DSD_PYR_MODIFIED );
											break;
										case 'R':
											pn->R = atof(tok2);
											DSF_ModifiedNode( id, DSD_PYR_MODIFIED );
											break;
										case 't':
											pn->data.cam.tilt = atof(tok2);
											DSF_ModifiedNode( id, DSD_CAMERA_MODIFIED );
											break;
										case 'p':
											pn->data.cam.pan = atof(tok2);
											DSF_ModifiedNode( id, DSD_CAMERA_MODIFIED );
											break;
										case 's':
											pn->data.cam.spin = atof(tok2);
											DSF_ModifiedNode( id, DSD_CAMERA_MODIFIED );
											break;
										case 'Z':
											pn->data.cam.zoom = atof(tok2);
											DSF_ModifiedNode( id, DSD_ZOOM_MODIFIED );
											break;
										case 'r':
											pn->data.lit.col[0] = atof(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case 'g':
											pn->data.lit.col[1] = atof(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case 'b':
											pn->data.lit.col[2] = atof(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case 'i':
											pn->data.lit.intensity = atof(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case '0':
											pn->data.lit.sp_dir[0] = atof(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case '1':
											pn->data.lit.sp_dir[1] = atof(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case '2':
											pn->data.lit.sp_dir[2] = atof(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case '3':
											pn->data.lit.sp_exp = atof(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case '4':
											pn->data.lit.sp_ang = atof(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case 'a':
											pn->attrib = atoi(tok2);
											DSF_ModifiedNode( id, DSD_ATTRIB_MODIFIED );
											break;
										case 'f':
											pn->flags = atoi(tok2);
											DSF_ModifiedNode( id, DSD_FLAGS_MODIFIED );
											break;
										case 'u':
											pn->user_flags = atoi(tok2);
											DSF_ModifiedNode( id, DSD_USERFLAGS_MODIFIED );
											break;
										case 'l':
											pn->data.lit.type = atoi(tok2);
											DSF_ModifiedNode( id, DSD_LIGHT_MODIFIED );
											break;
										case 'o':
											pn->data.mod.lod_override = atoi(tok2);
											DSF_ModifiedNode( id, DSD_MODEL_MODIFIED );
											break;
										case '+':
											pn->parent_id = atoi(tok2);
											DSF_ModifiedNode( id, DSD_PARENT_MODIFIED );
											break;
										}
										ii++;
									}
									build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);
								}
								break;

                            default :
                                Tcl_AppendResult( interp, "doug.node ", pn->name, " set (unknown argument \"", Tcl_GetString( objv[i] ), "\")", NULL );
								DSF_EndModifyScene( DSV_scene );
                                return TCL_ERROR;
                            }
                        }
                        else if( entry = Tcl_FindHashEntry( &double_params, tcl_cmdstr ) )
                        {
                            i++;
							build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);

							/* GET OFFSET TO DOUBLE PARAMENTER IN NODE STRUCTURE */
							pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

                            /* SET DOUBLE PARAMETER TO SPECIFIED VALUE */
                            Tcl_GetDoubleFromObj( interp, objv[i], pdouble );
                            i++;

							DSF_ModifiedNode( id, DSD_XYZ_MODIFIED|DSD_PYR_MODIFIED );
                        }
                        else if( entry = Tcl_FindHashEntry( &double_camparams, tcl_cmdstr ) )
                        {
                            i++;

                            /* FLOATS ARE ONLY USED IN CAMERA TILT,PAN,SPIN,ZOOM FIELDS */
                            if( pn->type & DSD_IS_CAMERA )
                            {
								build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);

                                /* GET OFFSET TO FLOAT PARAMENTER IN NODE STRUCTURE */
                                pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

                                /* SET FLOAT PARAMETER TO SPECIFIED VALUE */
                                Tcl_GetDoubleFromObj( interp, objv[i], pdouble );

								DSF_ModifiedNode( id, DSD_CAMERA_MODIFIED );
                            }
                            i++;
                        }
                        else if( entry = Tcl_FindHashEntry( &int_params, tcl_cmdstr ) )
                        {
                            int boff = (int)Tcl_GetHashValue( entry );
                            i++;
                            pint = (int*)(((char*)pn) + boff);

                            /* IF PARENT ID */
                            if( boff == BYTE_OFFSET(parent_id) )
                            {
                                char pname[200];
                                double x, y, z, P, Y, R;
                                int pid;
                                DST_MATRIX inv, res, ii, jj;
								double pos[3], att[3];

                                strcpy( buff, Tcl_GetString( objv[i] ) );
                                if( sscanf( buff, "%s %lf %lf %lf %lf %lf %lf", pname, &x, &y, &z, &P, &Y, &R ) == 7 )
                                {
                                    /* GET PARENT ID */
                                    pid = DSF_GetNodeID( pname );

									if( ParentOK( id, pid ) )
									{
										/* ASSIGN SPECIFIED OFFSETS */
										pn->x = x;
										pn->y = y;
										pn->z = z;
										pn->P = P;
										pn->Y = Y;
										pn->R = R;
										pn->parent_id = pid;
										build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);
									}
									else
									{
										char script[300];
										sprintf( script, "tk_messageBox -parent [doug.display get -main_window] -title Warning -type ok "
														 "-message \"A parent of %s would result in a circular link\" -icon warning",
														 pname );
										Tcl_Eval( interp, script );
									}
                                }
                                else
                                {
                                    /* GET PARENT ID */
                                    pid = DSF_GetNodeID( pname );

									if( ParentOK( id, pid ) )
									{
#if defined(SUPPORT_DOUBLE)
										if( DSV_double_data )
										{
											double gpmat_double[4][4];
											double gmat_double[4][4];
											double inv_double[4][4];
											double res_double[4][4];
											int cid;
											/* NOT DONE : need to compute using double precision */

											/* NEED TO RECOMPUTE RELATIVE POSITION */
											if( pid > -1 )
											{
#if defined(USE_AUTO_COLLAPSE)
												if( (cid=DSV_display->node_list[pid].collapsed_id) != pid )
												{
													DSM_MultMatrix( gpmat_double, DSV_double_data->processed_grelmat[pid], 
														DSV_double_data->processed_grelmat[cid] );
												}
												else
#endif
													memcpy( gpmat_double, DSV_double_data->processed_grelmat[pid], sizeof(double[4][4]) );
												DSF_FastInverseMatDouble( inv_double, gpmat_double );
#if defined(USE_AUTO_COLLAPSE)
												if( (cid=DSV_display->node_list[id].collapsed_id) != id )
												{
													DSM_MultMatrix( gmat_double, DSV_double_data->processed_grelmat[id], 
														DSV_double_data->processed_grelmat[cid] );
												}
												else
#endif
													memcpy( gmat_double, DSV_double_data->processed_grelmat[id], sizeof(double[4][4]) );

												/* IF RECOMPUTING A CAMERA POSITION, REMOVE CONCATINATED TILT,PAN,SPIN BEFORE COMPUTING MATRIX */
												if( pn->type & DSD_IS_CAMERA )
												{
													DSF_LoadMatrixDouble( gmat_double );
													DSF_RotateDouble( -(pn->data.cam.spin), 'x' );
													DSF_RotateDouble( -(pn->data.cam.tilt), 'y' );
													DSF_RotateDouble( -(pn->data.cam.pan),  'z' );
													DSF_GetMatrixDouble( gmat_double );
												}
												DSM_MultMatrix( res_double, gmat_double, inv_double );
											}
											else
											{
#if defined(USE_AUTO_COLLAPSE)
												if( (cid=DSV_display->node_list[id].collapsed_id) != id )
												{
													DSM_MultMatrix( gmat_double, DSV_double_data->processed_grelmat[id], 
														DSV_double_data->processed_grelmat[cid] );
												}
												else
#endif
													memcpy( gmat_double, DSV_double_data->processed_grelmat[id], sizeof(double[4][4]) );

												/* IF RECOMPUTING A CAMERA POSITION, REMOVE CONCATINATED TILT,PAN,SPIN BEFORE COMPUTING MATRIX */
												if( pn->type & DSD_IS_CAMERA )
												{
													DSF_LoadMatrixDouble( gmat_double );
													DSF_RotateDouble( -(pn->data.cam.spin), 'x' );
													DSF_RotateDouble( -(pn->data.cam.tilt), 'y' );
													DSF_RotateDouble( -(pn->data.cam.pan),  'z' );
													DSF_GetMatrixDouble( gmat_double );
												}
												memcpy( res_double, gmat_double, sizeof(double[4][4]) );
											}

											/* DECODE NEW POSITION */
											DSF_DecodeMatrixDouble( res_double, pn->order, pos, att );
											pn->x = pos[0];
											pn->y = pos[1];
											pn->z = pos[2];
											pn->R = att[0];
											pn->P = att[1];
											pn->Y = att[2];
											pn->parent_id = pid;

											build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);
										}
										else
#endif
										{
											DST_MATRIX gpmat;
											DST_MATRIX gmat;
											/* NOT DONE : need to compute using double precision */

											/* NEED TO RECOMPUTE RELATIVE POSITION */
											if( pid > -1 )
											{
												DSF_GetDisplayGlobalMat( pid, gpmat );
												DSF_FastInverseMat( inv, gpmat );
												DSF_GetDisplayGlobalMat( id, gmat );

												/* IF RECOMPUTING A CAMERA POSITION, REMOVE CONCATINATED TILT,PAN,SPIN BEFORE COMPUTING MATRIX */
												if( pn->type & DSD_IS_CAMERA )
												{
													DSF_LoadMatrix( gmat );
													DSF_Rotate( -(pn->data.cam.spin), 'x' );
													DSF_Rotate( -(pn->data.cam.tilt), 'y' );
													DSF_Rotate( -(pn->data.cam.pan),  'z' );
													DSF_GetMatrix( gmat );
												}
												DSM_MultMatrix( res, gmat, inv );
											}
											else
											{
												DSF_GetDisplayGlobalMat( id, gmat );

												/* IF RECOMPUTING A CAMERA POSITION, REMOVE CONCATINATED TILT,PAN,SPIN BEFORE COMPUTING MATRIX */
												if( pn->type & DSD_IS_CAMERA )
												{
													DSF_LoadMatrix( gmat );
													DSF_Rotate( -(pn->data.cam.spin), 'x' );
													DSF_Rotate( -(pn->data.cam.tilt), 'y' );
													DSF_Rotate( -(pn->data.cam.pan),  'z' );
													DSF_GetMatrix( gmat );
												}
												memcpy( res, gmat, sizeof(DST_MATRIX) );
											}

											/* DECODE NEW POSITION */
											DSF_DecodeMatrix( res, pn->order, pos, att );
											pn->x = pos[0];
											pn->y = pos[1];
											pn->z = pos[2];
											pn->R = att[0];
											pn->P = att[1];
											pn->Y = att[2];
											pn->parent_id = pid;

											build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);
										}
									}
									else
									{
										char script[300];
										sprintf( script, "tk_messageBox -parent [doug.display get -main_window] -title Warning -type ok "
														 "-message \"A parent of %s would result in a circular link\" -icon warning",
														 pname );
										Tcl_Eval( interp, script );
									}
                                }
								DSF_ModifiedNode( id, DSD_PARENT_MODIFIED|DSD_XYZ_MODIFIED|DSD_PYR_MODIFIED );
                            }

                            /* ELSE ITS THE ORDER PARAM */
                            else
                            {
                                char *ord = Tcl_GetString( objv[i] );

                                if( DSF_strcmpi( ord, "TPYR" ) )
                                    *pint = DSD_TPYR;
                                else if( DSF_strcmpi( ord, "TPRY" ) )
                                    *pint = DSD_TPRY;
                                else if( DSF_strcmpi( ord, "TRYP" ) )
                                    *pint = DSD_TRYP;
                                else if( DSF_strcmpi( ord, "TRPY" ) )
                                    *pint = DSD_TRPY;
                                else if( DSF_strcmpi( ord, "TYRP" ) )
                                    *pint = DSD_TYRP;
                                else if( DSF_strcmpi( ord, "TYPR" ) )
                                    *pint = DSD_TYPR;
                                else if( DSF_strcmpi( ord, "PYRT" ) )
                                    *pint = DSD_PYRT;
                                else if( DSF_strcmpi( ord, "PRYT" ) )
                                    *pint = DSD_PRYT;
                                else if( DSF_strcmpi( ord, "RYPT" ) )
                                    *pint = DSD_RYPT;
                                else if( DSF_strcmpi( ord, "RPYT" ) )
                                    *pint = DSD_RPYT;
                                else if( DSF_strcmpi( ord, "YRPT" ) )
                                    *pint = DSD_YRPT;
                                else if( DSF_strcmpi( ord, "YPRT" ) )
                                    *pint = DSD_YPRT;

								build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);
								DSF_ModifiedNode( id, DSD_ORDER_MODIFIED );
                            }
                            i++;
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_camparams, tcl_cmdstr ) )
                        {
                            /* THIS IS THE INDIRECT CAMERA PARAMETERS */
                            i++;
                            if( pn->type & DSD_IS_CAMERA )
							{
                                DOUG_CAM_setval( id, (int)Tcl_GetHashValue( entry ), Tcl_GetString( objv[i] ) );
								build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);
							}
                            i++;
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_modparams, tcl_cmdstr ) )
                        {
                            /* THIS IS THE INDIRECT MODEL PARAMETERS */
                            i++;
                            if( pn->type & DSD_IS_MODEL )
							{
                                DOUG_MOD_setval( id, (int)Tcl_GetHashValue( entry ), Tcl_GetString( objv[i] ) );
							}
                            i++;
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_nodeparams, tcl_cmdstr ) )
                        {
                            /* THIS IS THE INDIRECT NODE PARAMETERS */
                            i++;
                            DOUG_NODE_setval( id, (int)Tcl_GetHashValue( entry ), Tcl_GetString( objv[i] ) );
							build_matrix = (pn->attrib & DSD_MATRIX_ATTRIB);
                            i++;
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_litparams, tcl_cmdstr ) )
                        {
                            /* THIS IS EXTRA LIGHTING PARAMETERS : -lit_col -lit_int -lit_dir -lit_exp -lit_ang -lit_type */
                            i++;
                            if( pn->type & DSD_IS_LIGHT )
							{
                                DOUG_LIT_setval( id, (int)Tcl_GetHashValue( entry ), Tcl_GetString( objv[i] ) );
							}
                            i++;
                        }
                        else
                        {
                            Tcl_AppendResult( interp, "doug.node ", pn->name, " set (unknown argument \"", tcl_cmdstr, "\")", NULL );
							DSF_EndModifyScene( DSV_scene );
                            return TCL_ERROR;
                        }
                    }

					/* IF WE NEED TO REBUILD A MATRIX */
					if( build_matrix )
					{
						/* MAKE SURE NODE IS STILL IN MATRIX MODE */
						if( DSV_scene->node_list[id].attrib & DSD_MATRIX_ATTRIB )
						{
							/* IT IS SO BUILD THE MATRIX */
							DSV_scene->node_list[id].attrib &= ~DSD_MATRIX_ATTRIB;
							DSF_BuildLocalMatrix( DSV_scene, id );
							DSV_scene->node_list[id].attrib |= DSD_MATRIX_ATTRIB;
							DSF_ModifiedNode( id, DSD_MATRIX_MODIFIED );
						}
						build_matrix = 0;
					}

					DSF_EndModifyScene( DSV_scene );
                }
                break;

            case NODE_GET:
                {
                    DSF_BgnSceneAccess( DSV_scene, DSD_READ_ACCESS );
                    tcl_cmdstr = Tcl_GetString( objv[i] );
                    if( entry = Tcl_FindHashEntry( &options, tcl_cmdstr ) )
					{
						i++;
						switch( (int)Tcl_GetHashValue( entry ) )
						{
						case NODE_FLAGS:
							{
								int iii;
								int sub = 1;

								/* ADD ANY NODE ATTRIBUTES */
								for( iii=0; iii<DSV_attrib_count; iii++ )
								{
									if( pn->attrib & DSV_attrib_bits[iii] )
									{
										if( sub )
											Tcl_AppendResult( interp, DSV_attrib_names[iii], NULL );
										else
											Tcl_AppendResult( interp, " ", DSV_attrib_names[iii], NULL );
										sub = 0;
									}
								}

								/* ADD ANY NODE FLAGS */
								for( iii=0; iii<DSV_flag_count; iii++ )
								{
									if( pn->flags & DSV_flag_bits[iii] )
									{
										if( sub )
											Tcl_AppendResult( interp, DSV_flag_names[iii], NULL );
										else
											Tcl_AppendResult( interp, " ", DSV_flag_names[iii], NULL );
										sub = 0;
									}
								}
							}
							break;

						case NODE_USER_FLAGS:
							{
								int flag_num;
								char tbuf[80];
								int sub = 1;

								for( flag_num = 0; flag_num < 32; flag_num++ )
								{
									if( pn->user_flags & (0x1 << flag_num) )
									{
										sprintf( tbuf, " %d", flag_num );
										Tcl_AppendResult( interp, tbuf+sub, NULL );
										sub = 0;
									}
								}
							}
							break;

						case NODE_LAYER:
                            if( pn->layer & DSD_IS_BACKGROUND )
                                Tcl_SetResult( interp, "BACKGROUND", TCL_STATIC );
                            else if( pn->layer & DSD_IS_SCENE )
                                Tcl_SetResult( interp, "SCENE", TCL_STATIC );
                            else
                                Tcl_SetResult( interp, "FOREGROUND", TCL_STATIC );
							break;

						case NODE_STATE:
							{
								char 	result[300];
								char 	param_str[500];
								int  	param_i = 0;
								int  	dival;
								double 	dfval;

								result[0] = 0;

#define STATE_FVAR( v, t )	\
	dival = pn->v; \
	dfval = (dival < 0) ? (dival - pn->v) : (pn->v - dival); \
	if( dival || (dfval > 0.000001) ) \
	{\
		param_str[param_i] = t;\
		param_i += 1;\
		if( dfval < 0.000001 )\
			sprintf( buff, " %d", dival );\
		else\
			sprintf( buff, " %g", pn->v );\
		strcat( result, buff );\
	}

#define STATE_IVAR( c, v, t )	\
	if( pn->v != c ) \
	{\
		param_str[param_i] = t;\
		param_i += 1;\
		sprintf( buff, " %d", pn->v );\
		strcat( result, buff );\
	}

								STATE_FVAR(x,'x')
								STATE_FVAR(y,'y')
								STATE_FVAR(z,'z')
								STATE_FVAR(P,'P')
								STATE_FVAR(Y,'Y')
								STATE_FVAR(R,'R')
								STATE_IVAR(0,attrib,'a')
								STATE_IVAR(0,flags,'f')
								STATE_IVAR(0,user_flags,'u')
								if( pn->type & DSD_IS_CAMERA )
								{
									STATE_FVAR(data.cam.tilt,'t')
									STATE_FVAR(data.cam.pan,'p')
									STATE_FVAR(data.cam.spin,'s')
									STATE_FVAR(data.cam.zoom,'Z')
								}
								if( pn->type & DSD_IS_LIGHT )
								{
									STATE_IVAR(DSD_IS_DIRECT_LIGHT,data.lit.type,'l')
									STATE_FVAR(data.lit.col[0],'r')
									STATE_FVAR(data.lit.col[1],'g')
									STATE_FVAR(data.lit.col[2],'b')
									STATE_FVAR(data.lit.intensity,'i')
									if( (pn->data.lit.type == DSD_IS_SPOT_LIGHT) || (pn->data.lit.type == DSD_IS_DIRECT_LIGHT ) )
									{
										STATE_FVAR(data.lit.sp_dir[0],'0')
										STATE_FVAR(data.lit.sp_dir[1],'1')
										STATE_FVAR(data.lit.sp_dir[2],'2')

										if( pn->data.lit.type == DSD_IS_SPOT_LIGHT )
										{
											STATE_FVAR(data.lit.sp_exp,'3')
											STATE_FVAR(data.lit.sp_ang,'4')
										}
									}
								}
								if( pn->type & DSD_IS_MODEL )
								{
									STATE_IVAR(-1,data.mod.lod_override,'o')
								}

								param_str[param_i] = '+'; param_i += 1;
								sprintf( buff, " %d", pn->parent_id );
								strcat( result, buff );
								param_str[param_i] = 0; param_i += 1;
								strcat( param_str, result );
								Tcl_SetResult( interp, param_str, TCL_VOLATILE );
							}
							break;
						}
					}
                    else if( entry = Tcl_FindHashEntry( &double_params, tcl_cmdstr ) )
                    {
                        i++;
                        pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));
                        sprintf( buff, DOUG_data_format, *pdouble );
#if 0
                        Tcl_SetResult( interp, buff, TCL_VOLATILE );
#else
						Tcl_AppendResult( interp, buff, NULL );
#endif
                    }
                    else if( entry = Tcl_FindHashEntry( &double_camparams, tcl_cmdstr ) )
                    {
                        i++;
                        if( pn->type & DSD_IS_CAMERA )
                        {
                            pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));
                            sprintf( buff, DOUG_data_format, *pdouble );
                            Tcl_SetResult( interp, buff, TCL_VOLATILE );
                        }
                    }
                    else if( entry = Tcl_FindHashEntry( &proc_camparams, tcl_cmdstr ) )
                    {
                        /* THIS IS INDIRECT CAMERA PARAMETERS */
                        i++;
						if( pn->type & DSD_IS_CAMERA )
							Tcl_SetResult( interp, DOUG_CAM_getval( id, (int)Tcl_GetHashValue( entry ) ), TCL_VOLATILE );
                    }
                    else if( entry = Tcl_FindHashEntry( &proc_modparams, tcl_cmdstr ) )
                    {
                        /* THIS IS INDIRECT CAMERA PARAMETERS */
                        i++;
						if( pn->type & DSD_IS_MODEL )
							Tcl_SetResult( interp, DOUG_MOD_getval( id, (int)Tcl_GetHashValue( entry ) ), TCL_VOLATILE );
                    }
                    else if( entry = Tcl_FindHashEntry( &proc_nodeparams, tcl_cmdstr ) )
                    {
                        /* THIS IS INDIRECT CAMERA PARAMETERS */
                        i++;
                        Tcl_SetResult( interp, DOUG_NODE_getval( id, (int)Tcl_GetHashValue( entry ) ), TCL_VOLATILE );
                    }
                    else if( entry = Tcl_FindHashEntry( &proc_litparams, tcl_cmdstr ) )
                    {
                        /* THIS IS EXTRA LIGHTING PARAMETERS : -lit_col -lit_int -lit_dir -lit_exp -lit_ang -lit_type */
                        i++;
						if( pn->type & DSD_IS_LIGHT )
							Tcl_SetResult( interp, DOUG_LIT_getval( id, (int)Tcl_GetHashValue( entry ) ), TCL_VOLATILE );
                    }
					else if( !DSF_strcmpi( tcl_cmdstr, "-type" ) )
					{
						if( pn->type & DSD_IS_MODEL )
						{
							Tcl_SetResult( interp, "MODEL", TCL_STATIC );
						}
						else if( pn->type & DSD_IS_LIGHT )
						{
							Tcl_SetResult( interp, "LIGHT", TCL_STATIC );
						}
						else if( pn->type & DSD_IS_CAMERA )
						{
							Tcl_SetResult( interp, "CAMERA", TCL_STATIC );
						}
						else if( pn->type & DSD_IS_SYSTEM )
						{
							Tcl_SetResult( interp, "SYSTEM", TCL_STATIC );
						}
						else if( pn->type & DSD_IS_CONTROL )
						{
							Tcl_SetResult( interp, "CONTROL", TCL_STATIC );
						}
						else if( pn->type & DSD_IS_OVERLAY )
						{
							Tcl_SetResult( interp, "OVERLAY", TCL_STATIC );
						}
						else 
						{
							Tcl_SetResult( interp, "UNKNOWN", TCL_STATIC );
						}
					}
					else if( !DSF_strcmpi( tcl_cmdstr, "-parent" ) )
                    {
						if( pn->parent_id < 0 )
							Tcl_SetResult( interp, "NULL", TCL_STATIC );
						else
							Tcl_SetResult( interp, DSV_scene->node_list[pn->parent_id].name, TCL_VOLATILE );
					}
                    DSF_EndSceneAccess();
                }
                break;

            case NODE_MAP:
                {
                    /* NOT DONE */
					DSF_BgnSceneAccess( DSV_scene, DSD_READ_ACCESS );
                    while( i < objc )
                    {
                        tcl_cmdstr = Tcl_GetString( objv[i] );
                        /* FIRST SEE IF PARAMETER IS MAPPABLE VIA THE INDIRECT METHOD (since this is done with tk widgets) */
                        if( entry = Tcl_FindHashEntry( &proc_camparams, tcl_cmdstr ) )
                        {
                            i++;
                            /* THE FOLLOWING IS ONLY FOR CAMERA TYPE */
                            if( pn->type & DSD_IS_CAMERA )
                            {
                                /* GET NODE VARIABLE AND ASSIGN IT TO THE SPECIFIED TCL-VARIABLE */
                                pnvar = DOUG_GetNodeVar( Tcl_GetString( objv[i] ), INDIRECT_VAR );
                                i++;

                                /* UPDATE THE TCL-VARIABLE TO THE CURRENT NODE VALUE */
                                pnvar->data.ivar.GetVal = DOUG_CAM_getval;
                                pnvar->data.ivar.SetVal = DOUG_CAM_setval;
                                pnvar->data.ivar.type = (int)Tcl_GetHashValue( entry );

                                pnvar->id = pn - DSV_scene->node_list;
								Tcl_UnlinkVar( DSV_doug->interp, pnvar->tclvar );
								if( !(pnvar->data.ivar.tclval) || (strlen(pnvar->data.ivar.tclval) < strlen(pnvar->data.ivar.GetVal( pnvar->id, pnvar->data.ivar.type ))) )
								{
									if( pnvar->data.ivar.tclval )
										Tcl_Free( pnvar->data.ivar.tclval );
									pnvar->data.ivar.tclval = (char*)Tcl_Alloc( STRING_VAR_SIZE );
								}
                                Tcl_LinkVar( DSV_doug->interp, pnvar->tclvar, (char*)(&(pnvar->data.ivar.tclval)), TCL_LINK_STRING );
                                strcpy( pnvar->data.ivar.val, pnvar->data.ivar.GetVal( pnvar->id, pnvar->data.ivar.type ) );
                                strcpy( pnvar->data.ivar.prev_val, pnvar->data.ivar.val );
                                strcpy( pnvar->data.ivar.tclval, pnvar->data.ivar.val );
                                strcpy( pnvar->data.ivar.prev_tclval, pnvar->data.ivar.val );
                                Tcl_UpdateLinkedVar( DSV_doug->interp, pnvar->tclvar );
                            }
                            else
                                i++;
                        }
                        /* FIRST SEE IF PARAMETER IS MAPPABLE VIA THE INDIRECT METHOD (since this is done with tk widgets) */
                        else if( entry = Tcl_FindHashEntry( &proc_modparams, tcl_cmdstr ) )
                        {
                            i++;
                            /* THE FOLLOWING IS ONLY FOR MODEL TYPE */
                            if( pn->type & DSD_IS_MODEL )
                            {
                                /* GET NODE VARIABLE AND ASSIGN IT TO THE SPECIFIED TCL-VARIABLE */
                                pnvar = DOUG_GetNodeVar( Tcl_GetString( objv[i] ), INDIRECT_VAR );
                                i++;

                                /* UPDATE THE TCL-VARIABLE TO THE CURRENT NODE VALUE */
                                pnvar->data.ivar.GetVal = DOUG_MOD_getval;
                                pnvar->data.ivar.SetVal = DOUG_MOD_setval;
                                pnvar->data.ivar.type = (int)Tcl_GetHashValue( entry );

                                pnvar->id = pn - DSV_scene->node_list;
								Tcl_UnlinkVar( DSV_doug->interp, pnvar->tclvar );
								if( !(pnvar->data.ivar.tclval) || (strlen(pnvar->data.ivar.tclval) < strlen(pnvar->data.ivar.GetVal( pnvar->id, pnvar->data.ivar.type ))) )
								{
									if( pnvar->data.ivar.tclval )
										Tcl_Free( pnvar->data.ivar.tclval );
									pnvar->data.ivar.tclval = (char*)Tcl_Alloc( STRING_VAR_SIZE );
								}
                                Tcl_LinkVar( DSV_doug->interp, pnvar->tclvar, (char*)(&(pnvar->data.ivar.tclval)), TCL_LINK_STRING );
                                strcpy( pnvar->data.ivar.val, pnvar->data.ivar.GetVal( pnvar->id, pnvar->data.ivar.type ) );
                                strcpy( pnvar->data.ivar.prev_val, pnvar->data.ivar.val );
                                strcpy( pnvar->data.ivar.tclval, pnvar->data.ivar.val );
                                strcpy( pnvar->data.ivar.prev_tclval, pnvar->data.ivar.val );
                                Tcl_UpdateLinkedVar( DSV_doug->interp, pnvar->tclvar );
                            }
                            else
                                i++;
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_nodeparams, tcl_cmdstr ) )
                        {
                            i++;

                            /* GET NODE VARIABLE AND ASSIGN IT TO THE SPECIFIED TCL-VARIABLE */
                            pnvar = DOUG_GetNodeVar( Tcl_GetString( objv[i] ), INDIRECT_VAR );
                            i++;

                            /* UPDATE THE TCL-VARIABLE TO THE CURRENT NODE VALUE */
                            pnvar->data.ivar.GetVal = DOUG_NODE_getval;
                            pnvar->data.ivar.SetVal = DOUG_NODE_setval;
                            pnvar->data.ivar.type = (int)Tcl_GetHashValue( entry );

                            pnvar->id = pn - DSV_scene->node_list;
							Tcl_UnlinkVar( DSV_doug->interp, pnvar->tclvar );
							if( !(pnvar->data.ivar.tclval) || (strlen(pnvar->data.ivar.tclval) < strlen(pnvar->data.ivar.GetVal( pnvar->id, pnvar->data.ivar.type )) ) )
							{
								if( pnvar->data.ivar.tclval )
									Tcl_Free( pnvar->data.ivar.tclval );
								pnvar->data.ivar.tclval = (char*)Tcl_Alloc( STRING_VAR_SIZE );
							}
                            Tcl_LinkVar( DSV_doug->interp, pnvar->tclvar, (char*)(&(pnvar->data.ivar.tclval)), TCL_LINK_STRING );
                            strcpy( pnvar->data.ivar.val, pnvar->data.ivar.GetVal( pnvar->id, pnvar->data.ivar.type ) );
                            strcpy( pnvar->data.ivar.prev_val, pnvar->data.ivar.val );
                            strcpy( pnvar->data.ivar.tclval, pnvar->data.ivar.val );
                            strcpy( pnvar->data.ivar.prev_tclval, pnvar->data.ivar.val );
                            Tcl_UpdateLinkedVar( DSV_doug->interp, pnvar->tclvar );
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_litparams, tcl_cmdstr ) )
                        {
                            i++;
                            /* THE FOLLOWING IS ONLY FOR LIGHT TYPE */
                            if( pn->type & DSD_IS_LIGHT )
                            {
                                /* GET NODE VARIABLE AND ASSIGN IT TO THE SPECIFIED TCL-VARIABLE */
                                pnvar = DOUG_GetNodeVar( Tcl_GetString( objv[i] ), INDIRECT_VAR );
                                i++;

                                /* UPDATE THE TCL-VARIABLE TO THE CURRENT NODE VALUE */
                                pnvar->data.ivar.GetVal = DOUG_LIT_getval;
                                pnvar->data.ivar.SetVal = DOUG_LIT_setval;
                                pnvar->data.ivar.type = (int)Tcl_GetHashValue( entry );

                                pnvar->id = pn - DSV_scene->node_list;
								Tcl_UnlinkVar( DSV_doug->interp, pnvar->tclvar );
								if( !(pnvar->data.ivar.tclval) || (strlen(pnvar->data.ivar.tclval) < strlen(pnvar->data.ivar.GetVal( pnvar->id, pnvar->data.ivar.type ))) )
								{
									if( pnvar->data.ivar.tclval )
										Tcl_Free( pnvar->data.ivar.tclval );
									pnvar->data.ivar.tclval = (char*)Tcl_Alloc( STRING_VAR_SIZE );
								}
                                Tcl_LinkVar( DSV_doug->interp, pnvar->tclvar, (char*)(&(pnvar->data.ivar.tclval)), TCL_LINK_STRING );
                                strcpy( pnvar->data.ivar.val, pnvar->data.ivar.GetVal( pnvar->id, pnvar->data.ivar.type ) );
                                strcpy( pnvar->data.ivar.prev_val, pnvar->data.ivar.val );
                                strcpy( pnvar->data.ivar.tclval, pnvar->data.ivar.val );
                                strcpy( pnvar->data.ivar.prev_tclval, pnvar->data.ivar.val );
                                Tcl_UpdateLinkedVar( DSV_doug->interp, pnvar->tclvar );
                            }
                            else
                                i++;
                        }
                        else if( entry = Tcl_FindHashEntry( &double_params, tcl_cmdstr ) )
                        {
                            /* GET OFFSET TO DOUBLE PARAMENTER IN NODE STRUCTURE */
                            i++;
                            pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

                            /* GET NODE VARIABLE AND ASSIGN IT TO THE SPECIVIED TCL-VARIABLE */
                            pnvar = DOUG_GetNodeVar( Tcl_GetString( objv[i] ), DIRECT_VAR );
                            i++;

                            /* UPDATE THE TCL-VARIABLE TO THE CURRENT NODE VALUE */
                            pnvar->data.dvar.pval = pdouble;
                            pnvar->id = pn - DSV_scene->node_list;
							Tcl_UnlinkVar( DSV_doug->interp, pnvar->tclvar );
                            Tcl_LinkVar( DSV_doug->interp, pnvar->tclvar, (char *)(&(pnvar->data.dvar.tclval)), TCL_LINK_DOUBLE);
                            pnvar->data.dvar.tclval = pnvar->data.dvar.prev_tclval = pnvar->data.dvar.prev_val = *pdouble;
                            Tcl_UpdateLinkedVar( DSV_doug->interp, pnvar->tclvar );
                        }
                        else if( entry = Tcl_FindHashEntry( &double_camparams, tcl_cmdstr ) )
                        {
                            i++;

                            /* FLOATS ARE ONLY USED IN CAMERA TILT,PAN,SPIN,ZOOM FIELDS */
                            if( pn->type & DSD_IS_CAMERA )
                            {
                                /* GET OFFSET TO FLOAT PARAMENTER IN NODE STRUCTURE */
                                pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

                                /* GET NODE VARIABLE AND ASSIGN IT TO THE SPECIVIED TCL-VARIABLE */
                                pnvar = DOUG_GetNodeVar( Tcl_GetString( objv[i] ), DIRECT_VAR );
                                i++;

                                /* UPDATE THE TCL-VARIABLE TO THE CURRENT NODE VALUE */
                                pnvar->data.dvar.pval = pdouble;
                                pnvar->id = pn - DSV_scene->node_list;
								Tcl_UnlinkVar( DSV_doug->interp, pnvar->tclvar );
                                Tcl_LinkVar( DSV_doug->interp, pnvar->tclvar, (char *)(&(pnvar->data.dvar.tclval)), 
                                    TCL_LINK_DOUBLE );
                                pnvar->data.dvar.tclval = pnvar->data.dvar.prev_tclval = pnvar->data.dvar.prev_val = *pdouble;
                                Tcl_UpdateLinkedVar( DSV_doug->interp, pnvar->tclvar );
                            }
                            else
                                i++;
                        }
                        else 
                        {
							DSF_EndSceneAccess();
                            Tcl_AppendResult( interp, "doug.node ", pn->name, " map (unknown argument \"", Tcl_GetString( objv[i] ), "\")", NULL );
                            return TCL_ERROR;
                        }
                    }
					DSF_EndSceneAccess();
                }
                break;

            case NODE_TEST:
				DSF_BgnSceneAccess( DSV_scene, DSD_READ_ACCESS );
				strcpy( buff, Tcl_GetString( objv[i] ) );
				i++;
				tok_ptr = 0;
				tok = DSF_strtok_r( buff, sep, &tok_ptr );
				if( entry = Tcl_FindHashEntry( &fbits, tok ) )
				{
					fval = (int)Tcl_GetHashValue( entry );
					if( entry = Tcl_FindHashEntry( &fparams, tok ) )
					{
						pint = (int*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

						if( *pint & fval )
							Tcl_AppendResult( interp, "1", NULL );
						else
							Tcl_AppendResult( interp, "0", NULL );
					}
					else
						Tcl_AppendResult( interp, "0", NULL );
				}
				else
					Tcl_AppendResult( interp, "0", NULL );
				DSF_EndSceneAccess();
                break;

            case NODE_ANIMATE:
                {
					panim = 0;
                    tcl_cmdstr = Tcl_GetString( objv[i] );
                    /* FIRST LOOK TO SEE IF WE ARE DIRECTLY ANIMATING A PARAMETER */
                    if( !(entry = Tcl_FindHashEntry( &double_params, tcl_cmdstr )) )
                    {
                        if( pn->type & DSD_IS_CAMERA )
                            entry = Tcl_FindHashEntry( &double_camparams, tcl_cmdstr );
                    }

                    /* WE ARE ANIMATING A PARAMETER DIRECTLY */
                    if( entry )
                    {
                        i++;

                        /* GET PARAM REFERENCE INTO NODE */
                        pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

                        /* ADD A NEW ENTRY TO THE HASH TABLE IF NEEDED */
                        entry = Tcl_CreateHashEntry( &animate_hash, (char*)pdouble, &new_item );
                        if( new_item )
                        {
                            panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
                            panim->id           = id;
                            panim->type         = PARAM;
                            panim->param        = pdouble;
                            panim->enabled      = AUTO_UPDATE;
                            panim->prev_time    = cur_time;
                            panim->scalevar     = NULL;
                            panim->unitsvar     = NULL;
                            panim->scale        = 1.0;
                            panim->units        = 1.0;
                            panim->samples      = 2.0;
                            Tcl_SetHashValue( entry, (ClientData)panim );
                        }
                        else
                        {
                            panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
                            panim->id           = id;
                            panim->type         = PARAM;
                            panim->param        = pdouble;
                            panim->enabled      = AUTO_UPDATE;
                            panim->prev_time    = cur_time;
                            panim->scalevar     = NULL;
                            panim->unitsvar     = NULL;
                            panim->scale        = 1.0;
                            panim->units        = 1.0;
                            panim->samples      = 2.0;
                        }
                    }

                    /* OHTERWISE SEE IF WE ARE ANIMATING A RELATIVE-PARAMETER */
                    else
                    {
                        /* WE ARE DOING A RELATIVE PARAMETER ANIMATE */
                        if( entry = Tcl_FindHashEntry( &rel_params, tcl_cmdstr ) )
                        {
                            i++;

                            /* GET RELATIVE PARAM TYPE */
                            reltype = (int)Tcl_GetHashValue( entry );

                            /* ADD A NEW ENTRY TO THE HASH TABLE (based on node_id and param_type) IF NEEDED */
                            entry = Tcl_CreateHashEntry( &relanimate_hash, (char*)((id << 10)|reltype), &new_item );
                            if( new_item )
                            {
                                panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
                                panim->id           = id;
                                panim->type         = reltype;
                                panim->enabled      = AUTO_UPDATE;
                                panim->prev_time    = cur_time;
                                panim->scalevar     = NULL;
                                panim->unitsvar     = NULL;
                                panim->scale        = 1.0;
                                panim->units        = 1.0;
                                panim->samples      = 2.0;
                                Tcl_SetHashValue( entry, (ClientData)panim );
                            }
                            else
                            {
                                panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
                                panim->id           = id;
                                panim->type         = reltype;
                                panim->enabled      = AUTO_UPDATE;
                                panim->prev_time    = cur_time;
                                panim->scalevar     = NULL;
                                panim->unitsvar     = NULL;
                                panim->scale        = 1.0;
                                panim->units        = 1.0;
                                panim->samples      = 2.0;
                            }
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_camparams, tcl_cmdstr ) )
                        {
                            i++;
							if( pn->type & DSD_IS_CAMERA )
							{
								reltype = (int)Tcl_GetHashValue( entry );
								entry = Tcl_CreateHashEntry( &procanimate_hash, (char*)((id << 10)|reltype), &new_item );
								if( new_item )
								{
									panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
									panim->id           = id;
									panim->type         = PROC_PARAM;
									panim->vtype        = reltype;
									panim->enabled      = AUTO_UPDATE;
									panim->prev_time    = cur_time;
									panim->scalevar     = NULL;
									panim->unitsvar     = NULL;
									panim->scale        = 1.0;
									panim->units        = 1.0;
									panim->samples      = 2.0;
									panim->GetVal       = DOUG_CAM_getval_double;
									panim->SetVal       = DOUG_CAM_setval_double;
									Tcl_SetHashValue( entry, (ClientData)panim );
								}
								else
								{
									panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
									panim->id           = id;
									panim->type         = PROC_PARAM;
									panim->vtype        = reltype;
									panim->enabled      = AUTO_UPDATE;
									panim->prev_time    = cur_time;
									panim->scalevar     = NULL;
									panim->unitsvar     = NULL;
									panim->scale        = 1.0;
									panim->units        = 1.0;
									panim->samples      = 2.0;
									panim->GetVal       = DOUG_CAM_getval_double;
									panim->SetVal       = DOUG_CAM_setval_double;
								}
							}
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_modparams, tcl_cmdstr ) )
                        {
                            i++;
							if( pn->type & DSD_IS_MODEL )
							{
								reltype = (int)Tcl_GetHashValue( entry );
								entry = Tcl_CreateHashEntry( &procanimate_hash, (char*)((id << 10)|reltype), &new_item );
								if( new_item )
								{
									panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
									panim->id           = id;
									panim->type         = PROC_PARAM;
									panim->vtype        = reltype;
									panim->enabled      = AUTO_UPDATE;
									panim->prev_time    = cur_time;
									panim->scalevar     = NULL;
									panim->unitsvar     = NULL;
									panim->scale        = 1.0;
									panim->units        = 1.0;
									panim->samples      = 2.0;
									panim->GetVal       = DOUG_MOD_getval_double;
									panim->SetVal       = DOUG_MOD_setval_double;
									Tcl_SetHashValue( entry, (ClientData)panim );
								}
								else
								{
									panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
									panim->id           = id;
									panim->type         = PROC_PARAM;
									panim->vtype        = reltype;
									panim->enabled      = AUTO_UPDATE;
									panim->prev_time    = cur_time;
									panim->scalevar     = NULL;
									panim->unitsvar     = NULL;
									panim->scale        = 1.0;
									panim->units        = 1.0;
									panim->samples      = 2.0;
									panim->GetVal       = DOUG_MOD_getval_double;
									panim->SetVal       = DOUG_MOD_setval_double;
								}
							}
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_nodeparams, tcl_cmdstr ) )
                        {
                            i++;
                            reltype = (int)Tcl_GetHashValue( entry );

                            entry = Tcl_CreateHashEntry( &procanimate_hash, (char*)((id << 10)|reltype), &new_item );
                            if( new_item )
                            {
                                panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
                                panim->id           = id;
                                panim->type         = PROC_PARAM;
                                panim->vtype        = reltype;
                                panim->enabled      = AUTO_UPDATE;
                                panim->prev_time    = cur_time;
                                panim->scalevar     = NULL;
                                panim->unitsvar     = NULL;
                                panim->scale        = 1.0;
                                panim->units        = 1.0;
                                panim->samples      = 2.0;
                                panim->GetVal       = DOUG_NODE_getval_double;
                                panim->SetVal       = DOUG_NODE_setval_double;
                                Tcl_SetHashValue( entry, (ClientData)panim );
                            }
                            else
                            {
                                panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
                                panim->id           = id;
                                panim->type         = PROC_PARAM;
                                panim->enabled      = AUTO_UPDATE;
                                panim->prev_time    = cur_time;
                                panim->scalevar     = NULL;
                                panim->unitsvar     = NULL;
                                panim->scale        = 1.0;
                                panim->units        = 1.0;
                                panim->samples      = 2.0;
                                panim->GetVal       = DOUG_NODE_getval_double;
                                panim->SetVal       = DOUG_NODE_setval_double;
                            }
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_litparams, tcl_cmdstr ) )
                        {
                            i++;
							if( pn->type & DSD_IS_LIGHT )
							{
								reltype = (int)Tcl_GetHashValue( entry );
								entry = Tcl_CreateHashEntry( &procanimate_hash, (char*)((id << 10)|reltype), &new_item );
								if( new_item )
								{
									panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
									panim->id           = id;
									panim->type         = PROC_PARAM;
									panim->vtype        = reltype;
									panim->enabled      = AUTO_UPDATE;
									panim->prev_time    = cur_time;
									panim->scalevar     = NULL;
									panim->unitsvar     = NULL;
									panim->scale        = 1.0;
									panim->units        = 1.0;
									panim->samples      = 2.0;
									panim->GetVal       = DOUG_LIT_getval_double;
									panim->SetVal       = DOUG_LIT_setval_double;
									Tcl_SetHashValue( entry, (ClientData)panim );
								}
								else
								{
									panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
									panim->id           = id;
									panim->type         = PROC_PARAM;
									panim->vtype        = reltype;
									panim->enabled      = AUTO_UPDATE;
									panim->prev_time    = cur_time;
									panim->scalevar     = NULL;
									panim->unitsvar     = NULL;
									panim->scale        = 1.0;
									panim->units        = 1.0;
									panim->samples      = 2.0;
									panim->GetVal       = DOUG_LIT_getval_double;
									panim->SetVal       = DOUG_LIT_setval_double;
								}
							}
                        }
                        else
                        {
                            Tcl_AppendResult( interp, "doug.node ", pn->name, " animate (invalid argument \"", tcl_cmdstr, "\")", NULL );
                            return TCL_ERROR;
                        }
                    }

					while( i < objc )
					{
						if( panim )
						{
							tok = Tcl_GetString( objv[i] );
							i++;

							if( !strcmp( tok, "-units" ) )
							{
								panim->type |= (panim->type & ~ANIM_TYPE) | ANIM_UNIT;
								Tcl_GetDoubleFromObj( interp, objv[i], &(panim->units) );
								i++;
							}
							else if( !strcmp( tok, "-rate" ) )
							{
								panim->type |= (panim->type & ~ANIM_TYPE) | ANIM_RATE;
								Tcl_GetDoubleFromObj( interp, objv[i], &(panim->units) );
								i++;
							}
							else if( !strcmp( tok, "-ratevar" ) )
							{
								panim->type |= (panim->type & ~ANIM_TYPE) | ANIM_RATE;

								if( entry = Tcl_FindHashEntry( &var_hash, Tcl_GetString(objv[i]) ) )
									panim->unitsvar = (DOUG_USER_VARIABLE*)Tcl_GetHashValue( entry );
								else
								{
									Tcl_AppendResult( interp, "doug.node ", pn->name, " animate \n"
										"-ratevar (undefined variable \"", Tcl_GetString(objv[i]), "\")", NULL );
									return TCL_ERROR;
								}
								i++;
							}
							else if( !strcmp( tok, "-unitsvar" ) )
							{
								panim->type |= (panim->type & ~ANIM_TYPE) | ANIM_UNIT;

								if( entry = Tcl_FindHashEntry( &var_hash, Tcl_GetString(objv[i]) ) )
									panim->unitsvar = (DOUG_USER_VARIABLE*)Tcl_GetHashValue( entry );
								else
								{
									Tcl_AppendResult( interp, "doug.node ", pn->name, " animate \n"
										"-unitsvar (undefined variable \"", Tcl_GetString(objv[i]), "\")", NULL );
									return TCL_ERROR;
								}
								i++;
							}
							else if( !strcmp( tok, "-scalevar" ) )
							{
								if( entry = Tcl_FindHashEntry( &var_hash, Tcl_GetString( objv[i] ) ) )
									panim->scalevar = (DOUG_USER_VARIABLE*)Tcl_GetHashValue( entry );
								else
								{
									Tcl_AppendResult( interp, "doug.node ", pn->name, " animate \n"
										"-scalevar (undefined variable \"", Tcl_GetString( objv[i] ), "\")", NULL );
									return TCL_ERROR;
								}
								i++;
							}
							else if( !strcmp( tok, "-samples" ) )
							{
								Tcl_GetDoubleFromObj( interp, objv[i], &(panim->samples) );
								i++;
							}
							else if( !strcmp( tok, "-reverse" ) )
							{
								int ival;
								Tcl_GetIntFromObj( interp, objv[i], &ival );
								if( ival )
									panim->enabled |= AUTO_REVERSE;
								else
									panim->enabled &= ~AUTO_REVERSE;
								i++;
							}
							else if( !strcmp( tok, "-enabled" ) )
							{
								int ival;
								Tcl_GetIntFromObj( interp, objv[i], &ival );
								if( ival && !(panim->enabled & AUTO_UPDATE) )
								{
									panim->prev_time = cur_time;
									panim->enabled |= AUTO_UPDATE;
								}
								else if( !ival )
									panim->enabled &= ~AUTO_UPDATE;
								i++;
							}
							else
							{
								tcl_cmdstr = tok;
								/* FIRST LOOK TO SEE IF WE ARE DIRECTLY ANIMATING A PARAMETER */
								if( !(entry = Tcl_FindHashEntry( &double_params, tcl_cmdstr )) )
								{
									if( pn->type & DSD_IS_CAMERA )
										entry = Tcl_FindHashEntry( &double_camparams, tcl_cmdstr );
								}

								/* WE ARE ANIMATING A PARAMETER DIRECTLY */
								if( entry )
								{
									/* GET PARAM REFERENCE INTO NODE */
									pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

									/* ADD A NEW ENTRY TO THE HASH TABLE IF NEEDED */
									entry = Tcl_CreateHashEntry( &animate_hash, (char*)pdouble, &new_item );
									if( new_item )
									{
										panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
										panim->id           = id;
										panim->type         = PARAM;
										panim->param        = pdouble;
										panim->enabled      = AUTO_UPDATE;
										panim->prev_time    = cur_time;
										panim->scalevar     = NULL;
										panim->unitsvar     = NULL;
										panim->scale        = 1.0;
										panim->units        = 1.0;
										panim->samples      = 2.0;
										Tcl_SetHashValue( entry, (ClientData)panim );
									}
									else
									{
										panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
										panim->id           = id;
										panim->type         = PARAM;
										panim->param        = pdouble;
										panim->enabled      = AUTO_UPDATE;
										panim->prev_time    = cur_time;
										panim->scalevar     = NULL;
										panim->unitsvar     = NULL;
										panim->scale        = 1.0;
										panim->units        = 1.0;
										panim->samples      = 2.0;
									}
								}

								/* OHTERWISE SEE IF WE ARE ANIMATING A RELATIVE-PARAMETER */
								else
								{
									/* WE ARE DOING A RELATIVE PARAMETER ANIMATE */
									if( entry = Tcl_FindHashEntry( &rel_params, tcl_cmdstr ) )
									{
										/* GET RELATIVE PARAM TYPE */
										reltype = (int)Tcl_GetHashValue( entry );

										/* ADD A NEW ENTRY TO THE HASH TABLE (based on node_id and param_type) IF NEEDED */
										entry = Tcl_CreateHashEntry( &relanimate_hash, (char*)((id << 10)|reltype), &new_item );
										if( new_item )
										{
											panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
											panim->id           = id;
											panim->type         = reltype;
											panim->enabled      = AUTO_UPDATE;
											panim->prev_time    = cur_time;
											panim->scalevar     = NULL;
											panim->unitsvar     = NULL;
											panim->scale        = 1.0;
											panim->units        = 1.0;
											panim->samples      = 2.0;
											Tcl_SetHashValue( entry, (ClientData)panim );
										}
										else
										{
											panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
											panim->id           = id;
											panim->type         = reltype;
											panim->enabled      = AUTO_UPDATE;
											panim->prev_time    = cur_time;
											panim->scalevar     = NULL;
											panim->unitsvar     = NULL;
											panim->scale        = 1.0;
											panim->units        = 1.0;
											panim->samples      = 2.0;
										}
									}
									else if( entry = Tcl_FindHashEntry( &proc_camparams, tcl_cmdstr ) )
									{
										if( pn->type & DSD_IS_CAMERA )
										{
											reltype = (int)Tcl_GetHashValue( entry );
											entry = Tcl_CreateHashEntry( &procanimate_hash, (char*)((id << 10)|reltype), &new_item );
											if( new_item )
											{
												panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
												panim->id           = id;
												panim->type         = PROC_PARAM;
												panim->vtype        = reltype;
												panim->enabled      = AUTO_UPDATE;
												panim->prev_time    = cur_time;
												panim->scalevar     = NULL;
												panim->unitsvar     = NULL;
												panim->scale        = 1.0;
												panim->units        = 1.0;
												panim->samples      = 2.0;
												panim->GetVal       = DOUG_CAM_getval_double;
												panim->SetVal       = DOUG_CAM_setval_double;
												Tcl_SetHashValue( entry, (ClientData)panim );
											}
											else
											{
												panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
												panim->id           = id;
												panim->type         = PROC_PARAM;
												panim->vtype        = reltype;
												panim->enabled      = AUTO_UPDATE;
												panim->prev_time    = cur_time;
												panim->scalevar     = NULL;
												panim->unitsvar     = NULL;
												panim->scale        = 1.0;
												panim->units        = 1.0;
												panim->samples      = 2.0;
												panim->GetVal       = DOUG_CAM_getval_double;
												panim->SetVal       = DOUG_CAM_setval_double;
											}
										}
									}
									else if( entry = Tcl_FindHashEntry( &proc_modparams, tcl_cmdstr ) )
									{
										if( pn->type & DSD_IS_MODEL )
										{
											reltype = (int)Tcl_GetHashValue( entry );
											entry = Tcl_CreateHashEntry( &procanimate_hash, (char*)((id << 10)|reltype), &new_item );
											if( new_item )
											{
												panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
												panim->id           = id;
												panim->type         = PROC_PARAM;
												panim->vtype        = reltype;
												panim->enabled      = AUTO_UPDATE;
												panim->prev_time    = cur_time;
												panim->scalevar     = NULL;
												panim->unitsvar     = NULL;
												panim->scale        = 1.0;
												panim->units        = 1.0;
												panim->samples      = 2.0;
												panim->GetVal       = DOUG_MOD_getval_double;
												panim->SetVal       = DOUG_MOD_setval_double;
												Tcl_SetHashValue( entry, (ClientData)panim );
											}
											else
											{
												panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
												panim->id           = id;
												panim->type         = PROC_PARAM;
												panim->vtype        = reltype;
												panim->enabled      = AUTO_UPDATE;
												panim->prev_time    = cur_time;
												panim->scalevar     = NULL;
												panim->unitsvar     = NULL;
												panim->scale        = 1.0;
												panim->units        = 1.0;
												panim->samples      = 2.0;
												panim->GetVal       = DOUG_MOD_getval_double;
												panim->SetVal       = DOUG_MOD_setval_double;
											}
										}
									}
									else if( entry = Tcl_FindHashEntry( &proc_nodeparams, tcl_cmdstr ) )
									{
										reltype = (int)Tcl_GetHashValue( entry );

										entry = Tcl_CreateHashEntry( &procanimate_hash, (char*)((id << 10)|reltype), &new_item );
										if( new_item )
										{
											panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
											panim->id           = id;
											panim->type         = PROC_PARAM;
											panim->vtype        = reltype;
											panim->enabled      = AUTO_UPDATE;
											panim->prev_time    = cur_time;
											panim->scalevar     = NULL;
											panim->unitsvar     = NULL;
											panim->scale        = 1.0;
											panim->units        = 1.0;
											panim->samples      = 2.0;
											panim->GetVal       = DOUG_NODE_getval_double;
											panim->SetVal       = DOUG_NODE_setval_double;
											Tcl_SetHashValue( entry, (ClientData)panim );
										}
										else
										{
											panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
											panim->id           = id;
											panim->type         = PROC_PARAM;
											panim->vtype        = reltype;
											panim->enabled      = AUTO_UPDATE;
											panim->prev_time    = cur_time;
											panim->scalevar     = NULL;
											panim->unitsvar     = NULL;
											panim->scale        = 1.0;
											panim->units        = 1.0;
											panim->samples      = 2.0;
											panim->GetVal       = DOUG_NODE_getval_double;
											panim->SetVal       = DOUG_NODE_setval_double;
										}
									}
									else if( entry = Tcl_FindHashEntry( &proc_litparams, tcl_cmdstr ) )
									{
										if( pn->type & DSD_IS_LIGHT )
										{
											reltype = (int)Tcl_GetHashValue( entry );
											entry = Tcl_CreateHashEntry( &procanimate_hash, (char*)((id << 10)|reltype), &new_item );
											if( new_item )
											{
												panim = (DOUG_ANIMATE_CMD*)malloc( sizeof(DOUG_ANIMATE_CMD) );
												panim->id           = id;
												panim->type         = PROC_PARAM;
												panim->vtype        = reltype;
												panim->enabled      = AUTO_UPDATE;
												panim->prev_time    = cur_time;
												panim->scalevar     = NULL;
												panim->unitsvar     = NULL;
												panim->scale        = 1.0;
												panim->units        = 1.0;
												panim->samples      = 2.0;
												panim->GetVal       = DOUG_LIT_getval_double;
												panim->SetVal       = DOUG_LIT_setval_double;
												Tcl_SetHashValue( entry, (ClientData)panim );
											}
											else
											{
												panim = (DOUG_ANIMATE_CMD*)Tcl_GetHashValue( entry );
												panim->id           = id;
												panim->type         = PROC_PARAM;
												panim->vtype        = reltype;
												panim->enabled      = AUTO_UPDATE;
												panim->prev_time    = cur_time;
												panim->scalevar     = NULL;
												panim->unitsvar     = NULL;
												panim->scale        = 1.0;
												panim->units        = 1.0;
												panim->samples      = 2.0;
												panim->GetVal       = DOUG_LIT_getval_double;
												panim->SetVal       = DOUG_LIT_setval_double;
											}
										}
									}
									else
									{
										Tcl_AppendResult( interp, "doug.node ", pn->name, " animate (invalid argument \"", tcl_cmdstr, "\")", NULL );
										return TCL_ERROR;
									}
								}
							}
						}
						else
							break;
					}
                }
                break;

            case NODE_LIMIT:
                {
                    tcl_cmdstr = Tcl_GetString( objv[i] );

                    /* FIRST LOOK TO SEE IF WE ARE DIRECTLY MONITORING A PARAMETER */
                    if( !(entry = Tcl_FindHashEntry( &double_params, tcl_cmdstr )) )
                    {
                        if( pn->type & DSD_IS_CAMERA )
                            entry = Tcl_FindHashEntry( &double_camparams, tcl_cmdstr );
                    }

                    /* IF A VALID PARAMETER WAS LOCATED */
                    if( entry )
                    {
                        i++;

                        /* GET PARAM REFERENCE INTO NODE */
                        pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

                        /* ADD A NEW ENTRY TO THE HASH TABLE IF NEEDED */
                        entry = Tcl_CreateHashEntry( &limit_hash, (char*)pdouble, &new_item );
                        if( new_item )
                        {
                            plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
							memset( plim, 0, sizeof(DOUG_LIMIT_PARAM) );
                            plim->id            = id;
                            plim->indirect      = 0;
                            plim->param         = pdouble;
                            plim->enabled       = 1;
                            plim->min           = *pdouble;
                            plim->max           = *pdouble;
                            Tcl_SetHashValue( entry, (ClientData)plim );
                        }
                        else
                        {
                            plim = (DOUG_LIMIT_PARAM*)Tcl_GetHashValue( entry );
                        }
                    }
                    else
                    {
                        if( entry = Tcl_FindHashEntry( &proc_camparams, tcl_cmdstr ) )
                        {
                            i++;
							if( pn->type & DSD_IS_CAMERA )
							{
								reltype = (int)Tcl_GetHashValue( entry );

								entry = Tcl_CreateHashEntry( &proclimit_hash, (char*)((id << 8)|reltype), &new_item );
								if( new_item )
								{
									plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
									Tcl_SetHashValue( entry, (ClientData)plim );
									plim->id            = id;
									plim->indirect      = 1;
									plim->vtype         = reltype;
									plim->enabled       = 1;
									plim->GetVal        = DOUG_CAM_getval_double;
									plim->SetVal        = DOUG_CAM_setval_double;
									plim->min           = DOUG_CAM_getval_double( id, reltype ) - 0.001;
									plim->max           = plim->min + 0.001;
								}
								else
								{
									plim = (DOUG_LIMIT_PARAM*)Tcl_GetHashValue( entry );
									plim->id            = id;
									plim->indirect      = 1;
									plim->vtype         = reltype;
									plim->enabled       = 1;
								}
							}
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_nodeparams, tcl_cmdstr ) )
                        {
                            i++;
                            reltype = (int)Tcl_GetHashValue( entry );

                            entry = Tcl_CreateHashEntry( &proclimit_hash, (char*)((id << 8)|reltype), &new_item );
                            if( new_item )
                            {
                                plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
                                Tcl_SetHashValue( entry, (ClientData)plim );
                                plim->id            = id;
                                plim->indirect      = 1;
                                plim->vtype         = reltype;
                                plim->enabled       = 1;
                                plim->GetVal        = DOUG_NODE_getval_double;
                                plim->SetVal        = DOUG_NODE_setval_double;
                                plim->min           = DOUG_NODE_getval_double( id, reltype ) - 0.001;
                                plim->max           = plim->min + 0.001;
                            }
                            else
                            {
                                plim = (DOUG_LIMIT_PARAM*)Tcl_GetHashValue( entry );
                                plim->id            = id;
                                plim->indirect      = 1;
                                plim->vtype         = reltype;
                                plim->enabled       = 1;
                            }
                        }
                        else if( entry = Tcl_FindHashEntry( &proc_litparams, tcl_cmdstr ) )
                        {
                            i++;
							if( pn->type & DSD_IS_LIGHT )
							{
								reltype = (int)Tcl_GetHashValue( entry );

								entry = Tcl_CreateHashEntry( &proclimit_hash, (char*)((id << 8)|reltype), &new_item );
								if( new_item )
								{
									plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
									Tcl_SetHashValue( entry, (ClientData)plim );
									plim->id            = id;
									plim->indirect      = 1;
									plim->vtype         = reltype;
									plim->enabled       = 1;
									plim->GetVal        = DOUG_LIT_getval_double;
									plim->SetVal        = DOUG_LIT_setval_double;
									plim->min           = DOUG_LIT_getval_double( id, reltype ) - 0.001;
									plim->max           = plim->min + 0.001;
								}
								else
								{
									plim = (DOUG_LIMIT_PARAM*)Tcl_GetHashValue( entry );
									plim->id            = id;
									plim->indirect      = 1;
									plim->vtype         = reltype;
									plim->enabled       = 1;
								}
							}
                        }
						else if( !strcmp( tcl_cmdstr, "-parent" ) )
						{
							i++;
							reltype = NODE_PARENT;
							entry = Tcl_CreateHashEntry( &limit_hash, (char*)((id << 8)|reltype), &new_item );
							if( new_item )
							{
                                plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
                                Tcl_SetHashValue( entry, (ClientData)plim );
                                plim->id            = id;
                                plim->indirect      = 0;
                                plim->vtype         = reltype;
                                plim->enabled       = 1;
								plim->iparam		= &(pn->parent_id);
								plim->ival			= pn->parent_id;
                            }
                            else
                            {
                                plim = (DOUG_LIMIT_PARAM*)Tcl_GetHashValue( entry );
                                plim->id            = id;
                                plim->indirect      = 0;
                                plim->vtype         = reltype;
                                plim->enabled       = 1;
								plim->iparam		= &(pn->parent_id);
								plim->ival			= pn->parent_id;
							}
						}
                        else
                        {
                            Tcl_AppendResult( interp, "doug.node ", pn->name, " limit (invalid argument \"", tcl_cmdstr, "\")", NULL );
                            return TCL_ERROR;
                        }
                    }

                    while( i < objc )
                    {
                        tok = Tcl_GetString( objv[i] );
                        i++;

                        if( !strcmp( tok, "-interval" ) || !strcmp( tok, "-range" ) )
                        {
                            Tcl_GetDoubleFromObj( interp, objv[i], &(plim->min) );
                            i++;
                            Tcl_GetDoubleFromObj( interp, objv[i], &(plim->max) );
                            i++;
                            if( plim->indirect )
                            {
                                if( (plim->max-plim->min) < 0.0001 )
                                {
                                    plim->min = plim->min - 0.00006;
                                    plim->max = plim->max + 0.00006;
                                }
                            }

                        }
                        else if( !strcmp( tok, "-enabled" ) )
                        {
                            Tcl_GetIntFromObj( interp, objv[i], &(plim->enabled) );
                            i++;
                        }
                        else
                        {
                            tcl_cmdstr = tok;

                            /* FIRST LOOK TO SEE IF WE ARE DIRECTLY MONITORING A PARAMETER */
                            if( !(entry = Tcl_FindHashEntry( &double_params, tcl_cmdstr )) )
                            {
                                if( pn->type & DSD_IS_CAMERA )
                                    entry = Tcl_FindHashEntry( &double_camparams, tcl_cmdstr );
                            }

                            /* IF A VALID PARAMETER WAS LOCATED */
                            if( entry )
                            {
                                /* GET PARAM REFERENCE INTO NODE */
                                pdouble = (double*)(((char*)pn) + (int)Tcl_GetHashValue( entry ));

                                /* ADD A NEW ENTRY TO THE HASH TABLE IF NEEDED */
                                entry = Tcl_CreateHashEntry( &limit_hash, (char*)pdouble, &new_item );
                                if( new_item )
                                {
                                    plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
                                    plim->id            = id;
                                    plim->indirect      = 0;
                                    plim->param         = pdouble;
                                    plim->enabled       = 1;
                                    plim->min           = *pdouble;
                                    plim->max           = *pdouble;
                                    Tcl_SetHashValue( entry, (ClientData)plim );
                                }
                                else
                                {
                                    plim = (DOUG_LIMIT_PARAM*)Tcl_GetHashValue( entry );
                                }
                            }
                            else
                            {
                                if( entry = Tcl_FindHashEntry( &proc_camparams, tcl_cmdstr ) )
                                {
									if( pn->type & DSD_IS_CAMERA )
									{
										reltype = (int)Tcl_GetHashValue( entry );

										entry = Tcl_CreateHashEntry( &proclimit_hash, (char*)((id << 8)|reltype), &new_item );
										if( new_item )
										{
											plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
											Tcl_SetHashValue( entry, (ClientData)plim );
											plim->id            = id;
											plim->indirect      = 1;
											plim->vtype         = reltype;
											plim->enabled       = 1;
											plim->GetVal        = DOUG_CAM_getval_double;
											plim->SetVal        = DOUG_CAM_setval_double;
											plim->min           = DOUG_CAM_getval_double( id, reltype ) - 0.001;
											plim->max           = plim->min + 0.001;
										}
										else
										{
											plim->id            = id;
											plim->indirect      = 1;
											plim->vtype         = reltype;
											plim->enabled       = 1;
										}
									}
                                }
                                else if( entry = Tcl_FindHashEntry( &proc_nodeparams, tcl_cmdstr ) )
                                {
                                    reltype = (int)Tcl_GetHashValue( entry );

                                    entry = Tcl_CreateHashEntry( &proclimit_hash, (char*)((id << 8)|reltype), &new_item );
                                    if( new_item )
                                    {
                                        plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
                                        Tcl_SetHashValue( entry, (ClientData)plim );
                                        plim->id            = id;
                                        plim->indirect      = 1;
                                        plim->vtype         = reltype;
                                        plim->enabled       = 1;
                                        plim->GetVal        = DOUG_NODE_getval_double;
                                        plim->SetVal        = DOUG_NODE_setval_double;
                                        plim->min           = DOUG_NODE_getval_double( id, reltype ) - 0.001;
                                        plim->max           = plim->min + 0.001;
                                    }
                                    else
                                    {
                                        plim->id            = id;
                                        plim->indirect      = 1;
                                        plim->vtype         = reltype;
                                        plim->enabled       = 1;
                                    }
                                }
                                else if( entry = Tcl_FindHashEntry( &proc_litparams, tcl_cmdstr ) )
                                {
									if( pn->type & DSD_IS_LIGHT )
									{
										reltype = (int)Tcl_GetHashValue( entry );

										entry = Tcl_CreateHashEntry( &proclimit_hash, (char*)((id << 8)|reltype), &new_item );
										if( new_item )
										{
											plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
											Tcl_SetHashValue( entry, (ClientData)plim );
											plim->id            = id;
											plim->indirect      = 1;
											plim->vtype         = reltype;
											plim->enabled       = 1;
											plim->GetVal        = DOUG_LIT_getval_double;
											plim->SetVal        = DOUG_LIT_setval_double;
											plim->min           = DOUG_LIT_getval_double( id, reltype ) - 0.001;
											plim->max           = plim->min + 0.001;
										}
										else
										{
											plim->id            = id;
											plim->indirect      = 1;
											plim->vtype         = reltype;
											plim->enabled       = 1;
										}
									}
                                }
								else if( !strcmp( tcl_cmdstr, "-parent" ) )
								{
									reltype = NODE_PARENT;
									entry = Tcl_CreateHashEntry( &limit_hash, (char*)((id << 8)|reltype), &new_item );
									if( new_item )
									{
										plim = (DOUG_LIMIT_PARAM*)malloc( sizeof(DOUG_LIMIT_PARAM) );
										Tcl_SetHashValue( entry, (ClientData)plim );
										plim->id            = id;
										plim->indirect      = 0;
										plim->vtype         = reltype;
										plim->enabled       = 1;
										plim->iparam		= &(pn->parent_id);
										plim->ival			= pn->parent_id;
									}
									else
									{
										plim = (DOUG_LIMIT_PARAM*)Tcl_GetHashValue( entry );
										plim->id            = id;
										plim->indirect      = 0;
										plim->vtype         = reltype;
										plim->enabled       = 1;
										plim->iparam		= &(pn->parent_id);
										plim->ival			= pn->parent_id;
									}
								}
                                else
                                {
                                    Tcl_AppendResult( interp, "doug.node ", pn->name, " limit (invalid argument \"", tcl_cmdstr, "\")", NULL );
                                    return TCL_ERROR;
                                }
                            }
                        }
                    }
                }
                break;
            }
        }
        else
        {
            Tcl_AppendResult( interp, "doug.node ", pn->name, "(unknown command \"", Tcl_GetString( objv[i] ), "\")", NULL );
            return TCL_ERROR;
        }
    }

    return TCL_OK;
}

« Using the FOV overlay | EDGE User’s Guide | Using the doug callback command »

[4]: javascript:toggleObj('togglecode_id0','hide','Show DOUG_NODE_cmd source code','Show DOUG_NODE_cmd source code','')