Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

plug_render.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002    Major portions of this software are copyrighted by the Medical College
00003    of Wisconsin, 1994-2000, and are released under the Gnu General Public
00004    License, Version 2.  See the file README.Copyright for details.
00005 ******************************************************************************/
00006 
00007 #include "afni.h"
00008 #include "mri_render.h"
00009 #include "mcw_graf.h"
00010 #include "parser.h"
00011 #include <ctype.h>
00012 
00013 #ifndef ALLOW_PLUGINS
00014 #  error "Plugins not properly set up -- see machdep.h"
00015 #endif
00016 
00017 #undef REND_DEBUG
00018 #define ONLY_AXIAL
00019 
00020 /***********************************************************************
00021   Plugin to render a volume dataset.  Makes a custom interface.
00022   Modified from plug_drawdset.c by RWCox - February 1999.
00023 ************************************************************************/
00024 
00025 /*---------- prototypes for internal routines ----------*/
00026 
00027 char * REND_main( PLUGIN_interface * ) ;                 /* called from AFNI */
00028 
00029 void REND_make_widgets(void) ;                           /* initialization */
00030 
00031 void REND_done_CB   ( Widget , XtPointer , XtPointer ) ; /* Done button */
00032 void REND_draw_CB   ( Widget , XtPointer , XtPointer ) ; /* Draw button */
00033 void REND_help_CB   ( Widget , XtPointer , XtPointer ) ; /* Help button */
00034 void REND_reload_CB ( Widget , XtPointer , XtPointer ) ; /* Reload button */
00035 void REND_choose_CB ( Widget , XtPointer , XtPointer ) ; /* Choose button */
00036 void REND_xhair_CB  ( Widget , XtPointer , XtPointer ) ; /* See Xhairs toggle */
00037 void REND_dynamic_CB( Widget , XtPointer , XtPointer ) ; /* DynaDraw toggle */
00038 void REND_accum_CB  ( Widget , XtPointer , XtPointer ) ; /* Accumulate toggle */
00039 void REND_angle_CB  ( MCW_arrowval * , XtPointer ) ;     /* Angle arrowvals */
00040 void REND_param_CB  ( MCW_arrowval * , XtPointer ) ;     /* Cutout arrowvals */
00041 void REND_precalc_CB( MCW_arrowval * , XtPointer ) ;     /* Precalc menu */
00042 void REND_clip_CB   ( MCW_arrowval * , XtPointer ) ;     /* Clip arrowvals */
00043 
00044 void REND_xhair_recv( int,int , int *, void * ) ;        /* 29 Mar 1999 */
00045 
00046 void REND_environ_CB( char * ) ;                         /* 20 Jun 2000 */
00047 
00048 void   REND_choose_av_CB      ( MCW_arrowval * , XtPointer ) ; /* Sub-brick menus */
00049 char * REND_choose_av_label_CB( MCW_arrowval * , XtPointer ) ;
00050 void   REND_opacity_scale_CB  ( MCW_arrowval * , XtPointer ) ;
00051 
00052 void REND_finalize_dset_CB( Widget , XtPointer , MCW_choose_cbs * ) ; /* dataset chosen */
00053 
00054 void REND_reload_dataset(void) ;  /* actual reloading work */
00055 void REND_xhair_underlay(void) ;  /* make the crosshairs - in the underlay */
00056 void REND_xhair_overlay(void)  ;  /* make the crosshairs - in the overlay  */
00057 
00058 static PLUGIN_interface * plint = NULL ;                 /* what AFNI sees */
00059 
00060 void REND_textact_CB( Widget , XtPointer , XtPointer ) ; /* press Enter in a textfield */
00061 
00062 static float angle_fstep  = 5.0 ;
00063 static float cutout_fstep = 5.0 ;
00064 
00065 #define NUM_precalc    3
00066 static char * precalc_strings[] = { "Low" , "Medium" , "High" } ;
00067 static int    precalc_mode[]    = { PMODE_LOW,PMODE_MEDIUM,PMODE_HIGH } ;
00068 
00069 #define MODE_LOW       0
00070 #define MODE_MEDIUM    1
00071 #define MODE_HIGH      2
00072 
00073 #ifdef SGI
00074 static int   precalc_ival   = MODE_LOW    ;
00075 #else
00076 static int   precalc_ival   = MODE_MEDIUM ;
00077 #endif
00078 
00079 /*==========================================================================*/
00080 #define ALLOW_INCROT   /* 26 Apr 2002 - RWCox */
00081 #ifdef  ALLOW_INCROT
00082 
00083   /** prototypes for incremental rotation matrix/angles stuff **/
00084 
00085  static void REND_inc_angles( int,float, float *,float *,float *) ;
00086  static THD_dmat33 REND_rotmatrix( int,double , int,double , int,double ) ;
00087  static void REND_rotmatrix_to_angles( THD_dmat33, double *,double *,double *);
00088 
00089   /** toggle button for incremental rotations **/
00090 
00091  static MCW_bbox *incrot_bbox ;
00092 
00093   /** callback for above toggle **/
00094 
00095  static void REND_incrot_CB(Widget,XtPointer,XtPointer) ;
00096 
00097   /** prototype for what happens when user increments angles **/
00098 
00099  static void REND_do_incrot( MCW_arrowval * ) ;
00100 
00101 #endif /* ALLOW_INCROT */
00102 /*==========================================================================*/
00103 
00104 /***********************************************************************
00105    Set up the interface to the user.  Note that we bypass the
00106    normal interface creation, and simply have the menu selection
00107    directly call the main function, which will create a custom
00108    set of interface widgets.
00109 ************************************************************************/
00110 
00111 
00112 DEFINE_PLUGIN_PROTOTYPE
00113 
00114 PLUGIN_interface * PLUGIN_init( int ncall )
00115 {
00116    char * env ;
00117    float  val ;
00118    int    ii  ;
00119 
00120    if( ncall > 0 ) return NULL ;  /* only one interface */
00121 
00122    plint = PLUTO_new_interface( "Render Dataset" , NULL , NULL ,
00123                                 PLUGIN_CALL_IMMEDIATELY , REND_main ) ;
00124 
00125    PLUTO_add_hint( plint , "Volume Rendering" ) ;
00126 
00127    PLUTO_set_sequence( plint , "A:graphics" ) ;
00128 
00129    /***----- retrieve relevant environment variables, if any -----***/
00130 
00131    env = getenv("AFNI_RENDER_ANGLE_DELTA") ;
00132    if( env != NULL ){
00133       val = strtod(env,NULL) ;
00134       if( val > 0.0 && val < 100.0 ) angle_fstep = val ;
00135    }
00136    PLUTO_register_environment_numeric( "AFNI_RENDER_ANGLE_DELTA" ,
00137                                        "Angle stepsize in deg (volume renderer)" ,
00138                                        1,9,0,(int)angle_fstep, REND_environ_CB );
00139 
00140    /*--*/
00141 
00142    env = getenv("AFNI_RENDER_CUTOUT_DELTA") ;
00143    if( env != NULL ){
00144       val = strtod(env,NULL) ;
00145       if( val > 0.0 && val < 100.0 ) cutout_fstep = val ;
00146    }
00147    PLUTO_register_environment_numeric( "AFNI_RENDER_CUTOUT_DELTA" ,
00148                                        "Cutout stepsize in mm (volume renderer)" ,
00149                                        1,9,0,(int)cutout_fstep, REND_environ_CB );
00150 
00151    /*--*/
00152 
00153    env = getenv("AFNI_RENDER_PRECALC_MODE") ;
00154    if( env != NULL ){
00155       for( ii=0 ; ii < NUM_precalc ; ii++ )
00156          if( strcmp(env,precalc_strings[ii]) == 0 ) break ;
00157       if( ii < NUM_precalc ) precalc_ival = precalc_mode[ii] ;
00158    }
00159 
00160    /*--*/
00161 
00162    env = getenv("AFNI_RENDER_SHOWTHRU_FAC") ;
00163    if( env != NULL ){
00164       val = strtod(env,NULL) ;
00165       if( val < 0.0 || val > 1.0 ) val = 1.0 ;
00166    } else {
00167       val = 1.0 ;
00168    }
00169    PLUTO_register_environment_numeric( "AFNI_RENDER_SHOWTHRU_FAC" ,
00170                                        "ShowThru mixing factor (volume renderer)",
00171                                        30,100,2,(int)rint(100.0*val) , NULL ) ;
00172 
00173    /*-- done --*/
00174 
00175    return plint ;
00176 }
00177 
00178 /***************************************************************************
00179                           Internal data structures
00180 ****************************************************************************/
00181 
00182 #define NO_DATASET_STRING "[No Dataset is Loaded]"
00183 
00184 /* Interface widgets */
00185 
00186 static Widget shell=NULL , anat_rowcol , info_lab , choose_pb ;
00187 static Widget done_pb , help_pb , draw_pb , reload_pb ;
00188 static MCW_arrowval * roll_av , * pitch_av , * yaw_av , * precalc_av ;
00189 static MCW_bbox * xhair_bbox , * dynamic_bbox , * accum_bbox ;
00190 static MCW_arrowval * choose_av , * opacity_scale_av ;
00191 
00192   /* 08 Mar 2001 - stuff for colored xhairs */
00193 
00194 extern void REND_xhair_EV( Widget, XtPointer, XEvent *, Boolean * ) ;
00195 extern void REND_xhair_ovc_CB( Widget, XtPointer, MCW_choose_cbs * ) ;
00196 static int xhair_ovc = 0 ;
00197 
00198 static char * REND_dummy_av_label[2] = { "[Nothing At All]" , "[Nothing At All]" } ;
00199 
00200 static Widget top_rowcol , anat_frame ;
00201 
00202 #define CLIP_RANGE 32767
00203 
00204 static Widget range_lab ;
00205 static MCW_arrowval * clipbot_av , * cliptop_av ;
00206 
00207 static float  brickfac = 0.0 ;
00208 static Widget range_faclab , clipbot_faclab , cliptop_faclab ;
00209 
00210 void REND_graf_CB( MCW_graf * , void * ) ;
00211 static MCW_graf    * opa_graf ;
00212 static MCW_graf    * gry_graf ;
00213 static MCW_pasgraf * his_graf ;
00214 
00215 static char * xhair_bbox_label[1]   = { "See Xhairs" } ;
00216 static char * dynamic_bbox_label[1] = { "DynaDraw"   } ;
00217 static char * accum_bbox_label[1]   = { "Accumulate" } ;
00218 
00219 /*----------------------------------------------------------------*/
00220 
00221 /* Other data */
00222 
00223 static MCW_DC * dc ;                   /* display context */
00224 static Three_D_View * im3d ;           /* AFNI controller */
00225 static THD_3dim_dataset * dset ;       /* The dataset!    */
00226 static MCW_idcode         dset_idc ;   /* 31 Mar 1999     */
00227 static int new_dset = 0 ;              /* Is it new?      */
00228 static int dset_ival = 0 ;             /* Sub-brick index */
00229 static char dset_title[THD_MAX_NAME] ; /* Title string */
00230 
00231 static MRI_IMAGE * grim=NULL ,
00232                  * opim=NULL ;      /* volumes to render */
00233 static void * render_handle ;       /* rendering struct */
00234 
00235 static MRI_IMAGE * grim_showthru=NULL ,
00236                  * opim_showthru=NULL ;  /* 07 Jan 2000 */
00237 
00238 #define FREEIM(x) if( (x) != NULL ){ mri_free(x); (x)=NULL; }
00239 
00240 #define FREE_VOLUMES                                  \
00241   do{ FREEIM(grim) ; FREEIM(opim) ;                   \
00242       FREEIM(grim_showthru); FREEIM(opim_showthru) ; } while(0) ;
00243 
00244 #define NEED_VOLUMES (grim == NULL || opim == NULL)
00245 
00246 static int   dynamic_flag   = 0      ;
00247 static int   accum_flag     = 0      ;
00248 static float angle_roll     =   70.0 ;
00249 static float angle_pitch    =  120.0 ;
00250 static float angle_yaw      =    0.0 ;
00251 
00252 static int xhair_flag  = 0    ;
00253 static int xhair_ixold = -666 ;  /* remember the past */
00254 static int xhair_jyold = -666 ;
00255 static int xhair_kzold = -666 ;
00256 static int xhair_omold = -666 ;  /* 02 Jun 1999 */
00257 
00258 static int xhair_recv  = -1 ;    /* 29 Mar 1999 */
00259 
00260 #define CHECK_XHAIR_MOTION ( im3d->vinfo->i1             != xhair_ixold || \
00261                              im3d->vinfo->j2             != xhair_jyold || \
00262                              im3d->vinfo->k3             != xhair_kzold || \
00263                              im3d->vinfo->xhairs_orimask != xhair_omold   )
00264 
00265 static int new_data_loaded = 0 ;
00266 
00267 static int renderer_open   = 0 ;
00268 
00269 static int npixels = 0 ;
00270 
00271 /*------------------  Stuff for the image display window -----------------*/
00272 
00273 static MCW_imseq * imseq      = NULL ;
00274 static MRI_IMARR * renderings = NULL ;
00275 
00276 void REND_open_imseq( void ) ;
00277 void REND_update_imseq( void ) ;
00278 void REND_destroy_imseq( void ) ;
00279 XtPointer REND_imseq_getim( int , int , XtPointer ) ;
00280 void REND_seq_send_CB( MCW_imseq * , XtPointer , ISQ_cbs * ) ;
00281 
00282 /*---------------- Stuff for Automate mode --------------*/
00283 
00284 static MCW_bbox * automate_bbox ;
00285 
00286 static int automate_flag = 0 ;
00287 static char * automate_bbox_label[1]   = { "Automate" } ;
00288 
00289 static MCW_arrowval * autoframe_av ;
00290 static Widget autocompute_pb , autocancel_pb ;
00291 
00292 void REND_autoflag_CB   (Widget , XtPointer , XtPointer) ; /* Automate toggle */
00293 void REND_autocompute_CB(Widget , XtPointer , XtPointer) ; /* Compute pushbutton */
00294 void REND_autocancel_CB (Widget , XtPointer , XtPointer) ; /* Cancel pushbutton */
00295 
00296 /*-------------------------- Stuff for cutout logic ----------------------*/
00297 
00298 void REND_cutout_type_CB( MCW_arrowval * , XtPointer ) ;
00299 void REND_numcutout_CB  ( MCW_arrowval * , XtPointer ) ;
00300 void REND_cutout_set_CB ( Widget , XtPointer , XtPointer ) ;
00301 
00302 typedef struct {                            /* widgets for a cutout */
00303    Widget hrc , param_lab , set_pb ;
00304    MCW_arrowval * type_av , * param_av ;
00305    MCW_bbox * mustdo_bbox ;
00306 } REND_cutout ;
00307 
00308 REND_cutout * REND_make_cutout( int n ) ;   /* makes the widgets */
00309 
00310 #define MAX_CUTOUTS 9
00311 static REND_cutout * cutouts[MAX_CUTOUTS] ;
00312 
00313 #define CUTOUT_OR  0
00314 #define CUTOUT_AND 1
00315 static char * cutout_logic_labels[] = { "OR" , "AND" } ;
00316 
00317 static char * cutout_mustdo_names[] = { "NO" , "YES" } ;
00318 
00319 static int num_cutouts  = 0 ;
00320 static int logic_cutout = CUTOUT_OR ;
00321 
00322 MCW_arrowval * numcutout_av ;
00323 MCW_arrowval * logiccutout_av ;
00324 
00325 typedef struct {                                     /* store the status */
00326    int num , logic ;                                 /* of the cutouts   */
00327    int   type[MAX_CUTOUTS] , mustdo[MAX_CUTOUTS] ;
00328    float param[MAX_CUTOUTS] , opacity_scale ;
00329    char  param_str[MAX_CUTOUTS][AV_MAXLEN+4] ;
00330 } CUTOUT_state ;
00331 
00332 #define MIN_OPACITY_SCALE 0.000
00333 
00334 CUTOUT_state current_cutout_state , old_cutout_state ;
00335 
00336 void REND_load_cutout_state(void) ;                /* load from widgets */
00337 int REND_cutout_state_changed(void) ;              /* has it changed? */
00338 void REND_cutout_blobs(MRI_IMAGE *) ;              /* actually do cutouts */
00339 
00340 static char * mustdo_bbox_label[1] = { "Must Do" } ;
00341 
00342 /*-----------------   stuff for evaluation of expressions   ------------*/
00343 
00344 static double atoz[26] ;  /* values of 'a', 'b', ..., 'z' in expressions */
00345 
00346 #define N_IND  13  /* 'n' */
00347 #define T_IND  19  /* 't' */
00348 #define X_IND  23  /* 'x' */
00349 #define Y_IND  24  /* 'y' */
00350 #define Z_IND  25  /* 'z' */
00351 
00352 float REND_evaluate( MCW_arrowval * ) ;
00353 
00354 /*-------------------- Icon Pixmap for Image Window ----------------------*/
00355 
00356 static Pixmap afni48ren_pixmap = XmUNSPECIFIED_PIXMAP ;
00357 #define afni48ren_width 48
00358 #define afni48ren_height 48                /* from file afni48ren.xbm */
00359 static unsigned char afni48ren_bits[] = {
00360    0xff, 0xff, 0xc1, 0xc1, 0xff, 0xff, 0xff, 0x7f, 0x60, 0x00, 0xfe, 0xff,
00361    0xff, 0x0f, 0x30, 0x10, 0xf0, 0xff, 0xff, 0x01, 0x37, 0xf0, 0x80, 0xff,
00362    0x7f, 0xe0, 0x77, 0xe0, 0x07, 0xff, 0x7f, 0xfe, 0xe0, 0x00, 0x3f, 0xff,
00363    0x7f, 0x1e, 0xc0, 0x03, 0x38, 0xff, 0x3f, 0x00, 0x87, 0xe7, 0x01, 0xff,
00364    0x3f, 0xf0, 0x07, 0xe7, 0x0f, 0xfe, 0x3f, 0x7f, 0xc0, 0x04, 0x7e, 0xfe,
00365    0x3f, 0x0f, 0xe6, 0x67, 0x70, 0xfe, 0x3f, 0xe0, 0xa7, 0xe7, 0x03, 0xfe,
00366    0x1f, 0xfc, 0x21, 0x83, 0x3f, 0xfc, 0x9f, 0x1f, 0xe0, 0x00, 0xfc, 0xfc,
00367    0x9f, 0x83, 0xc7, 0xe1, 0xc1, 0xfc, 0x1f, 0xf0, 0x87, 0xe7, 0x0f, 0xfc,
00368    0x0f, 0x7f, 0x00, 0x07, 0x7e, 0xf8, 0xcf, 0x0f, 0xc0, 0x04, 0xf0, 0xf9,
00369    0xcf, 0x80, 0xe7, 0xe7, 0x81, 0xf9, 0x0f, 0xf0, 0xa7, 0xe3, 0x1f, 0xf8,
00370    0x0f, 0x7f, 0xe0, 0x00, 0xfe, 0xf9, 0xcf, 0x0f, 0xc0, 0x01, 0xe0, 0xf1,
00371    0xc7, 0x00, 0x87, 0xe3, 0x00, 0xf0, 0x07, 0xf8, 0x07, 0xe7, 0x1f, 0xf0,
00372    0x87, 0xff, 0xc0, 0x86, 0xff, 0xf1, 0xe7, 0x07, 0xe0, 0x03, 0xe0, 0xf3,
00373    0x77, 0x00, 0xe0, 0x00, 0x00, 0xe6, 0x03, 0x00, 0xc0, 0x01, 0x00, 0xe0,
00374    0x03, 0x00, 0x80, 0x03, 0x00, 0xe0, 0x03, 0xf8, 0x0f, 0xf8, 0x1f, 0xe0,
00375    0x81, 0xff, 0x3f, 0xfc, 0xff, 0xc1, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff,
00376    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf8, 0xff, 0xff, 0x1f, 0xc0,
00377    0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00378    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x74, 0x31, 0xc4, 0xe8, 0xc6,
00379    0xad, 0x67, 0xad, 0xb7, 0xcd, 0xda, 0xad, 0x57, 0xad, 0xb7, 0xad, 0xfa,
00380    0x31, 0x56, 0x2d, 0xc6, 0xad, 0xfa, 0xb5, 0x57, 0xad, 0xd7, 0xad, 0x8a,
00381    0xad, 0x37, 0xad, 0xb7, 0x6d, 0xda, 0xad, 0x77, 0xad, 0xb7, 0xed, 0xda,
00382    0x2d, 0x74, 0x31, 0xb4, 0xe8, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00383    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
00384 
00385 /*-------------------- Functional overlay stuff ----------------------*/
00386 
00387 #define INVALIDATE_OVERLAY do{ FREEIM(ovim) ; } while(0)
00388 
00389 #define DO_OVERLAY   ((func_dset != NULL && func_see_overlay) ||          \
00390                       func_see_ttatlas || (xhair_flag && xhair_ovc > 0) )
00391 
00392 #define NEED_OVERLAY (DO_OVERLAY && ovim == NULL)
00393 #define NEED_RELOAD  (NEED_VOLUMES || NEED_OVERLAY)
00394 
00395 #define TURNOFF_OVERLAY_WIDGETS                                   \
00396   do{ XmString xstr ;                                              \
00397       xstr = XmStringCreateLtoR( NO_DATASET_STRING ,                \
00398                                  XmFONTLIST_DEFAULT_TAG ) ;          \
00399       XtVaSetValues( wfunc_info_lab , XmNlabelString,xstr , NULL ) ;  \
00400       XmStringFree(xstr) ;                                             \
00401                                                                         \
00402       xstr = REND_range_label() ;                                        \
00403       XtVaSetValues( wfunc_range_label , XmNlabelString , xstr , NULL ) ; \
00404       XmStringFree(xstr) ;                                                 \
00405                                                                             \
00406       xstr = REND_autorange_label() ;                                        \
00407       XtVaSetValues( wfunc_range_bbox->wbut[0], XmNlabelString,xstr, NULL ) ; \
00408       XmStringFree(xstr) ;                                                    \
00409                                                                              \
00410       AV_SENSITIZE( wfunc_color_av  , False ) ;                             \
00411       AV_SENSITIZE( wfunc_thresh_av , False ) ;                            \
00412   } while(0)
00413 
00414 void REND_func_widgets(void) ;
00415 void REND_init_cmap(void) ;
00416 void REND_reload_func_dset(void) ;
00417 void REND_reload_renderer(void) ;
00418 
00419 void REND_overlay_ttatlas(void) ; /* 12 Jul 2001 */
00420 
00421 static Widget wfunc_open_pb ;
00422 void REND_open_func_CB( Widget , XtPointer , XtPointer ) ;
00423 
00424 static Widget wfunc_frame=NULL , wfunc_rowcol , wfunc_choose_pb ,
00425               wfunc_uber_rowcol , wfunc_info_lab , wfunc_vsep ;
00426 
00427 static Widget wfunc_thr_rowcol , wfunc_thr_label , wfunc_thr_scale=NULL ,
00428               wfunc_thr_pval_label ;
00429 static MCW_arrowval * wfunc_thr_top_av ;
00430 
00431 static Widget wfunc_color_rowcol , wfunc_color_label ;
00432 static MCW_pbar * wfunc_color_pbar=NULL ;
00433 static MCW_arrowval * wfunc_color_av , * wfunc_thresh_av , * wfunc_colornum_av ;
00434 static MCW_bbox * wfunc_color_bbox ;
00435 
00436 static Widget wfunc_choices_rowcol , wfunc_choices_label ,
00437               wfunc_buck_frame , wfunc_buck_rowcol ,
00438               wfunc_opacity_frame , wfunc_opacity_rowcol ,
00439               wfunc_range_rowcol , wfunc_range_frame ;
00440 
00441 static Widget wfunc_range_label ;
00442 static MCW_arrowval * wfunc_opacity_av , * wfunc_range_av ;
00443 static MCW_arrowval * wfunc_range_rotate_av ; /* 30 Mar 2001 */
00444 static MCW_bbox * wfunc_see_overlay_bbox , * wfunc_cut_overlay_bbox ,
00445                 * wfunc_kill_clusters_bbox , * wfunc_range_bbox ;
00446 static MCW_arrowval * wfunc_clusters_rmm_av , * wfunc_clusters_vmul_av ;
00447 
00448 static MCW_bbox * wfunc_see_ttatlas_bbox ;    /* 24 Jul 2001 */
00449 
00450 static Widget wfunc_pbar_menu , wfunc_pbar_equalize_pb , wfunc_pbar_settop_pb ;
00451 static Widget wfunc_pbar_saveim_pb ;
00452 static MCW_arrowval * wfunc_pbar_palette_av ;
00453 static MCW_arrowval * wfunc_pbar_mixshade_av ;  /* 21 Dec 1999 */
00454 
00455 extern void REND_pbarmenu_CB( Widget , XtPointer , XtPointer ) ;
00456 extern void REND_pbarmenu_EV( Widget , XtPointer , XEvent * , Boolean * ) ;
00457 extern void REND_palette_av_CB( MCW_arrowval * , XtPointer ) ;
00458 extern void REND_mixshade_av_CB( MCW_arrowval * , XtPointer ) ;  /* 21 Dec 1999 */
00459 extern void REND_set_pbar_top_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00460 extern void REND_finalize_saveim_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00461 
00462 #define DEFAULT_FUNC_RANGE 10000.0
00463 
00464 static int   func_use_autorange = 1   ;
00465 static float func_threshold     = 0.5 ;
00466 static float func_thresh_top    = 1.0 ;
00467 static int   func_use_thresh    = 1   ;   /* not currently alterable */
00468 static float func_color_opacity = 0.5 ;
00469 static int   func_see_overlay   = 0   ;
00470 static int   func_see_ttatlas   = 0   ;   /* 24 Jul 2001 */
00471 static int   func_cut_overlay   = 0   ;
00472 static int   func_kill_clusters = 0   ;
00473 static float func_clusters_rmm  = 1.0 ;
00474 static float func_clusters_vmul = 200.0 ;
00475 static int   func_posfunc       = 0   ;
00476 static float func_range         = DEFAULT_FUNC_RANGE ;
00477 static float func_autorange     = DEFAULT_FUNC_RANGE ;
00478 static int   func_computed      = 0 ;
00479 
00480 #define FUNC_RANGE  \
00481   ((func_range==0.0 || func_use_autorange ) ? func_autorange : func_range)
00482 
00483 static int   func_showthru      = 0 ;  /* 07 Jan 2000 */
00484 static int   func_showthru_pass = 0 ;
00485 static int   func_showthru_dcue = 0 ;  /* 11 Sep 2001 */
00486 
00487 #define NOSHADE 1
00488 #define NOMIX   2
00489 static int   func_mixshade      = 0 ;    /* 20 Dec 1999 */
00490 
00491 static THD_3dim_dataset * func_dset = NULL ;
00492 static MCW_idcode         func_dset_idc ;   /* 31 Mar 1999 */
00493 
00494 static int func_color_ival  = 0 ;
00495 static int func_thresh_ival = 0 ;
00496 
00497 static byte func_rmap[256] , func_gmap[256] , func_bmap[256] ;
00498 static int func_ncmap ;
00499 static int func_cmap_set = 0 ;
00500 
00501 static MRI_IMAGE * ovim ;
00502 
00503 static char func_dset_title[THD_MAX_NAME] ; /* Title string */
00504 
00505 char * REND_thresh_tlabel_CB( MCW_arrowval * , XtPointer ) ;
00506 void REND_setup_color_pbar(void) ;
00507 XmString REND_range_label(void) ;
00508 XmString REND_autorange_label(void) ;
00509 
00510 void REND_range_bbox_CB    ( Widget , XtPointer , XtPointer ) ;
00511 void REND_color_bbox_CB    ( Widget , XtPointer , XtPointer ) ;
00512 void REND_thr_scale_CB     ( Widget , XtPointer , XtPointer ) ;
00513 void REND_thr_scale_drag_CB( Widget , XtPointer , XtPointer ) ;
00514 void REND_see_overlay_CB   ( Widget , XtPointer , XtPointer ) ;
00515 void REND_cut_overlay_CB   ( Widget , XtPointer , XtPointer ) ;
00516 void REND_kill_clusters_CB ( Widget , XtPointer , XtPointer ) ;
00517 void REND_finalize_func_CB ( Widget , XtPointer , MCW_choose_cbs * ) ;
00518 void REND_see_ttatlas_CB   ( Widget , XtPointer , XtPointer ) ;   /* 24 Jul 2001 */
00519 
00520 void REND_range_av_CB     ( MCW_arrowval * , XtPointer ) ;
00521 void REND_thresh_top_CB   ( MCW_arrowval * , XtPointer ) ;
00522 void REND_colornum_av_CB  ( MCW_arrowval * , XtPointer ) ;
00523 void REND_color_opacity_CB( MCW_arrowval * , XtPointer ) ;
00524 void REND_clusters_av_CB  ( MCW_arrowval * , XtPointer ) ;
00525 
00526 void REND_color_pbar_CB( MCW_pbar * , XtPointer , int ) ;
00527 void REND_set_thr_pval(void) ;
00528 
00529 #define COLSIZE AV_colsize()  /* to modify optmenus -- 11 Dec 2001 */
00530 
00531 #undef FIX_SCALE_SIZE
00532 #undef HIDE_SCALE
00533 #ifdef FIX_SCALE_SIZE_PROBLEM
00534 #  define FIX_SCALE_SIZE                                        \
00535      do{ int sel_height ;  XtPointer sel_ptr ;                  \
00536          if( wfunc_thr_scale != NULL ){                         \
00537            XtVaGetValues( wfunc_thr_scale ,                     \
00538                              XmNuserData , &sel_ptr , NULL ) ;  \
00539            sel_height = (int) sel_ptr ;                         \
00540            XtVaSetValues( wfunc_thr_scale ,                     \
00541                              XmNheight , sel_height , NULL ) ;  \
00542            XtManageChild(wfunc_thr_scale) ;                     \
00543        } } while(0)
00544 #  define HIDE_SCALE \
00545      do{ if(wfunc_thr_scale != NULL) XtUnmanageChild(wfunc_thr_scale); } while(0)
00546 #else
00547 #  define FIX_SCALE_SIZE /* nada */
00548 #  define HIDE_SCALE     /* nada */
00549 #endif
00550 
00551 /*-------------------------------------------------------------------*/
00552 #define USE_SCRIPTING
00553 #ifdef USE_SCRIPTING
00554 
00555   static Widget script_menu , script_cbut ,                     /* the menu */
00556                 script_save_this_pb , script_save_many_pb ,
00557                 script_read_exec_pb , script_read_this_pb  ;
00558   static MCW_bbox * script_load_bbox , * script_brindex_bbox ;
00559 
00560   void REND_script_CB(Widget , XtPointer , XtPointer) ;
00561   void REND_script_menu( Widget ) ;
00562   void REND_script_load_CB( Widget , XtPointer , XtPointer ) ;
00563   void REND_script_brindex_CB( Widget , XtPointer , XtPointer ) ;
00564   void REND_save_this_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00565   void REND_save_many_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00566   void REND_read_this_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00567   void REND_read_this_finalize_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00568   void REND_read_exec_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00569 
00570   static int script_load      =  0 ;
00571   static int script_load_last = -1 ;
00572   static int script_brindex   =  0 ;
00573 
00574   static int script_dontdraw  =  0 ;  /* 24 Nov 2000 */
00575 
00576 #define SCRIPT_GRAFS  /* Bastille Day 1999 */
00577 #ifdef SCRIPT_GRAFS
00578   typedef struct {
00579      int nh , spl , xh[MAX_GHANDS] , yh[MAX_GHANDS] ;
00580   } graf_state ;
00581 
00582   static int graf_states_equal( graf_state * g1 , graf_state * g2 )
00583   {  int ii ;
00584      if( g1->nh  != g2->nh  ) return 0 ;
00585      if( g1->spl != g2->spl ) return 0 ;
00586      for( ii=0 ; ii < g1->nh ; ii++ ){
00587         if( g1->xh[ii] != g2->xh[ii] ) return 0 ;
00588         if( g1->yh[ii] != g2->yh[ii] ) return 0 ;
00589      }
00590      return 1 ;
00591   }
00592 
00593   static void graf_state_get( MCW_graf * gp , graf_state * gs )
00594   {
00595      GRAF_get_setup( gp , &(gs->nh) , gs->xh , gs->yh , &(gs->spl) ) ;
00596      return ;
00597   }
00598 
00599   static void graf_state_put( MCW_graf * gp , graf_state * gs )
00600   {
00601      GRAF_put_setup( gp , gs->nh , gs->xh , gs->yh , gs->spl ) ;
00602      return ;
00603   }
00604 
00605   static MCW_bbox * script_graf_bbox ;
00606   void REND_script_graf_CB( Widget , XtPointer , XtPointer ) ;
00607   static int script_graf = 0 ;
00608 #endif /* SCRIPT_GRAFS */
00609 
00610 #define SCRIPT_DSETS
00611 #ifdef SCRIPT_DSETS
00612   /* 12 Apr 2000: stuff for changing datasets from script */
00613 
00614   static MCW_bbox * script_dset_bbox ;
00615   void REND_script_dset_CB( Widget , XtPointer , XtPointer ) ;
00616   static int script_dsetchange =  0 ;
00617 #endif
00618 
00619   /* data structure to store the state of rendering operations */
00620 
00621   typedef struct {
00622 
00623      char dset_name[THD_MAX_NAME] , func_dset_name[THD_MAX_NAME] ;
00624      MCW_idcode dset_idc          , func_dset_idc ;
00625      int dset_ival , func_color_ival , func_thresh_ival ;
00626 
00627      int clipbot , cliptop ;
00628 
00629      float angle_roll , angle_pitch , angle_yaw ;
00630      int xhair_flag ;
00631      int xhair_ovc  ;  /* 08 Mar 2001 */
00632 
00633      float func_threshold     ;
00634      float func_thresh_top    ;
00635      float func_color_opacity ;
00636      int   func_see_overlay   ;
00637      int   func_see_ttatlas   ;   /* 24 Jul 2001 */
00638      int   func_cut_overlay   ;
00639      int   func_kill_clusters ;
00640      float func_clusters_rmm  ;
00641      float func_clusters_vmul ;
00642      int   func_use_autorange ;
00643      float func_range         ;
00644 
00645      int pbar_mode , pbar_npane ;
00646      float pbar_pval[NPANE_MAX+1] ;
00647 
00648      CUTOUT_state current_cutout_state ;
00649 
00650 #ifdef SCRIPT_GRAFS
00651      graf_state bright_graf_state , opacity_graf_state ;
00652 #endif
00653 
00654   } RENDER_state ;
00655 
00656   typedef struct {
00657       int num , nall ;
00658       RENDER_state ** rsarr ;
00659   } RENDER_state_array ;
00660 
00661 #  define RSA_SUBSTATE(name,nn) ((name)->rsarr[(nn)])
00662 #  define RSA_COUNT(name)       ((name)->num)
00663 #  define INC_RSA 32
00664 
00665 #  define INIT_RSA(name)                                                               \
00666      do{ int iq ; (name) = (RENDER_state_array *) malloc(sizeof(RENDER_state_array)) ; \
00667          (name)->num = 0 ; (name)->nall = INC_RSA ;                                   \
00668          (name)->rsarr = (RENDER_state **)malloc(sizeof(RENDER_state *)*INC_RSA) ;   \
00669          for( iq=0 ; iq < INC_RSA ; iq++ ) (name)->rsarr[iq] = NULL ;               \
00670          break ; } while(0)
00671 
00672 #  define ADDTO_RSA(name,imm)                                                        \
00673      do{ int nn , iq ;                                                                \
00674          if( (name)->num == (name)->nall ){                                            \
00675             nn = (name)->nall = 1.1*(name)->nall + INC_RSA ;                            \
00676             (name)->rsarr = realloc( (name)->rsarr,sizeof(RENDER_state *)*nn );          \
00677             for( iq=(name)->num ; iq < (name)->nall ; iq++ ) (name)->rsarr[iq] = NULL ; } \
00678          nn = (name)->num ; ((name)->num)++ ;                                             \
00679          (name)->rsarr[nn] = (imm) ; break ; } while(0)
00680 
00681 #  define FREE_RSA(name)       \
00682      do{ if( (name) != NULL ){ \
00683             free((name)->rsarr); free((name)); (name) = NULL; } break; } while(0)
00684 
00685 #  define DESTROY_RSA(name)                                              \
00686      do{ int nn ;                                                         \
00687          if( (name) != NULL ){                                             \
00688             for( nn=0 ; nn < (name)->num ; nn++ ) free((name)->rsarr[nn]) ; \
00689             free((name)->rsarr); free((name)); (name) = NULL; } break; } while(0)
00690 
00691   void   REND_state_to_widgets( RENDER_state * ) ;
00692   void   REND_widgets_to_state( RENDER_state * ) ;
00693 
00694   char * REND_save_state      ( RENDER_state * , RENDER_state * ) ;
00695 
00696   RENDER_state_array * REND_read_states( char * , RENDER_state * ) ;
00697 
00698   static RENDER_state_array * renderings_state = NULL ;
00699   static RENDER_state * last_rendered_state = NULL ;
00700 
00701 #endif /* USE_SCRIPTING */
00702 /*-------------------------------------------------------------------*/
00703 
00704 /***************************************************************************
00705   Will be called from AFNI when user selects from Plugins menu.
00706 ****************************************************************************/
00707 
00708 char * REND_main( PLUGIN_interface * plint )
00709 {
00710    XmString xstr ;
00711 
00712    /*-- sanity checks --*/
00713 
00714    if( ! IM3D_OPEN(plint->im3d) ) return "AFNI Controller\nnot opened?!" ;
00715 
00716    if( renderer_open ){
00717       XtMapWidget(shell) ;
00718       XRaiseWindow( XtDisplay(shell) , XtWindow(shell) ) ;
00719       return NULL ;
00720    }
00721 
00722    im3d = plint->im3d ;  /* save for local use */
00723 
00724    /*-- create widgets, first time through --*/
00725 
00726    if( shell == NULL ){
00727       dc = im3d->dc ;        /* save this too */
00728       REND_make_widgets() ;
00729       PLUTO_set_topshell( plint , shell ) ;  /* 22 Sep 2000 */
00730       RWC_visibilize_widget( shell ) ;       /* 27 Sep 2000 */
00731    }
00732 
00733    /*-- set titlebar --*/
00734 
00735    { char ttl[PLUGIN_STRING_SIZE] ;
00736      sprintf( ttl , "AFNI Renderer %s" , AFNI_controller_label(im3d) ) ;
00737      XtVaSetValues( shell , XmNtitle , ttl , NULL ) ;
00738    }
00739 
00740    /*-- set some widget values --*/
00741 
00742    xstr = XmStringCreateLtoR( NO_DATASET_STRING ,
00743                               XmFONTLIST_DEFAULT_TAG ) ;
00744    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
00745    XmStringFree(xstr) ;
00746 
00747    xstr = XmStringCreateLtoR( "Min=?????? Max=??????" ,
00748                               XmFONTLIST_DEFAULT_TAG            ) ;
00749    XtVaSetValues( range_lab , XmNlabelString , xstr , NULL ) ;
00750    XmStringFree(xstr) ;
00751 
00752    AV_assign_ival( clipbot_av , -CLIP_RANGE ) ;
00753    AV_assign_ival( cliptop_av ,  CLIP_RANGE ) ;
00754 
00755    brickfac = 0.0 ;
00756    XtUnmanageChild( range_faclab   ) ;
00757    XtUnmanageChild( clipbot_faclab ) ;
00758    XtUnmanageChild( cliptop_faclab ) ;
00759 
00760    MCW_set_bbox( xhair_bbox   , 0 ) ; xhair_flag   = 0 ; xhair_ovc = 0 ;
00761    MCW_set_bbox( dynamic_bbox , 0 ) ; dynamic_flag = 0 ;
00762    MCW_set_bbox( accum_bbox   , 0 ) ; accum_flag   = 0 ;
00763 
00764    MCW_set_bbox( automate_bbox , 0 ) ; automate_flag = 0 ;
00765    XtSetSensitive( autocompute_pb , False ) ;
00766 
00767    AV_assign_ival( numcutout_av , 0 ) ;      /* turn off cutouts */
00768    REND_numcutout_CB( numcutout_av , NULL ) ;
00769 
00770    REND_load_cutout_state() ; old_cutout_state = current_cutout_state ;
00771 
00772    AV_SENSITIZE( choose_av , False ) ;
00773 
00774    /*--- some of the function widgets, too ---*/
00775 
00776    if( wfunc_frame != NULL ){
00777 
00778       TURNOFF_OVERLAY_WIDGETS ;
00779 
00780    }
00781 
00782    /*-- pop the widget up --*/
00783 
00784    XtMapWidget(shell) ;
00785    PLUTO_cursorize(shell) ;
00786 
00787    /*-- misc initialization --*/
00788 
00789    dset          = NULL ;   /* not rendering anything     */
00790    dset_ival     = 0 ;      /* if we were, it would be #0 */
00791    renderer_open = 1 ;      /* renderer is now open for business */
00792    imseq         = NULL ;   /* no image window is open yet */
00793    grim = opim   = NULL ;   /* don't have volumes to render yet */
00794    render_handle = NULL ;   /* don't have a renderer yet */
00795 
00796    ovim          = NULL ;   /* no overlay volume yet */
00797    func_dset     = NULL ;   /* no functional dataset yet */
00798 
00799    new_data_loaded = 0 ;    /* not yet */
00800 
00801    grim_showthru = opim_showthru = NULL ; /* 07 Jan 2000 */
00802 
00803    set_MCW_pasgraf( his_graf , NULL ) ;  /* set histogram graph to 0's */
00804    redraw_MCW_pasgraf( his_graf ) ;
00805 
00806    xhair_ixold = -666 ; xhair_jyold = -666 ; xhair_kzold = -666 ;
00807 
00808    /* 29 Mar 1999: register to receive updates from AFNI */
00809 
00810 #if 1
00811    xhair_recv = AFNI_receive_init( im3d ,
00812                                    RECEIVE_VIEWPOINT_MASK
00813                                  | RECEIVE_DRAWNOTICE_MASK
00814                                  | RECEIVE_DSETCHANGE_MASK ,
00815                                    REND_xhair_recv , NULL  ,
00816                                   "REND_xhair_recv"         ) ;
00817 #else
00818    xhair_recv = AFNI_receive_init( im3d ,
00819                                    RECEIVE_VIEWPOINT_MASK ,
00820                                    REND_xhair_recv , NULL ,
00821                                   "REND_xhair_recv"         ) ;
00822 #endif
00823 
00824    MPROBE ;
00825    return NULL ;
00826 }
00827 
00828 /*------------------------------------------------------------------------
00829   Make the control popup for this thing
00830 --------------------------------------------------------------------------*/
00831 
00832 /*-- structures defining action buttons (at bottom of popup) --*/
00833 
00834 #define NACT 4  /* number of action buttons */
00835 
00836 static MCW_action_item REND_actor[NACT] = {
00837 
00838  {"Help",REND_help_CB,NULL,
00839   "Displays more help" , "Displays more help",0} ,
00840 
00841  {"Draw",REND_draw_CB,NULL,
00842   "(Re)Draw the image" , "(Re)Draw the image",0} ,
00843 
00844  {"Reload",REND_reload_CB,NULL,
00845   "Reload dataset values" , "Reload dataset values",0} ,
00846 
00847  {"done",REND_done_CB,NULL,
00848   "Close renderer\nand image." , "Close windows",1}
00849 } ;
00850 
00851 #define SEP_HOR(ww)  XtVaCreateManagedWidget(                     \
00852                        "AFNI" , xmSeparatorWidgetClass , (ww) ,   \
00853                           XmNseparatorType , XmSINGLE_LINE ,      \
00854                           XmNinitialResourcesPersistent , False , \
00855                        NULL )
00856 
00857 #define SEP_VER(ww) XtVaCreateManagedWidget(                      \
00858                        "AFNI" , xmSeparatorWidgetClass , (ww) ,   \
00859                           XmNseparatorType , XmDOUBLE_LINE ,      \
00860                           XmNorientation   , XmVERTICAL ,         \
00861                           XmNinitialResourcesPersistent , False , \
00862                        NULL )
00863 
00864 void REND_make_widgets(void)
00865 {
00866    XmString xstr ;
00867    char      str[64] ;
00868    Widget hrc , vrc ;
00869    int ii ;
00870    char * env ;
00871    float val ;
00872 
00873    /***=============================================================*/
00874 
00875    /*** top level shell for window manager ***/
00876 
00877    shell =
00878       XtVaAppCreateShell(
00879            "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
00880 
00881            XmNtitle             , "AFNI Renderer" , /* top of window */
00882            XmNiconName          , "Renderer"      , /* label on icon */
00883            XmNdeleteResponse    , XmDO_NOTHING  ,   /* deletion handled below */
00884            XmNallowShellResize  , True ,            /* let code resize shell? */
00885            XmNmappedWhenManaged , False ,           /* must map it manually */
00886            XmNinitialResourcesPersistent , False ,
00887       NULL ) ;
00888 
00889    DC_yokify( shell , dc ) ; /* 14 Sep 1998 */
00890 
00891 #ifndef DONT_INSTALL_ICONS
00892    if( afni48_good )             /* set icon pixmap */
00893       XtVaSetValues( shell ,
00894                         XmNiconPixmap , afni48_pixmap ,
00895                      NULL ) ;
00896 #endif
00897 
00898    if( MCW_isitmwm(shell) )      /* remove some MWM functions */
00899       XtVaSetValues( shell ,
00900                        XmNmwmFunctions ,
00901                        MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE ,
00902                      NULL ) ;
00903 
00904    XmAddWMProtocolCallback(      /* make "Close" window menu work */
00905            shell ,
00906            XmInternAtom( dc->display , "WM_DELETE_WINDOW" , False ) ,
00907            REND_done_CB , (XtPointer) plint ) ;
00908 
00909    /*** horizontal rowcol to hold ALL interface stuff ***/
00910 
00911    top_rowcol =  XtVaCreateWidget(
00912                   "AFNI" , xmRowColumnWidgetClass , shell ,
00913                      XmNorientation  , XmHORIZONTAL ,
00914                      XmNpacking      , XmPACK_TIGHT ,
00915                      XmNadjustLast   , False ,
00916                      XmNadjustMargin , False ,
00917                      XmNtraversalOn  , False ,
00918                      XmNmarginWidth  , 0 ,
00919                      XmNmarginHeight , 0 ,
00920                      XmNinitialResourcesPersistent , False ,
00921                   NULL ) ;
00922 
00923    /*** vertical rowcolumn widget to hold anat interface stuff ***/
00924 
00925    anat_frame = XtVaCreateWidget(
00926                    "AFNI" , xmFrameWidgetClass , top_rowcol ,
00927                       XmNshadowType , XmSHADOW_ETCHED_IN ,
00928                       XmNshadowThickness , 5 ,
00929                       XmNtraversalOn , False ,
00930                       XmNinitialResourcesPersistent , False ,
00931                    NULL ) ;
00932 
00933    anat_rowcol = XtVaCreateWidget(
00934                   "AFNI" , xmRowColumnWidgetClass , anat_frame ,
00935                      XmNpacking     , XmPACK_TIGHT ,
00936                      XmNorientation , XmVERTICAL ,
00937                      XmNadjustLast  , False ,
00938                      XmNadjustMargin, False ,
00939                      XmNtraversalOn , False ,
00940                      XmNinitialResourcesPersistent , False ,
00941                   NULL ) ;
00942 
00943    /***=============================================================*/
00944 
00945    /*** label at top to let user know who we are ***/
00946 
00947    xstr = XmStringCreateLtoR( NO_DATASET_STRING ,
00948                               XmFONTLIST_DEFAULT_TAG ) ;
00949    info_lab = XtVaCreateManagedWidget(
00950                  "AFNI" , xmLabelWidgetClass , anat_rowcol ,
00951                     XmNlabelString , xstr ,
00952                     XmNrecomputeSize , False ,
00953                     XmNinitialResourcesPersistent , False ,
00954                  NULL ) ;
00955    XmStringFree(xstr) ;
00956    MCW_register_help( info_lab , "Shows dataset being rendered" ) ;
00957 
00958    /***** top row of widgets to choose dataset and sub-brick *****/
00959 
00960    SEP_HOR(anat_rowcol) ;  /* separator widget */
00961 
00962    hrc =  XtVaCreateWidget(
00963            "AFNI" , xmRowColumnWidgetClass , anat_rowcol ,
00964               XmNorientation  , XmHORIZONTAL ,
00965               XmNpacking      , XmPACK_TIGHT ,
00966               XmNadjustLast   , False ,
00967               XmNadjustMargin , False ,
00968               XmNtraversalOn  , False ,
00969               XmNmarginWidth  , 0 ,
00970               XmNmarginHeight , 0 ,
00971               XmNinitialResourcesPersistent , False ,
00972            NULL ) ;
00973 
00974    /*** button to let user choose dataset to render ***/
00975 
00976    xstr = XmStringCreateLtoR( "Choose Underlay Dataset" , XmFONTLIST_DEFAULT_TAG ) ;
00977    choose_pb = XtVaCreateManagedWidget(
00978                   "AFNI" , xmPushButtonWidgetClass , hrc ,
00979                      XmNalignment   , XmALIGNMENT_CENTER ,
00980                      XmNlabelString , xstr ,
00981                      XmNtraversalOn , False ,
00982                      XmNinitialResourcesPersistent , False ,
00983                   NULL ) ;
00984    XmStringFree(xstr) ;
00985    XtAddCallback( choose_pb, XmNactivateCallback, REND_choose_CB, NULL ) ;
00986    MCW_register_help( choose_pb ,
00987                       "Use this to popup a\n"
00988                       "'chooser' that lets\n"
00989                       "you select which\n"
00990                       "dataset to render."
00991                     ) ;
00992 
00993    /*** menu to let user choose sub-brick to deal with ***/
00994 
00995    SEP_VER(hrc) ;
00996 
00997    choose_av = new_MCW_arrowval(
00998                           hrc ,                   /* parent Widget */
00999                           "Brick " ,              /* label */
01000                           MCW_AV_optmenu ,        /* option menu style */
01001                           0 ,                     /* first option */
01002                           1 ,                     /* last option */
01003                           0 ,                     /* initial selection */
01004                           MCW_AV_readtext ,       /* ignored but needed */
01005                           0 ,                     /* decimal shift */
01006                           REND_choose_av_CB ,     /* callback when changed */
01007                           NULL ,                  /* data for above */
01008                           MCW_av_substring_CB ,   /* text creation routine */
01009                           REND_dummy_av_label     /* data for above */
01010                         ) ;
01011 
01012    /*** button to open and close overlay panel ***/
01013 
01014    SEP_VER(hrc) ;
01015 
01016    xstr = XmStringCreateLtoR( "Overlay" , XmFONTLIST_DEFAULT_TAG ) ;
01017    wfunc_open_pb = XtVaCreateManagedWidget(
01018                   "AFNI" , xmPushButtonWidgetClass , hrc ,
01019                      XmNalignment   , XmALIGNMENT_CENTER ,
01020                      XmNlabelString , xstr ,
01021                      XmNtraversalOn , False ,
01022                      XmNinitialResourcesPersistent , False ,
01023                   NULL ) ;
01024    XmStringFree(xstr) ;
01025    XtAddCallback( wfunc_open_pb, XmNactivateCallback, REND_open_func_CB, NULL ) ;
01026 
01027    XtManageChild(hrc) ;
01028 
01029    /***=============================================================*/
01030 
01031    /*** horizontal rowcol for data value clipping ***/
01032 
01033    SEP_HOR(anat_rowcol) ;  /* separator */
01034 
01035    hrc =  XtVaCreateWidget(
01036            "AFNI" , xmRowColumnWidgetClass , anat_rowcol ,
01037               XmNorientation  , XmHORIZONTAL ,
01038               XmNpacking      , XmPACK_TIGHT ,
01039               XmNadjustLast   , False ,
01040               XmNadjustMargin , False ,
01041               XmNtraversalOn  , False ,
01042               XmNmarginWidth  , 0 ,
01043               XmNmarginHeight , 0 ,
01044               XmNinitialResourcesPersistent , False ,
01045            NULL ) ;
01046 
01047    /*** vertical rowcol for dataset range information labels ***/
01048 
01049    vrc = XtVaCreateWidget(
01050              "AFNI" , xmRowColumnWidgetClass , hrc ,
01051                 XmNpacking     , XmPACK_TIGHT ,
01052                 XmNorientation , XmVERTICAL ,
01053                 XmNadjustLast  , False ,
01054                 XmNadjustMargin, False ,
01055                 XmNtraversalOn , False ,
01056                 XmNmarginWidth , 0 ,
01057                 XmNmarginHeight, 0 ,
01058                 XmNinitialResourcesPersistent , False ,
01059              NULL ) ;
01060 
01061    /*** 1st label for dataset range information ***/
01062 
01063    xstr = XmStringCreateLtoR( "Min=?????? Max=??????" , XmFONTLIST_DEFAULT_TAG ) ;
01064    range_lab = XtVaCreateManagedWidget(
01065                  "AFNI" , xmLabelWidgetClass , vrc ,
01066                     XmNlabelString , xstr ,
01067                     XmNrecomputeSize , False ,
01068                     XmNinitialResourcesPersistent , False ,
01069                  NULL ) ;
01070    XmStringFree(xstr) ;
01071 
01072    MCW_register_help( range_lab ,
01073                       "Shows the range of the data stored\n"
01074                       "in the brick voxels.\n"
01075                       "\n"
01076                       "N.B.: These values are NOT scaled\n"
01077                       "      by any floating point\n"
01078                       "      brick scaling factor."
01079                     ) ;
01080 
01081    /*** 2nd label for scaled dataset range information ***/
01082 
01083    xstr = XmStringCreateLtoR( "[123456789 123456789]" , XmFONTLIST_DEFAULT_TAG ) ;
01084    range_faclab = XtVaCreateWidget(
01085                     "AFNI" , xmLabelWidgetClass , vrc ,
01086                        XmNlabelString , xstr ,
01087                        XmNrecomputeSize , False ,
01088                        XmNinitialResourcesPersistent , False ,
01089                     NULL ) ;
01090    XmStringFree(xstr) ;
01091 
01092    MCW_register_help( range_faclab ,
01093                       "Shows the range of data stored\n"
01094                       "in the brick, this time multiplied\n"
01095                       "by the brick's scaling factor."
01096                     ) ;
01097 
01098    XtManageChild(vrc) ;
01099 
01100    SEP_VER(hrc) ;
01101 
01102    /*** arrowvals to get dataset clip levels ***/
01103 
01104    /*** vertical rowcol for Bot arrowval ***/
01105 
01106    vrc = XtVaCreateWidget(
01107              "AFNI" , xmRowColumnWidgetClass , hrc ,
01108                 XmNpacking     , XmPACK_TIGHT ,
01109                 XmNorientation , XmVERTICAL ,
01110                 XmNadjustLast  , False ,
01111                 XmNadjustMargin, False ,
01112                 XmNtraversalOn , False ,
01113                 XmNmarginWidth , 0 ,
01114                 XmNmarginHeight, 0 ,
01115                 XmNinitialResourcesPersistent , False ,
01116              NULL ) ;
01117 
01118    clipbot_av = new_MCW_arrowval( vrc , "Bot " ,
01119                                 MCW_AV_downup , -CLIP_RANGE,CLIP_RANGE,-CLIP_RANGE ,
01120                                 MCW_AV_editext , 0 ,
01121                                 REND_clip_CB , NULL , NULL,NULL ) ;
01122 
01123    MCW_reghelp_children( clipbot_av->wrowcol ,
01124                          "All (unscaled) voxel values below\n"
01125                          "'Bot' will be increased to this\n"
01126                          "value.  The larger of 'Bot' and\n"
01127                          "'Min' is the left edge of the\n"
01128                          "brick graphs shown below."
01129                        ) ;
01130 
01131    xstr = XmStringCreateLtoR( "[-> 123456789]" , XmFONTLIST_DEFAULT_TAG ) ;
01132    clipbot_faclab = XtVaCreateWidget(
01133                     "AFNI" , xmLabelWidgetClass , vrc ,
01134                        XmNlabelString , xstr ,
01135                        XmNrecomputeSize , False ,
01136                        XmNinitialResourcesPersistent , False ,
01137                     NULL ) ;
01138    XmStringFree(xstr) ;
01139 
01140    MCW_register_help( clipbot_faclab ,
01141                       "Shows the scaled\nvalue of 'Bot'." ) ;
01142 
01143    XtManageChild(vrc) ;
01144 
01145    SEP_VER(hrc) ;
01146 
01147    /*** vertical rowcol for Top arrowval ***/
01148 
01149    vrc = XtVaCreateWidget(
01150              "AFNI" , xmRowColumnWidgetClass , hrc ,
01151                 XmNpacking     , XmPACK_TIGHT ,
01152                 XmNorientation , XmVERTICAL ,
01153                 XmNadjustLast  , False ,
01154                 XmNadjustMargin, False ,
01155                 XmNtraversalOn , False ,
01156                 XmNmarginWidth , 0 ,
01157                 XmNmarginHeight, 0 ,
01158                 XmNinitialResourcesPersistent , False ,
01159              NULL ) ;
01160 
01161    cliptop_av = new_MCW_arrowval( vrc , "Top " ,
01162                                 MCW_AV_downup , -CLIP_RANGE,CLIP_RANGE, CLIP_RANGE ,
01163                                 MCW_AV_editext , 0 ,
01164                                 REND_clip_CB , NULL , NULL,NULL ) ;
01165 
01166    MCW_reghelp_children( cliptop_av->wrowcol ,
01167                          "All (unscaled) voxel values above\n"
01168                          "'Top' will be decreased to this\n"
01169                          "value.  The smaller of 'Top' and\n"
01170                          "'Max' is the right edge of the\n"
01171                          "brick graphs shown below."
01172                        ) ;
01173 
01174    xstr = XmStringCreateLtoR( "[-> 123456789]" , XmFONTLIST_DEFAULT_TAG ) ;
01175    cliptop_faclab = XtVaCreateWidget(
01176                     "AFNI" , xmLabelWidgetClass , vrc ,
01177                        XmNlabelString , xstr ,
01178                        XmNrecomputeSize , False ,
01179                        XmNinitialResourcesPersistent , False ,
01180                     NULL ) ;
01181    XmStringFree(xstr) ;
01182 
01183    MCW_register_help( clipbot_faclab ,
01184                       "Shows the scaled\nvalue of 'Top'." ) ;
01185 
01186    XtManageChild(vrc) ;
01187    XtManageChild(hrc) ;
01188 
01189    /***=============================================================*/
01190 
01191    /*** horizontal rowcol for graphs ***/
01192 
01193    SEP_HOR(anat_rowcol) ;  /* separator */
01194 
01195    hrc =  XtVaCreateWidget(
01196            "AFNI" , xmRowColumnWidgetClass , anat_rowcol ,
01197               XmNorientation , XmHORIZONTAL ,
01198               XmNpacking , XmPACK_TIGHT ,
01199               XmNadjustLast  , False ,
01200               XmNadjustMargin, False ,
01201               XmNtraversalOn , False ,
01202               XmNmarginWidth , 0 ,
01203               XmNmarginHeight, 0 ,
01204               XmNinitialResourcesPersistent , False ,
01205            NULL ) ;
01206 
01207    /*** graph to control grayscale ***/
01208 
01209    gry_graf = new_MCW_graf( hrc , im3d->dc, "Brightness", REND_graf_CB, NULL ) ;
01210 
01211    MCW_reghelp_children( gry_graf->topform ,
01212                          "This controls the brightness of each\n"
01213                          "voxel, as a function of input signal.\n"
01214                          "After you change this curve, you\n"
01215                          "must press 'Draw' to see the effect." ) ;
01216 
01217    SEP_VER(hrc) ;
01218 
01219    /*** graph to control opacity ***/
01220 
01221    opa_graf = new_MCW_graf( hrc , im3d->dc, "Opacity", REND_graf_CB, NULL ) ;
01222 
01223    MCW_reghelp_children( opa_graf->topform ,
01224                          "This controls the opacity of each\n"
01225                          "voxel, as a function of input signal.\n\n"
01226                          "After you change this curve, you\n"
01227                          "must press 'Draw' to see the effect." ) ;
01228 
01229    SEP_VER(hrc) ;
01230 
01231    /*** passive graph to show data distribution ***/
01232 
01233    his_graf = new_MCW_pasgraf( hrc , im3d->dc , "Sqrt Histogram" ) ;
01234    his_graf->mode = PASGRAF_BAR ;
01235 
01236    MCW_reghelp_children( his_graf->topform ,
01237                          "The graph height is proportional to\n"
01238                          "the square-root of the histogram of\n"
01239                          "the input signal.\n"
01240                          "\n"
01241                          "N.B.: The histogram at 0 is not included\n"
01242                          "      in the scaling, since it tends to\n"
01243                          "      be huge.  The square-root is graphed\n"
01244                          "      to enhance the range of the plot."      ) ;
01245 
01246    XtManageChild(hrc) ;
01247 
01248    /***=============================================================*/
01249 
01250    /*** horizontal rowcol to hold cutout controls ***/
01251 
01252    SEP_HOR(anat_rowcol) ;  /* separator */
01253 
01254    hrc =  XtVaCreateWidget(
01255            "AFNI" , xmRowColumnWidgetClass , anat_rowcol ,
01256               XmNorientation , XmHORIZONTAL ,
01257               XmNpacking , XmPACK_TIGHT ,
01258               XmNadjustLast  , False ,
01259               XmNadjustMargin, False ,
01260               XmNtraversalOn , False ,
01261               XmNmarginWidth , 0 ,
01262               XmNmarginHeight, 0 ,
01263               XmNinitialResourcesPersistent , False ,
01264            NULL ) ;
01265 
01266    /*** option menu to choose number of cutouts ***/
01267 
01268    numcutout_av = new_MCW_optmenu( hrc , "Cutouts " ,
01269                               0 , MAX_CUTOUTS , num_cutouts,0 ,
01270                               REND_numcutout_CB , NULL , NULL , NULL ) ;
01271 
01272    MCW_reghelp_children( numcutout_av->wrowcol ,
01273                          "Use this to choose the number of cutouts\n"
01274                          "to apply before rendering.  Controls for\n"
01275                          "the number selected will be activated below."
01276                        ) ;
01277 
01278    /*** option menu to choose cutout logic ***/
01279 
01280    logiccutout_av = new_MCW_optmenu( hrc , "+" ,
01281                               0 , 1 , logic_cutout,0 ,
01282                               NULL , NULL ,
01283                               MCW_av_substring_CB , cutout_logic_labels ) ;
01284 
01285    MCW_reghelp_children( logiccutout_av->wrowcol ,
01286                          "Use this to control the logic of how\n"
01287                          "multiple cutouts are combined:\n\n"
01288                          "OR  = the union of all regions\n"
01289                          "AND = the intersection of all regions"
01290                        ) ;
01291 
01292    SEP_VER(hrc) ;  /* separator */
01293 
01294    /*** arrowval to select opacity reduction factor ***/
01295 
01296    opacity_scale_av = new_MCW_arrowval( hrc , "Opacity Factor " ,
01297                                 MCW_AV_downup , 0,10,10 ,
01298                                 MCW_AV_noactext , 1 ,
01299                                 REND_opacity_scale_CB , NULL , NULL,NULL ) ;
01300    XtAddCallback( opacity_scale_av->wtext, XmNactivateCallback,
01301                   REND_textact_CB, opacity_scale_av ) ;
01302 
01303    /*** 07 July 1999: insert menu to control scripting actions ***/
01304 
01305 #ifdef USE_SCRIPTING
01306    SEP_VER(hrc) ;
01307    REND_script_menu( hrc ) ;
01308 #endif
01309 
01310    XtManageChild(hrc) ;
01311 
01312    /*** Create the widgets for each cutout ***/
01313 
01314    for( ii=0 ; ii < MAX_CUTOUTS ; ii++ ) cutouts[ii] = REND_make_cutout(ii) ;
01315 
01316    /***=============================================================*/
01317 
01318    /*** horizontal rowcol to hold automation controls ***/
01319 
01320    SEP_HOR(anat_rowcol) ;  /* separator */
01321 
01322    hrc =  XtVaCreateWidget(
01323            "AFNI" , xmRowColumnWidgetClass , anat_rowcol ,
01324               XmNorientation , XmHORIZONTAL ,
01325               XmNpacking , XmPACK_TIGHT ,
01326               XmNadjustLast  , False ,
01327               XmNadjustMargin, False ,
01328               XmNtraversalOn , False ,
01329               XmNmarginWidth , 0 ,
01330               XmNmarginHeight, 0 ,
01331               XmNinitialResourcesPersistent , False ,
01332            NULL ) ;
01333 
01334    /*** button box to enable automation mode ***/
01335 
01336    automate_bbox = new_MCW_bbox( hrc ,
01337                                  1 , automate_bbox_label ,
01338                                  MCW_BB_check , MCW_BB_noframe ,
01339                                  REND_autoflag_CB , NULL ) ;
01340 
01341    MCW_set_bbox( automate_bbox , automate_flag ) ;
01342 
01343    MCW_reghelp_children( automate_bbox->wrowcol ,
01344                          "IN:  Enable automation of renderings\n"
01345                          "OUT: Don't allow automated rendering"  ) ;
01346 
01347    SEP_VER(hrc) ;  /* separator */
01348 
01349    /*** arrowval to control number of frames to compute */
01350 
01351    autoframe_av = new_MCW_arrowval( hrc , "Frames " ,
01352                                     MCW_AV_downup , 2,999,5 ,
01353                                     MCW_AV_editext , 0 ,
01354                                     NULL , NULL , NULL,NULL ) ;
01355 
01356    MCW_reghelp_children( autoframe_av->wrowcol ,
01357                          "Use this to set the number\n"
01358                          "of frames that will be rendered\n"
01359                          "when 'Compute' is activated."     ) ;
01360 
01361    SEP_VER(hrc) ;  /* separator */
01362 
01363    /*** pushbutton to activate the automation ***/
01364 
01365    xstr = XmStringCreateLtoR( "Compute" , XmFONTLIST_DEFAULT_TAG ) ;
01366    autocompute_pb = XtVaCreateManagedWidget(
01367                      "AFNI" , xmPushButtonWidgetClass , hrc ,
01368                         XmNlabelString , xstr ,
01369                         XmNtraversalOn , False ,
01370                         XmNinitialResourcesPersistent , False ,
01371                      NULL ) ;
01372    XmStringFree(xstr) ;
01373    XtAddCallback( autocompute_pb, XmNactivateCallback, REND_autocompute_CB, NULL ) ;
01374    MCW_register_help( autocompute_pb ,
01375                       "Use this to start the\n"
01376                       "automation of rendering" ) ;
01377 
01378    /*** pushbutton to cancel the automation [not managed now] ***/
01379 
01380    xstr = XmStringCreateLtoR( " * CANCEL * " , XmFONTLIST_DEFAULT_TAG ) ;
01381    autocancel_pb = XtVaCreateWidget(
01382                      "AFNI" , xmPushButtonWidgetClass , hrc ,
01383                         XmNlabelString , xstr ,
01384                         XmNtraversalOn , False ,
01385                         XmNinitialResourcesPersistent , False ,
01386                      NULL ) ;
01387    XmStringFree(xstr) ;
01388    XtAddCallback( autocancel_pb, XmNactivateCallback, REND_autocancel_CB, NULL ) ;
01389 
01390    XtManageChild(hrc) ;
01391 
01392    /***=============================================================*/
01393 
01394    /*** horizontal rowcol to hold miscellaneous display controls ***/
01395 
01396    SEP_HOR(anat_rowcol) ;  /* separator */
01397 
01398    hrc =  XtVaCreateWidget(
01399            "AFNI" , xmRowColumnWidgetClass , anat_rowcol ,
01400               XmNorientation , XmHORIZONTAL ,
01401               XmNpacking , XmPACK_TIGHT ,
01402               XmNadjustLast  , False ,
01403               XmNadjustMargin, False ,
01404               XmNtraversalOn , False ,
01405               XmNmarginWidth , 0 ,
01406               XmNmarginHeight, 0 ,
01407               XmNinitialResourcesPersistent , False ,
01408            NULL ) ;
01409 
01410    /*** option menu to choose precalculation level ***/
01411 
01412    precalc_av = new_MCW_optmenu( hrc , "Precalc " ,
01413                               0 , NUM_precalc-1 , precalc_ival,0 ,
01414                               REND_precalc_CB , NULL ,
01415                               MCW_av_substring_CB , precalc_strings ) ;
01416 
01417    MCW_reghelp_children( precalc_av->wrowcol ,
01418                          "Use this to set the amount of precalculation\n"
01419                          "performed before rendering.  The higher levels\n"
01420                          "will speed drawing, but will require overhead\n"
01421                          "anytime the dataset, colors, or opacity are\n"
01422                          "modified (i.e., anything but the angles).\n"
01423                          "\n"
01424                          "Low    = slow rendering, no precalculation\n"
01425                          "Medium = faster rendering, some precalculation\n"
01426                          "High   = fastest rendering, much precalculation"
01427                        ) ;
01428 
01429    SEP_VER(hrc) ;  /* separator */
01430 
01431    /*** button box to show AFNI crosshair location ***/
01432 
01433    xhair_bbox = new_MCW_bbox( hrc ,
01434                               1 , xhair_bbox_label ,
01435                               MCW_BB_check , MCW_BB_noframe ,
01436                               REND_xhair_CB , NULL ) ;
01437 
01438    /* 08 Mar 2001: Button3 popup to control xhair color */
01439 
01440    XtInsertEventHandler( xhair_bbox->wbut[0] ,
01441 
01442                                0
01443                              | ButtonPressMask   /* button presses */
01444                             ,
01445                             FALSE ,              /* nonmaskable events? */
01446                             REND_xhair_EV ,      /* handler */
01447                             NULL ,               /* client data */
01448                             XtListTail           /* last in queue */
01449                         ) ;
01450 
01451    MCW_set_bbox( xhair_bbox , xhair_flag ) ;
01452 
01453    MCW_reghelp_children( xhair_bbox->wrowcol ,
01454                          "IN:  show AFNI crosshair location\n"
01455                          "OUT: don't show AFNI crosshairs\n"
01456                          "\n"
01457                          "N.B.: Must press Reload to see the\n"
01458                          "      crosshair position updated\n"
01459                          "      if it is changed in AFNI."
01460                        ) ;
01461 
01462    SEP_VER(hrc) ;  /* separator */
01463 
01464    /*** button box to do dynamic updates ***/
01465 
01466    dynamic_bbox = new_MCW_bbox( hrc ,
01467                                 1 , dynamic_bbox_label ,
01468                                 MCW_BB_check , MCW_BB_noframe ,
01469                                 REND_dynamic_CB , NULL ) ;
01470 
01471    MCW_set_bbox( dynamic_bbox , dynamic_flag ) ;
01472 
01473    MCW_reghelp_children( dynamic_bbox->wrowcol ,
01474                          "IN:  Redraw immediately upon changes\n"
01475                          "OUT: Redraw only when commanded\n"
01476                          "\n"
01477                          "N.B.: Changes to the AFNI crosshair\n"
01478                          "      position are not detectable\n"
01479                          "      to force a dynamic redraw."     ) ;
01480 
01481    SEP_VER(hrc) ;  /* separator */
01482 
01483    /*** button box to accumulate images ***/
01484 
01485    accum_bbox = new_MCW_bbox( hrc ,
01486                               1 , accum_bbox_label ,
01487                               MCW_BB_check , MCW_BB_noframe ,
01488                               REND_accum_CB , NULL ) ;
01489 
01490    MCW_set_bbox( accum_bbox , accum_flag ) ;
01491 
01492    MCW_reghelp_children( accum_bbox->wrowcol ,
01493                          "IN:  Accumulate images for viewing\n"
01494                          "OUT: Save only the latest images"     ) ;
01495 
01496    XtManageChild(hrc) ;
01497 
01498    /***=============================================================*/
01499 
01500    /*** horizontal rowcol to hold angle arrows ***/
01501 
01502    SEP_HOR(anat_rowcol) ;  /* separator widget */
01503 
01504    hrc =  XtVaCreateWidget(
01505            "AFNI" , xmRowColumnWidgetClass , anat_rowcol ,
01506               XmNorientation , XmHORIZONTAL ,
01507               XmNpacking , XmPACK_TIGHT ,
01508               XmNadjustLast  , False ,
01509               XmNadjustMargin, False ,
01510               XmNtraversalOn , False ,
01511               XmNmarginWidth , 0 ,
01512               XmNmarginHeight, 0 ,
01513               XmNinitialResourcesPersistent , False ,
01514            NULL ) ;
01515 
01516 /*==========================================================================*/
01517 #ifdef ALLOW_INCROT /* 26 Apr 2002 - RWCox */
01518    { static char * incrot_bbox_label[1] = { "I" } ;
01519      incrot_bbox = new_MCW_bbox( hrc , 1 , incrot_bbox_label ,
01520                                  MCW_BB_check , MCW_BB_noframe ,
01521                                  REND_incrot_CB, NULL           ) ;
01522      MCW_set_bbox( incrot_bbox , 0 ) ;
01523      MCW_reghelp_children( incrot_bbox->wrowcol ,
01524                            "OUT: angles increment globally\n"
01525                            "IN:  angles increment locally"   ) ;
01526      MCW_reghint_children( incrot_bbox->wrowcol , "Incremental rotation?" ) ;
01527      SEP_VER(hrc) ;
01528    }
01529 #endif  /* ALLOW_INCROT */
01530 
01531   /** N.B.: removed trailing space from "Roll", "Pitch", "Yaw" labels
01532             for arrowvals below, to make space for the bbox created above **/
01533 /*==========================================================================*/
01534 
01535    /***  arrowvals to choose rotation angles  ***/
01536 
01537    roll_av = new_MCW_arrowval( hrc , "Roll" ,
01538                                 MCW_AV_downup , -999999,999999,(int)(0.1*angle_roll) ,
01539                                 MCW_AV_noactext , -1 ,
01540                                 REND_angle_CB , NULL , NULL,NULL ) ;
01541    roll_av->fstep = angle_fstep ;
01542    MCW_reghelp_children( roll_av->wrowcol ,
01543                          "Use this to set the roll angle\n"
01544                          "(about the I-S axis) for viewing,\n"
01545                          "then press 'Draw'"
01546                        ) ;
01547    XtAddCallback( roll_av->wtext, XmNactivateCallback, REND_textact_CB, roll_av ) ;
01548 
01549    SEP_VER(hrc) ;  /* separator widget */
01550 
01551    pitch_av = new_MCW_arrowval( hrc , "Pitch" ,
01552                                 MCW_AV_downup , -999999,999999,(int)(0.1*angle_pitch) ,
01553                                 MCW_AV_noactext , -1 ,
01554                                 REND_angle_CB , NULL , NULL,NULL ) ;
01555    pitch_av->fstep = angle_fstep ;
01556    MCW_reghelp_children( pitch_av->wrowcol ,
01557                          "Use this to set the pitch angle\n"
01558                          "(about the R-L axis) for viewing,\n"
01559                          "then press 'Draw'"
01560                        ) ;
01561    XtAddCallback( pitch_av->wtext, XmNactivateCallback, REND_textact_CB, pitch_av ) ;
01562 
01563    SEP_VER(hrc) ;  /* separator widget */
01564 
01565    yaw_av = new_MCW_arrowval( hrc , "Yaw" ,
01566                                 MCW_AV_downup , -999999,999999,(int)(0.1*angle_yaw) ,
01567                                 MCW_AV_noactext , -1 ,
01568                                 REND_angle_CB , NULL , NULL,NULL ) ;
01569    yaw_av->fstep = angle_fstep ;
01570    MCW_reghelp_children( yaw_av->wrowcol ,
01571                          "Use this to set the yaw angle\n"
01572                          "(about the A-P axis) for viewing,\n"
01573                          "then press 'Draw'"
01574                        ) ;
01575    XtAddCallback( yaw_av->wtext, XmNactivateCallback, REND_textact_CB, yaw_av ) ;
01576 
01577    /** 26 Apr 2002: add hints to these arrows as well **/
01578 
01579    MCW_reghint_children( roll_av->wrowcol  , "Angle about I-S axis" ) ;
01580    MCW_reghint_children( pitch_av->wrowcol , "Angle about R-L axis" ) ;
01581    MCW_reghint_children( yaw_av->wrowcol   , "Angle about A-P axis" ) ;
01582 
01583 /*==========================================================================*/
01584 #if 1
01585 #ifdef ALLOW_INCROT  /* 26 Apr 2002 - RWCox */
01586    XtVaSetValues( roll_av->wtext  , XmNcolumns , 8 , NULL ) ;
01587    XtVaSetValues( pitch_av->wtext , XmNcolumns , 8 , NULL ) ;
01588    XtVaSetValues( yaw_av->wtext   , XmNcolumns , 8 , NULL ) ;
01589 #endif
01590 #endif
01591 /*==========================================================================*/
01592 
01593    XtManageChild(hrc) ;
01594 
01595    /***=============================================================*/
01596 
01597    /*** a set of action buttons below the line ***/
01598 
01599    SEP_HOR(anat_rowcol) ;
01600 
01601    (void) MCW_action_area( anat_rowcol , REND_actor , NACT ) ;
01602 
01603    help_pb   = (Widget) REND_actor[0].data ;
01604    draw_pb   = (Widget) REND_actor[1].data ;
01605    reload_pb = (Widget) REND_actor[2].data ;
01606    done_pb   = (Widget) REND_actor[3].data ;
01607 
01608    /***=============================================================*/
01609 
01610    /*** that's all ***/
01611 
01612    XtManageChild(anat_rowcol) ;
01613    XtManageChild(anat_frame) ;
01614 
01615    XtManageChild(top_rowcol) ;
01616    XtRealizeWidget(shell) ;      /* will not be mapped */
01617 
01618    WAIT_for_window(shell) ;
01619    POPUP_cursorize(xhair_bbox->wbut[0]) ;
01620 
01621    /*** 12 July 1999: make the overlay widgets now, instead of later ***/
01622 
01623    REND_func_widgets() ;
01624 
01625 #if 0
01626    XtVaSetValues( anat_rowcol , XmNresizeWidth , False , NULL ) ;
01627 #endif
01628    return ;
01629 }
01630 
01631 /*-------------------------------------------------------------------
01632   Make a line of cutout widgets
01633 ---------------------------------------------------------------------*/
01634 
01635 #define NUM_CUTOUT_TYPES  22
01636 
01637 static char * cutout_type_labels[NUM_CUTOUT_TYPES] = {
01638   "No Cut"       ,
01639   "Right of"     , "Left of"       ,
01640   "Anterior to"  , "Posterior to"  ,
01641   "Inferior to"  , "Superior to"   ,
01642   "Expr > 0"     , "TT Ellipsoid " ,
01643 
01644   "Behind AL-PR" , "Front AL-PR"   ,    /* x+y > val , x+y < val  */
01645   "Front AR-PL"  , "Behind AR-PL"  ,    /* x-y > val , x-y < val  */
01646   "Above AS-PI"  , "Below AS-PI"   ,    /* y+z > val , y+z < val  */
01647   "Below AI-PS"  , "Above AI-PS"   ,    /* y-z > val , y-z < val  */
01648   "Above RS-LI"  , "Below RS-LI"   ,    /* x+z > val , x+z < val  */
01649   "Below RI-LS"  , "Above RI-LS"   ,    /* x-z > val , x-z < val  */
01650 
01651   "NonOverlay++"
01652 } ;
01653 
01654 static char * cutout_param_labels[NUM_CUTOUT_TYPES] = {
01655   "Parameter:   " ,
01656   "x(-R+L) [mm]:" , "x(-R+L) [mm]:" ,
01657   "y(-A+P) [mm]:" , "y(-A+P) [mm]:" ,
01658   "z(-I+S) [mm]:" , "z(-I+S) [mm]:" ,
01659   "Expression:  " , "Percentage:  " ,
01660 
01661   "Value [mm]:  " , "Value [mm]:  " ,
01662   "Value [mm]:  " , "Value [mm]:  " ,
01663   "Value [mm]:  " , "Value [mm]:  " ,
01664   "Value [mm]:  " , "Value [mm]:  " ,
01665   "Value [mm]:  " , "Value [mm]:  " ,
01666   "Value [mm]:  " , "Value [mm]:  " ,
01667 
01668   "Radius++[mm]:"
01669 } ;
01670 
01671 static char * cutout_type_names[NUM_CUTOUT_TYPES] = {
01672   "CUT_NONE"         , "CUT_RIGHT_OF"     , "CUT_LEFT_OF"      ,
01673   "CUT_ANTERIOR_TO"  , "CUT_POSTERIOR_TO" , "CUT_INFERIOR_TO"  ,
01674   "CUT_SUPERIOR_TO"  , "CUT_EXPRESSION"   , "CUT_TT_ELLIPSOID" ,
01675   "CUT_SLANT_XPY_GT" , "CUT_SLANT_XPY_LT" , "CUT_SLANT_XMY_GT" ,
01676   "CUT_SLANT_XMY_LT" , "CUT_SLANT_YPZ_GT" , "CUT_SLANT_YPZ_LT" ,
01677   "CUT_SLANT_YMZ_GT" , "CUT_SLANT_YMZ_LT" , "CUT_SLANT_XPZ_GT" ,
01678   "CUT_SLANT_XPZ_LT" , "CUT_SLANT_XMZ_GT" , "CUT_SLANT_XMZ_LT" ,
01679   "CUT_NONOVERLAY"
01680 } ;
01681 
01682 #define CUT_NONE           0
01683 #define CUT_RIGHT_OF       1
01684 #define CUT_LEFT_OF        2
01685 #define CUT_ANTERIOR_TO    3
01686 #define CUT_POSTERIOR_TO   4
01687 #define CUT_INFERIOR_TO    5
01688 #define CUT_SUPERIOR_TO    6
01689 #define CUT_EXPRESSION     7
01690 #define CUT_TT_ELLIPSOID   8
01691 
01692 #define CUT_SLANT_XPY_GT   9   /* slant cuts added 17 Feb 1999 */
01693 #define CUT_SLANT_XPY_LT  10
01694 #define CUT_SLANT_XMY_GT  11
01695 #define CUT_SLANT_XMY_LT  12
01696 #define CUT_SLANT_YPZ_GT  13
01697 #define CUT_SLANT_YPZ_LT  14
01698 #define CUT_SLANT_YMZ_GT  15
01699 #define CUT_SLANT_YMZ_LT  16
01700 #define CUT_SLANT_XPZ_GT  17
01701 #define CUT_SLANT_XPZ_LT  18
01702 #define CUT_SLANT_XMZ_GT  19
01703 #define CUT_SLANT_XMZ_LT  20
01704 
01705 #define CUT_NONOVERLAY    21
01706 
01707 #define CUT_SLANT_BASE     9
01708 #define CUT_SLANT_NUM     12
01709 
01710 #define SQ2 0.7071
01711 static float cut_slant_normals[CUT_SLANT_NUM][3] = {
01712     { SQ2 , SQ2 , 0.0 } , {-SQ2 ,-SQ2 , 0.0 } ,
01713     { SQ2 ,-SQ2 , 0.0 } , {-SQ2 , SQ2 , 0.0 } ,
01714     { 0.0 , SQ2 , SQ2 } , { 0.0 ,-SQ2 ,-SQ2 } ,
01715     { 0.0 , SQ2 ,-SQ2 } , { 0.0 ,-SQ2 ,+SQ2 } ,
01716     { SQ2 , 0.0 , SQ2 } , {-SQ2 , 0.0 ,-SQ2 } ,
01717     { SQ2 , 0.0 ,-SQ2 } , {-SQ2 , 0.0 , SQ2 }
01718 } ;
01719 #if 0
01720 static int cut_slant_sign[CUT_SLANT_NUM] = {
01721     1 , -1 , 1 , -1 , 1 , -1 ,
01722     1 , -1 , 1 , -1 , 1 , -1  } ;
01723 #endif
01724 
01725 REND_cutout * REND_make_cutout( int n )
01726 {
01727    XmString xstr ;
01728    char      str[64] ;
01729    REND_cutout * rc ;
01730 
01731    rc = myXtNew(REND_cutout) ;
01732 
01733    /* horizontal rowcol holds all that follows */
01734 
01735    rc->hrc =  XtVaCreateWidget(
01736                 "AFNI" , xmRowColumnWidgetClass , anat_rowcol ,
01737                    XmNorientation , XmHORIZONTAL ,
01738                    XmNpacking , XmPACK_TIGHT ,
01739                    XmNadjustLast  , False ,
01740                    XmNadjustMargin, False ,
01741                    XmNtraversalOn , False ,
01742                    XmNmarginWidth , 0 ,
01743                    XmNmarginHeight, 0 ,
01744                    XmNinitialResourcesPersistent , False ,
01745                 NULL ) ;
01746 
01747    /* menu to choose type of cutout */
01748 
01749    sprintf(str,"#%d",n+1) ;
01750    rc->type_av = new_MCW_optmenu( rc->hrc , str ,
01751                                   0 , NUM_CUTOUT_TYPES-1 , CUT_NONE,0 ,
01752                                   REND_cutout_type_CB , NULL ,
01753                                   MCW_av_substring_CB , cutout_type_labels ) ;
01754    if( NUM_CUTOUT_TYPES >= COLSIZE )
01755       AVOPT_columnize( rc->type_av , 1+(NUM_CUTOUT_TYPES+1)/COLSIZE ) ;
01756 
01757    MCW_reghelp_children( rc->type_av->wrowcol ,
01758                          "Use this to set the type of cutout\n"
01759                          "controlled by this line of inputs."  ) ;
01760 
01761    /* label to indicate parameter to enter */
01762 
01763    xstr = XmStringCreateLtoR( cutout_param_labels[0] , XmFONTLIST_DEFAULT_TAG ) ;
01764    rc->param_lab = XtVaCreateWidget(
01765                      "AFNI" , xmLabelWidgetClass , rc->hrc ,
01766                         XmNlabelString , xstr ,
01767                         XmNinitialResourcesPersistent , False ,
01768                      NULL ) ;
01769    XmStringFree(xstr) ;
01770 
01771    /* arrowval to enter parameter */
01772 
01773    rc->param_av = new_MCW_arrowval( rc->hrc , NULL ,
01774                                 MCW_AV_downup , -999999,999999,0 ,
01775                                 MCW_AV_noactext , -1 ,
01776                                 REND_param_CB , NULL , NULL,NULL ) ;
01777    rc->param_av->fstep = cutout_fstep ;
01778    XtAddCallback( rc->param_av->wtext, XmNactivateCallback, REND_textact_CB, rc->param_av ) ;
01779    XtUnmanageChild( rc->param_av->wrowcol ) ;
01780 
01781    /* button to "Get" parameter from AFNI */
01782 
01783    xstr = XmStringCreateLtoR( "Get" , XmFONTLIST_DEFAULT_TAG ) ;
01784    rc->set_pb = XtVaCreateWidget(
01785                   "AFNI" , xmPushButtonWidgetClass , rc->hrc ,
01786                      XmNlabelString , xstr ,
01787                      XmNtraversalOn , False ,
01788                      XmNinitialResourcesPersistent , False ,
01789                   NULL ) ;
01790    XmStringFree(xstr) ;
01791    XtAddCallback( rc->set_pb, XmNactivateCallback, REND_cutout_set_CB, NULL ) ;
01792    MCW_register_help( rc->set_pb , "Use this to get the parameter\n"
01793                                    "for this cutout from the current\n"
01794                                    "AFNI crosshair location."           ) ;
01795 
01796    /* button box to allow "must do" status (overriding "AND") */
01797 
01798    rc->mustdo_bbox = new_MCW_bbox( rc->hrc ,
01799                                    1 , mustdo_bbox_label ,
01800                                    MCW_BB_check , MCW_BB_noframe ,
01801                                    NULL , NULL ) ;
01802 
01803    MCW_set_bbox( rc->mustdo_bbox , 0 ) ;
01804 
01805    MCW_reghelp_children( rc->mustdo_bbox->wrowcol ,
01806                          "Use this to force the cutout\n"
01807                          "to be performed, even if the\n"
01808                          "chosen logic is 'AND'.  If the\n"
01809                          "logic is 'OR', this does nothing." ) ;
01810 
01811    XtUnmanageChild( rc->mustdo_bbox->wrowcol ) ;
01812 
01813    XtManageChild( rc->hrc ) ;
01814    return rc ;
01815 }
01816 
01817 /*-------------------------------------------------------------------
01818   Callback for done button
01819 ---------------------------------------------------------------------*/
01820 
01821 static int quit_first = 1 ;
01822 
01823 void REND_done_timeout_CB( XtPointer client_data , XtIntervalId * id )
01824 {
01825    MCW_set_widget_label( done_pb , "done" ) ;
01826    quit_first = 1 ;
01827    return ;
01828 }
01829 
01830 void REND_done_CB( Widget w, XtPointer client_data, XtPointer call_data )
01831 {
01832    /** like AFNI itself, require two quick presses to exit **/
01833 
01834    if( w == done_pb && quit_first && renderings != NULL ){
01835       MCW_set_widget_label( done_pb , "DONE " ) ;
01836       quit_first = 0 ;
01837       (void) XtAppAddTimeOut(
01838                XtWidgetToApplicationContext(done_pb) ,
01839                5000 , REND_done_timeout_CB , NULL ) ;
01840       return ;
01841    }
01842 
01843    if( xhair_recv >= 0 )  /* 29 Mar 1999 */
01844       AFNI_receive_control( im3d, xhair_recv,EVERYTHING_SHUTDOWN, NULL ) ;
01845 
01846    REND_destroy_imseq() ;      /* destroy the image window */
01847    DESTROY_IMARR(renderings) ; /* destroy the images */
01848 #ifdef USE_SCRIPTING
01849    DESTROY_RSA(renderings_state) ;
01850    script_load_last = -1 ;
01851 #endif
01852 
01853    if( wfunc_frame != NULL && XtIsManaged(wfunc_frame) )  /* close overlay */
01854       REND_open_func_CB(NULL,NULL,NULL) ;
01855 
01856    XtUnmapWidget( shell ) ; renderer_open = 0 ; imseq = NULL ;
01857 
01858    if( dset      != NULL ) dset      = NULL ;
01859    if( func_dset != NULL ) func_dset = NULL ;
01860 
01861    if( render_handle != NULL ){
01862       destroy_MREN_renderer(render_handle) ;
01863       render_handle = NULL ; func_cmap_set = 0 ;
01864    }
01865 
01866    FREE_VOLUMES ; INVALIDATE_OVERLAY ;
01867    MPROBE ;
01868    return ;
01869 }
01870 
01871 /*-------------------------------------------------------------------
01872    Load the data from the dataset into local arrays
01873 ---------------------------------------------------------------------*/
01874 
01875 void REND_reload_dataset(void)
01876 {
01877    int ii , nvox , vmin,vmax , cbot,ctop , ival,val , cutdone ;
01878    float fac ;
01879    void * var ;
01880    byte * gar ;
01881    MRI_IMAGE * vim ;
01882    XmString xstr ;
01883    char str[64] ;
01884 
01885 #define HISTOGRAMATE  /* 25 Jul 2001 */
01886 #define NHIST 255
01887    int vtop ;
01888 
01889    MCW_invert_widget(reload_pb) ;        /* flash a signal */
01890 
01891    /* start by tossing any old data */
01892 
01893    FREE_VOLUMES ;
01894 
01895    /* make sure the dataset is in memory */
01896 
01897    DSET_load(dset) ;
01898    vim = DSET_BRICK(dset,dset_ival) ; nvox = vim->nvox ;
01899    var = DSET_ARRAY(dset,dset_ival) ; brickfac = DSET_BRICK_FACTOR(dset,dset_ival) ;
01900 
01901    /* find data range, clip it, convert to bytes */
01902 
01903    grim = mri_new_conforming( vim , MRI_byte ) ;  /* new image data */
01904    gar  = MRI_BYTE_PTR(grim) ;
01905 
01906    switch( DSET_BRICK_TYPE(dset,dset_ival) ){
01907 
01908       case MRI_short:{
01909          short * sar = (short *) var ;
01910 
01911          vmin = vmax = sar[0] ;
01912          for( ii=1 ; ii < nvox ; ii++ ){        /* find range of values */
01913             val = sar[ii] ;
01914                  if( vmin > val ) vmin = val ;
01915             else if( vmax < val ) vmax = val ;
01916          }
01917 
01918 #ifdef HISTOGRAMATE
01919          if( vmax > vmin && vmin >= 0 && new_dset ){  /* 25 Jul 2001: find 'good' upper value */
01920            int hist[NHIST] , nhist,nh,hh ;
01921            nhist = (vmax-vmin > NHIST) ? NHIST : (vmax-vmin) ;
01922            mri_histogram( vim , vmin,vmax , 1,nhist , hist ) ;
01923            for( nh=ii=0 ; ii < nvox ; ii++ ) if( sar[ii] ) nh++ ;  /* count nonzeros  */
01924            nh *= 0.005 ;                                           /* find 99.5% point */
01925            for( ii=nhist-1 ; ii > 1 && nh > 0 ; ii-- ) nh -= hist[ii] ; /* in histogram */
01926            vtop = vmin + (ii+0.5)*(vmax-vmin)/(nhist-0.01) ;
01927            if( vtop > vmax || vtop <= vmin ) vtop = vmax ;
01928          } else {
01929             vtop = vmax ;
01930          }
01931 #else
01932          vtop = vmax ;
01933 #endif
01934 
01935          if( new_dset ){
01936             AV_assign_ival( clipbot_av , vmin ) ; cbot = vmin ;
01937             AV_assign_ival( cliptop_av , vtop ) ; ctop = vtop ;  /* 25 Jul 2001: vmax -> vtop */
01938          } else {
01939             cbot = MAX( clipbot_av->ival , vmin ) ;
01940             ctop = MIN( cliptop_av->ival , vmax ) ;
01941          }
01942 
01943          fac  = (ctop > cbot) ? 255.9/(ctop-cbot) : 1.0 ;
01944          for( ii=0 ; ii < nvox ; ii++ ){
01945             val  = sar[ii] ;
01946             ival = fac * (val-cbot) ; RANGE(ival,0,255) ; gar[ii] = ival ;
01947          }
01948       }
01949       break ;
01950 
01951       case MRI_byte:{
01952          byte * bar = (byte *) var ;
01953 
01954          vmin = vmax = bar[0] ;
01955          for( ii=1 ; ii < nvox ; ii++ ){        /* find range of values */
01956             val = bar[ii] ;
01957                  if( vmin > val ) vmin = val ;
01958             else if( vmax < val ) vmax = val ;
01959          }
01960 
01961 #ifdef HISTOGRAMATE
01962          if( vmax > vmin && new_dset ){        /* 25 Jul 2001: find 'good' upper value */
01963            int hist[256] , nhist=256,nh,hh ;
01964            mri_histobyte( vim , hist ) ;
01965            for( nh=0,ii=1 ; ii < nhist ; ii++ ) nh += hist[ii] ; /* count nonzeros    */
01966            nh *= 0.005 ;                                         /* find 99.5% point   */
01967            for( ii=nhist-1 ; ii > 1 && nh > 0 ; ii-- ) nh -= hist[ii] ; /* in histogram */
01968            vtop = ii ;
01969            if( vtop > vmax || vtop <= vmin ) vtop = vmax ;
01970          } else {
01971             vtop = vmax ;
01972          }
01973 #else
01974          vtop = vmax ;
01975 #endif
01976 
01977          if( new_dset ){
01978             AV_assign_ival( clipbot_av , vmin ) ; cbot = vmin ;
01979             AV_assign_ival( cliptop_av , vtop ) ; ctop = vtop ;  /* 25 Jul 2001: vmax -> vtop */
01980          } else {
01981             cbot = MAX( clipbot_av->ival , vmin ) ;
01982             ctop = MIN( cliptop_av->ival , vmax ) ;
01983          }
01984 
01985          fac  = (ctop > cbot) ? 255.9/(ctop-cbot) : 1.0 ;
01986          for( ii=0 ; ii < nvox ; ii++ ){
01987             val  = bar[ii] ;
01988             ival = fac * (val-cbot) ; RANGE(ival,0,255) ; gar[ii] = ival ;
01989          }
01990       }
01991       break ;
01992    }
01993 
01994    /* set label showing data range */
01995 
01996    sprintf(str,"Min=%d Max=%d",vmin,vmax) ;
01997    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
01998    XtVaSetValues( range_lab , XmNlabelString , xstr , NULL ) ;
01999    XmStringFree(xstr) ;
02000 
02001    /* if brick is scaled, show the scaled labels */
02002 
02003    HIDE_SCALE ;
02004 
02005    if( brickfac != 0.0 && brickfac != 1.0 ){
02006       char minch[16] , maxch[16] ;
02007 
02008       AV_fval_to_char( vmin*brickfac , minch ) ;
02009       AV_fval_to_char( vmax*brickfac , maxch ) ;
02010       sprintf(str,"[%s %s]",minch,maxch) ;
02011       xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
02012       XtVaSetValues( range_faclab , XmNlabelString , xstr , NULL ) ;
02013       XmStringFree(xstr) ;
02014 
02015       AV_fval_to_char( brickfac * clipbot_av->ival , minch ) ;
02016       sprintf(str,"[-> %s]",minch) ;
02017       xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
02018       XtVaSetValues( clipbot_faclab , XmNlabelString , xstr , NULL ) ;
02019       XmStringFree(xstr) ;
02020 
02021       AV_fval_to_char( brickfac * cliptop_av->ival , maxch ) ;
02022       sprintf(str,"[-> %s]",maxch) ;
02023       xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
02024       XtVaSetValues( cliptop_faclab , XmNlabelString , xstr , NULL ) ;
02025       XmStringFree(xstr) ;
02026 
02027       XtManageChild( range_faclab   ) ;
02028       XtManageChild( clipbot_faclab ) ;
02029       XtManageChild( cliptop_faclab ) ;
02030    } else {
02031       XtUnmanageChild( range_faclab   ) ;
02032       XtUnmanageChild( clipbot_faclab ) ;
02033       XtUnmanageChild( cliptop_faclab ) ;
02034    }
02035 
02036    FIX_SCALE_SIZE ;
02037 
02038    /* copy image data into opacity */
02039 
02040    opim = mri_to_byte( grim ) ;
02041 
02042    {  int hist[256] , nvox = grim->nvox , htop , ii ;
02043       float ofac = current_cutout_state.opacity_scale ;
02044 
02045       /* do the histogram graph */
02046 
02047       MCW_histo_bytes( nvox , MRI_BYTE_PTR(grim) , hist ) ;
02048 
02049       htop = 0 ;
02050       for( ii=0 ; ii < GRAF_SIZE ; ii++ ){
02051          hist[ii] = hist[2*ii] + hist[2*ii+1]  ;            /* fold 2 into 1  */
02052          if( ii > 0 && hist[ii] > htop ) htop = hist[ii] ;  /* find max value */
02053       }
02054 
02055       if( htop == 0 ){
02056          set_MCW_pasgraf( his_graf , NULL ) ;
02057       } else {
02058          float scl = (GRAF_SIZE-0.44) / sqrt((double)htop) ;
02059          byte bhis[GRAF_SIZE] ;
02060          for( ii=0 ; ii < GRAF_SIZE ; ii++ )
02061             bhis[ii] = (hist[ii] > htop) ? GRAF_SIZE-1
02062                                          : (byte)(scl*sqrt((double)hist[ii])+0.49) ;
02063 
02064          set_MCW_pasgraf( his_graf , bhis ) ;
02065       }
02066 
02067       redraw_MCW_pasgraf( his_graf ) ;
02068 
02069       /* modify the grayscale per the brightness graf */
02070 
02071       if( ! gry_graf->yeqx ){
02072          byte * bar=MRI_BYTE_PTR(grim) , * fun=gry_graf->func ;
02073 
02074          for( ii=0 ; ii < nvox ; ii++ ) bar[ii] = fun[ bar[ii] ] ;
02075       }
02076 
02077       /* modify the opacity per the opacity graf */
02078 
02079       if( !opa_graf->yeqx || ofac < 1.0 ){
02080          byte * bar=MRI_BYTE_PTR(opim) , * fun=opa_graf->func ;
02081 
02082          if( !opa_graf->yeqx )
02083             for( ii=0 ; ii < nvox ; ii++ ) bar[ii] = fun[ bar[ii] ] ;
02084 
02085          if( ofac < 1.0 )
02086             for( ii=0 ; ii < nvox ; ii++ ) bar[ii] *= ofac ;
02087       }
02088    }
02089 
02090    /*--- Now deal with overlay, if need be ---*/
02091 
02092    func_computed = 0 ;  /* at this point, data is for grayscale rendering */
02093    cutdone       = 0 ;  /* cutouts not done yet */
02094 
02095    if( DO_OVERLAY ){
02096       byte * gar , * opar , * ovar ;
02097       int nvox = grim->nvox , ii ;
02098 
02099       REND_reload_func_dset() ;
02100 
02101       if( num_cutouts > 0 && !func_cut_overlay ){  /* do cutouts NOW if not */
02102          REND_cutout_blobs(opim) ;                 /* to be done to overlay */
02103          cutdone = 1 ;
02104       }
02105 
02106       ovar = MRI_BYTE_PTR(ovim) ;
02107 
02108       if( !func_showthru ){  /* the old code: embed color into volume */
02109 
02110         gar  = MRI_BYTE_PTR(grim) ;
02111         opar = MRI_BYTE_PTR(opim) ;
02112 
02113         /* convert gar into index into the functional colormap */
02114 
02115         for( ii=0 ; ii < nvox ; ii++ ){
02116            if( ovar[ii] == 0 ) gar[ii] = gar[ii] >> 1   ;  /* gray */
02117            else                gar[ii] = 127 + ovar[ii] ;  /* color */
02118         }
02119 
02120         /* if needed, modify the opacity where there is color */
02121 
02122         if( func_color_opacity > 0.0 ){
02123            byte opac = (byte)(255.0 * MIN(func_color_opacity,1.0)) ;
02124            for( ii=0 ; ii < nvox ; ii++ )
02125               if( ovar[ii] != 0 ) opar[ii] = opac ;
02126         }
02127 
02128       } else {  /* 07 Jan 2000: make the showthru bricks instead */
02129 
02130         byte * garst , * oparst ;
02131 
02132         grim_showthru = mri_new_conforming( vim , MRI_byte ) ;
02133         opim_showthru = mri_new_conforming( vim , MRI_byte ) ;
02134         garst  = MRI_BYTE_PTR(grim_showthru) ;
02135         oparst = MRI_BYTE_PTR(opim_showthru) ;
02136 
02137         memset( garst  , 0 , sizeof(byte)*nvox ) ;
02138         memset( oparst , 0 , sizeof(byte)*nvox ) ;
02139 
02140         for( ii=0 ; ii < nvox ; ii++ ){       /* load values only if */
02141            if( ovar[ii] != 0 ){               /* there is overlay   */
02142 
02143               garst[ii]  = 127 + ovar[ii] ;   /* color index */
02144               oparst[ii] = 240 ;              /* mostly opaque */
02145            }
02146         }
02147       }
02148 
02149       func_computed = 1 ;  /* data is now set for color rendering */
02150    }
02151 
02152    /*--- Other piddling details ---*/
02153 
02154    if( num_cutouts > 0 && !cutdone ){    /* if cutouts hit overlay */
02155       REND_cutout_blobs(opim)  ;
02156       if( func_showthru && opim_showthru != NULL )
02157          REND_cutout_blobs(opim_showthru) ;
02158    }
02159 
02160    if( xhair_flag ) REND_xhair_underlay() ;
02161 
02162    MCW_invert_widget(reload_pb) ;  /* turn the signal off */
02163 
02164    new_dset = 0 ; new_data_loaded = 1 ;
02165    FIX_SCALE_SIZE ;     /* 09 May 2001 */
02166    return ;
02167 }
02168 
02169 /*-------------------------------------------------------------------
02170    Callback for the reload button
02171 ---------------------------------------------------------------------*/
02172 
02173 void REND_reload_CB( Widget w, XtPointer client_data, XtPointer call_data )
02174 {
02175    if( dset == NULL ){ XBell(dc->display,100) ; return ; }
02176 
02177    REND_reload_dataset() ;             /* load data again */
02178 
02179    if( render_handle != NULL ) REND_draw_CB(NULL,NULL,NULL) ; /* draw */
02180 
02181    return ;
02182 }
02183 
02184 /*-----------------------------------------------------------------------
02185   Actually send the computed bricks to the renderer
02186 -------------------------------------------------------------------------*/
02187 
02188 void REND_reload_renderer(void)
02189 {
02190    if( render_handle == NULL ) return ;  /* error */
02191 
02192    if( func_computed ){   /* render the underlay and overlay */
02193 
02194       if( !func_cmap_set ){
02195          MREN_set_rgbmap( render_handle, func_ncmap, func_rmap,func_gmap,func_bmap ) ;
02196          func_cmap_set = 1 ;
02197       }
02198 
02199       if( !func_showthru ){  /* the old code: both underlay and overlay are in grim */
02200 
02201          MREN_set_rgbbytes( render_handle , grim ) ;  /* color overlay */
02202          MREN_set_opabytes( render_handle , opim ) ;
02203 
02204       } else {               /* 07 Jan 2000:
02205                                 grayscale underlay is in grim
02206                                 color overlay is in grim_showthru */
02207 
02208          switch( func_showthru_pass ){  /* do the 2 images separately */
02209             default:
02210             case 0:
02211                MREN_set_graybytes( render_handle , grim ) ;  /* underlay */
02212                MREN_set_opabytes ( render_handle , opim ) ;
02213             break ;
02214 
02215             case 1:
02216                MREN_set_rgbbytes( render_handle , grim_showthru ) ; /* overlay */
02217                MREN_set_opabytes( render_handle , opim_showthru ) ;
02218             break ;
02219          }
02220       }
02221 
02222    } else {  /* just render the underlay in gray */
02223 
02224       MREN_set_graybytes( render_handle , grim ) ; /* grayscale underlay */
02225       MREN_set_opabytes ( render_handle , opim ) ;
02226    }
02227 
02228    return ;
02229 }
02230 
02231 /*-------------------------------------------------------------------
02232   Callback for draw button
02233 ---------------------------------------------------------------------*/
02234 
02235 void REND_draw_CB( Widget w, XtPointer client_data, XtPointer call_data )
02236 {
02237    MRI_IMAGE * rim ;
02238 
02239 #ifdef USE_SCRIPTING
02240    if( script_dontdraw ) return ;  /* 24 Nov 2000 */
02241 #endif
02242 
02243    if( dset == NULL ){ XBell(dc->display,100) ; return ; }
02244 
02245    MCW_invert_widget(draw_pb) ;
02246 
02247    /* if needed, create stuff for rendering */
02248 
02249    if( render_handle == NULL ){
02250       render_handle = new_MREN_renderer() ;
02251 #ifdef REND_DEBUG
02252       MREN_be_verbose(render_handle) ;  /* for debugging */
02253 #endif
02254    }
02255 
02256    REND_load_cutout_state() ;           /* load cutout data from widgets */
02257 
02258    if( REND_cutout_state_changed() ){   /* if cutouts changed, must reload data */
02259       FREE_VOLUMES ;
02260       if( func_cut_overlay ) INVALIDATE_OVERLAY ;
02261       old_cutout_state = current_cutout_state ;
02262    }
02263 
02264    if( xhair_flag && CHECK_XHAIR_MOTION ){  /* check for new crosshair position */
02265       if( xhair_ovc > 0 && DO_OVERLAY ) INVALIDATE_OVERLAY ;
02266       else                              FREE_VOLUMES ;
02267    }
02268 
02269    if( NEED_RELOAD ) REND_reload_dataset() ;
02270 
02271    if( new_data_loaded                ||     /* new data was loaded here */
02272        MREN_needs_data(render_handle) ||     /* renderer isn't ready yet */
02273        (func_computed && func_showthru)  ){  /* am doing ShowThru images */
02274 
02275       func_showthru_pass = 0 ;  /* always a good value */
02276       REND_reload_renderer() ;  /* load data from arrays here into renderer */
02277       new_data_loaded = 0 ;
02278    }
02279 
02280    /* setup for viewing */
02281 
02282    angle_roll  = REND_evaluate( roll_av )  ;  /* read angles from arrowvals */
02283    angle_pitch = REND_evaluate( pitch_av ) ;
02284    angle_yaw   = REND_evaluate( yaw_av )   ;
02285 
02286    MREN_set_viewpoint( render_handle , -angle_yaw,-angle_pitch,-angle_roll ) ;
02287    MREN_set_precalculation( render_handle , precalc_mode[precalc_ival] ) ;
02288    MREN_set_min_opacity( render_handle ,
02289                          0.05 * current_cutout_state.opacity_scale ) ;
02290 
02291    /* create and display the rendered image */
02292 
02293    rim = MREN_render( render_handle , npixels ) ;
02294 
02295    if( rim == NULL ){
02296       (void) MCW_popup_message( draw_pb ,
02297                                    "** Rendering fails,    **\n"
02298                                    "** for unknown reasons **\n\n"
02299                                    "** Sorry -- RWCox      **\n" ,
02300                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
02301       XBell(dc->display,100) ;
02302       MCW_invert_widget(draw_pb) ; return ;
02303    }
02304 
02305    /* 07 Jan 2000 - make the showthru image now, if needed */
02306 
02307 #if 1
02308 # define STCOM(x) (x)
02309 #else
02310 # define STCOM(x) (((x) + ((x)<<1))>>2)  /* 0.75 * x */
02311 #endif
02312 
02313    if( func_computed && func_showthru ){
02314       MRI_IMAGE * cim ;
02315 
02316       float ccf=-666.0 , ggf ;  /* 10 Jan 2000: merger factors */
02317       int   ccm=0 ;
02318       char * env = getenv("AFNI_RENDER_SHOWTHRU_FAC") ;
02319       if( env != NULL ) ccf = strtod(env,NULL) ;
02320       if( ccf <= 0.0 || ccf > 1.0 ) ccf = 1.0 ;
02321       ggf = 1.0 - ccf ;
02322       ccm = (ccf != 1.0) ;
02323 
02324       func_showthru_pass = 1 ;
02325       REND_reload_renderer() ;  /* load showthru data */
02326 
02327       if( func_showthru_dcue )
02328         MREN_depth_cue( render_handle , 1 ) ;         /* 11 Sep 2001 */
02329 
02330       cim = MREN_render( render_handle , npixels ) ;  /* render it */
02331 
02332       if( func_showthru_dcue )
02333         MREN_depth_cue( render_handle , 0 ) ;         /* 11 Sep 2001 */
02334 
02335       if( cim == NULL ){
02336         (void) MCW_popup_message( draw_pb ,
02337                                      "** ShowThru Rendering fails, **\n"
02338                                      "** for unknown reasons       **\n\n"
02339                                      "** Sorry about that -- RWCox **\n" ,
02340                                   MCW_USER_KILL | MCW_TIMER_KILL ) ;
02341         XBell(dc->display,100) ;
02342       } else {
02343          byte *rar=MRI_BYTE_PTR(rim) , *car=MRI_RGB_PTR(cim) ; /* composite it */
02344          int ii ;
02345 
02346          for( ii=0 ; ii < cim->nvox ; ii++ ){
02347             if( car[3*ii] == 0 && car[3*ii+1] == 0 && car[3*ii+2] == 0 ){
02348                car[3*ii] = car[3*ii+1] = car[3*ii+2] = STCOM( rar[ii] ) ;
02349 
02350             } else if( ccm ){                                /* 10 Jan 2000 */
02351                car[3*ii]   = ccf*car[3*ii]   + ggf*rar[ii] ; /* merge color */
02352                car[3*ii+1] = ccf*car[3*ii+1] + ggf*rar[ii] ; /* & grayscale */
02353                car[3*ii+2] = ccf*car[3*ii+2] + ggf*rar[ii] ;
02354             }
02355          }
02356 
02357          mri_free(rim) ; rim = cim ;
02358       }
02359    }
02360 
02361    /* 20 Dec 1999 - restrict colors, if ordered and needed */
02362 
02363    if( rim->kind == MRI_rgb && wfunc_color_pbar != NULL && func_mixshade >= NOSHADE ){
02364 
02365       int ii ; byte * bp = MRI_RGB_PTR(rim) ;
02366       for( ii=0 ; ii < rim->nvox ; ii++ )
02367          if( bp[3*ii] != 0 || bp[3*ii+1] != 0 || bp[3*ii+2] != 0 )
02368            DC_rgb_to_ovrgb( dc ,
02369                             wfunc_color_pbar->num_panes , wfunc_color_pbar->ov_index ,
02370                             (func_mixshade == NOMIX) ,
02371                             bp+(3*ii) , bp+(3*ii+1) , bp+(3*ii+2) ) ;
02372    }
02373 
02374 #ifdef USE_SCRIPTING
02375    if( last_rendered_state == NULL )
02376       last_rendered_state = (RENDER_state *) malloc(sizeof(RENDER_state)) ;
02377 
02378    REND_widgets_to_state( last_rendered_state ) ;
02379 #endif
02380 
02381    if( accum_flag || automate_flag ){
02382       if( renderings == NULL ){
02383          INIT_IMARR( renderings ) ;
02384 #ifdef USE_SCRIPTING
02385          INIT_RSA( renderings_state ) ; script_load_last = -1 ;
02386 #endif
02387       }
02388       ADDTO_IMARR( renderings , rim ) ;
02389 #ifdef USE_SCRIPTING
02390       { RENDER_state * rs = (RENDER_state *) malloc(sizeof(RENDER_state)) ;
02391         *rs = *last_rendered_state ;
02392         ADDTO_RSA( renderings_state , rs ) ;
02393       }
02394 #endif
02395    } else {
02396       DESTROY_IMARR( renderings ) ;
02397       INIT_IMARR( renderings ) ;
02398       ADDTO_IMARR( renderings , rim ) ;
02399 #ifdef USE_SCRIPTING
02400       { RENDER_state * rs = (RENDER_state *) malloc(sizeof(RENDER_state)) ;
02401         DESTROY_RSA( renderings_state ) ;
02402         INIT_RSA( renderings_state ) ; script_load_last = -1 ;
02403         *rs = *last_rendered_state ;
02404         ADDTO_RSA( renderings_state , rs ) ;
02405       }
02406 #endif
02407    }
02408    REND_update_imseq() ;
02409 
02410    MCW_invert_widget(draw_pb) ;
02411    FIX_SCALE_SIZE ;     /* 09 May 2001 */
02412    return ;
02413 }
02414 
02415 /*-------------------------------------------------------------------
02416   Callback for help button
02417 ---------------------------------------------------------------------*/
02418 
02419 void REND_help_CB( Widget w, XtPointer client_data, XtPointer call_data )
02420 {
02421    (void ) new_MCW_textwin( info_lab ,
02422 
02423        "++++++++++++++++++  V O L U M E   R E N D E R I N G  ++++++++++++++++++\n"
02424        "\n"
02425        "This plugin is used to render one brick from a 3D dataset in grayscale\n"
02426        "(the underlay), possibly overlaid in color with another (functional)\n"
02427        "dataset.  Although lengthy, this help is still rather terse.  Some\n"
02428        "experimentation will be needed to get decent results, since there are\n"
02429        "many controls that affect the way the final images appear.\n"
02430        "\n"
02431        "General Notes:\n"
02432        "--------------\n"
02433        " * To be rendered, an underlay dataset must have cubical voxels,\n"
02434        "     its data must be stored as bytes or shorts (but may have\n"
02435        "     a floating point scaling factor attached), and must\n"
02436        "     be stored as axial slices in the 'RAI' orientation\n"
02437        "     (x axis is Right-to-Left, y axis is Anterior-to-Posterior,\n"
02438        "     and z axis is Inferior-to-Superior).  This orientation\n"
02439        "     is how datasets are written out in the +acpc and +tlrc\n"
02440        "     coordinates -- with axial slices.\n"
02441 #ifdef ONLY_AXIAL
02442        "   N.B.: Combining the 3ddup and 3daxialize programs makes it\n"
02443        "         possible to create an cubical-voxel axially-oriented\n"
02444        "         copy of any dataset.\n"
02445 #else
02446        "   N.B.: The requirement that the dataset be stored in axial slices\n"
02447        "         has been removed; however, the cutouts will not work\n"
02448        "         properly.  For example, a 'Superior to' cutout will remove\n"
02449        "         voxels along the 3rd axis of a dataset; for a dataset made\n"
02450        "         up of sagittal slices, this will result in a 'Left of' or\n"
02451        "         a 'Right of' type of cutting.\n"
02452 #endif
02453        "\n"
02454        " * Use the Draw button to render and image after making changes\n"
02455        "     to the drawing parameters or after closing the image window.\n"
02456        "\n"
02457        " * The 'Reload' button is used to re-copy the dataset brick into\n"
02458        "     the renderer.  This can be used if you are altering the\n"
02459        "     dataset interactively with the Draw Dataset plugin.\n"
02460        "     Otherwise, you probably don't need this often, since the reload\n"
02461        "     operation will be carried out as needed by the renderer.\n"
02462        "\n"
02463        " * The Precalc mode determines how much work is done ahead of\n"
02464        "     time to make rendering more efficient:\n"
02465        "\n"
02466        "      Low    = no precalculation, very slow rendering\n"
02467        "                (this is the default on SGI machines);\n"
02468        "      Medium = small amount of precalculation, speeds up\n"
02469        "                rendering quite a lot on most computers\n"
02470        "                (this is the default on non-SGI machines);\n"
02471        "      High   = large amount of precalculation, can speed up\n"
02472        "                rendering even more, but will consume \n"
02473        "                several seconds and A LOT of memory in\n"
02474        "                the process.  This is useful if the only\n"
02475        "                changes between frames are viewing angles.\n"
02476        "\n"
02477        " * WARNING: The Medium and High mode rendering functions do not\n"
02478        "            work well on some computers, producing images with\n"
02479        "            a grid stippled on top.  This problem occurs with\n"
02480        "            some SGI compilers and (I've heard) some Sun systems.\n"
02481        "            In such a case, you may have to use the Low mode,\n"
02482        "            as painful as it is.  (If I knew how to fix this,\n"
02483        "            I would, so don't complain to me!)\n"
02484        "   N.B.: The Unix environment variable AFNI_RENDER_PRECALC_MODE can\n"
02485        "         be set to 'Low', 'Medium', or 'High' to override the default\n"
02486        "         initial setting.\n"
02487        "\n"
02488        " * If you depress 'See Xhairs', a 3D set of crosshairs\n"
02489        "     corresponding to the AFNI focus position will be drawn.\n"
02490        "     If you move the crosshairs in one of the AFNI image\n"
02491        "     windows, the rendering window is not automatically updated,\n"
02492        "     unless the 'DynaDraw' button is also depressed.  Otherwise,\n"
02493        "     the next time the rendering is redrawn for some other\n"
02494        "     reason, the correct crosshair positions will be shown.\n"
02495        "   02 Jun 1999: The renderer will now draw partial crosshair sets,\n"
02496        "        as indicated by the 'Xhairs' chooser in the AFNI control\n"
02497        "        window from which the renderer was started.\n"
02498        "   08 Mar 2001: Right-clicking (mouse button 3) on this toggle will\n"
02499        "        popup a color chooser.  If you set the color to something\n"
02500        "        besides 'none', AND if you are displaying a color overlay,\n"
02501        "        then the crosshairs will be rendered in the overlay (you\n"
02502        "        could still choose 'white' for the color, if you like).\n"
02503        "    N.B.: If the color opacity is set to 'ShowThru', then the\n"
02504        "          crosshairs will show through whatever underlay data\n"
02505        "          may be in the way.\n"
02506        "    N.B.: If you want only the crosshairs in color, then set the\n"
02507        "          theshold on the overlay dataset so high that no actual\n"
02508        "          data will show in color.  The crosshair overlay will\n"
02509        "          still be visible.\n"
02510        "    N.B.: If you change the crosshair gap in the AFNI control panel,\n"
02511        "          you will have to press 'Reload' in the renderer to force\n"
02512        "          a redraw with the new crosshairs.\n"
02513        "\n"
02514        " * If you depress 'DynaDraw', then the image will be re-\n"
02515        "     rendered immediately whenever certain actions are taken:\n"
02516        "      + The 'See Xhairs' toggle state is changed.\n"
02517        "      + A viewing angle is changed by pressing an arrow.\n"
02518        "      + A cutout parameter value is changed by pressing an arrow or\n"
02519        "        a 'Get' button.\n"
02520        "     Changing one of these values by directly typing in the\n"
02521        "     corresponding text entry field will NOT force a redraw\n"
02522        "     even in DynaDraw mode -- you will have to press 'Draw'.\n"
02523        "     Other changes (e.g., altering the opacity graph) will\n"
02524        "     not force a dynamic redraw and also require the use\n"
02525        "     of the 'Draw' button.\n"
02526        "   N.B.: The data entry fields with which DynaDraw and Automate\n"
02527        "         interact are displayed with a raised border, unlike\n"
02528        "         other data entry fields (e.g., 'Bot').\n"
02529        "   N.B.: The default stepsize for the angle and cutout variables\n"
02530        "         when an arrow is pressed is 5.0.  These values can be\n"
02531        "         altered by setting the Unix environment variables\n"
02532        "         AFNI_RENDER_ANGLE_DELTA and AFNI_RENDER_CUTOUT_DELTA\n"
02533        "         prior to running AFNI.  Once AFNI is started, these\n"
02534        "         stepsizes can only be altered from the\n"
02535        "         'Datamode->Misc->Edit Environment' menu item.\n"
02536        "   N.B.: Other circumstances that will invoke automatic redrawing\n"
02537        "         when DynaDraw is depressed include:\n"
02538        "      + The crosshairs are moved in an AFNI image window belonging\n"
02539        "        to the same controller, AND the 'See Xhairs' button is\n"
02540        "        depressed.\n"
02541        "      + You are also editing the dataset using the 'Draw Dataset'\n"
02542        "        plugin (invoked from the same controller), and you have\n"
02543        "        changed the dataset with a drawing operation.\n"
02544        "\n"
02545        " * If you depress 'Accumulate' IN, then rendered images are\n"
02546        "     saved as they are computed and can be re-viewed in the\n"
02547        "     image display window.  If Accumulate is OUT, then only\n"
02548        "     the latest image is kept.\n"
02549        "   N.B.: The image display window is like an AFNI slice viewing\n"
02550        "         window, but the slider control simply lets you scroll\n"
02551        "         back through past renderings, not through the spatial\n"
02552        "         extent of the dataset in any way.  Each additional\n"
02553        "         accumulated image appears as the last image in the\n"
02554        "         sequence, no matter where you are when 'Draw' activates.\n"
02555 #ifdef ALLOW_INCROT /* 26 Apr 2002 - RWCox */
02556        "\n"
02557        " * The 'I' toggle left of the 'Roll' button lets you select\n"
02558        "     incremental mode for angle changes made with the arrow\n"
02559        "     buttons.\n"
02560        "     + In incremental mode, the extra rotation implied by\n"
02561        "         pressing the arrow button will be around the spatial\n"
02562        "         axis corresponding to that button:\n"
02563        "         Roll=I-S axis, Pitch=R-L axis, Yaw=A-P axis.\n"
02564        "     + In non-incremental mode, the rotation angles are always\n"
02565        "         applied in the order Yaw, Pitch, Roll; the result may\n"
02566        "         not be intuitive since the SO(3) group is not Abelian.\n"
02567        "     + In incremental mode, when you press an angle arrow button,\n"
02568        "         new absolute spatial angles corresponding to the changed\n"
02569        "         orientation are calculated and put into the Roll, Pitch,\n"
02570        "         and Yaw text fields.\n"
02571        "     + Incremental rotation mode does not combine with Automate.\n"
02572 #endif /* ALLOW_INCROT */
02573        "\n"
02574        "Brightness and Opacity:\n"
02575        "-----------------------\n"
02576        " * The Min= and Max= values show the range of numbers stored\n"
02577        "     in the dataset brick.  The brick is copied into internal\n"
02578        "     memory for rendering.  You can use the 'Bot' and 'Top'\n"
02579        "     controls to limit the range of the copied voxel data.\n"
02580        "     Anything below 'Bot' will be set to the Bot value, and\n"
02581        "     anything above 'Top' will be set to the Top value.\n"
02582        "     (If Bot < Min, then Bot is effectively equal to Min;\n"
02583        "      if Top > Max, then Top is effectively equal to Max.)\n"
02584        "     In this way, you can eliminate the effect of a few extreme\n"
02585        "     data values.\n"
02586        "\n"
02587        " * The 'Sqrt Histogram' graph displays the square root of the\n"
02588        "     histogram of the dataset brick.  (The square root is graphed\n"
02589        "     so that small values will be somewhat enhanced in the display.\n"
02590        "     Also, the 0 bin value is not used in selecting the scale factor\n"
02591        "     for display, since it often is far larger than other bins.)\n"
02592        "     The purpose of this histogram is to let you choose good\n"
02593        "     values for Bot and Top.  After altering Bot and Top, press\n"
02594        "     the 'Reload' button to make the histogram graph be redrawn.\n"
02595        "\n"
02596        " * The 'Brightness' and 'Opacity' graphs are used to control\n"
02597        "     the mappings from dataset signal level (the numbers stored\n"
02598        "     in the voxels) to the grayscale and opacity levels.\n"
02599        "     The abscissa represents the copied voxel values, ranging\n"
02600        "     the larger of Min or Bot, to the smaller of Max or Top.\n"
02601        "     A larger opacity makes a voxel less transparent; for\n"
02602        "     example, a high opacity with a low brightness is like\n"
02603        "     black barrier in the line of sight.  Zero opacity\n"
02604        "     means a voxel is transparent and does not contribute to\n"
02605        "     the rendered image.\n"
02606        "\n"
02607        " * The ordinate on the 'Brightness' graph ranges from black\n"
02608        "     at the bottom to white at the top.  The ordinate on the\n"
02609        "     'Opacity' graph ranges from 0 (transparent) to 1 (opaque).\n"
02610        "\n"
02611        " * The 'Opacity Factor' control lets you scale the entire\n"
02612        "     underlay opacity down by some constant factor.  (However,\n"
02613        "     this doesn't seem to be very useful.)\n"
02614        "\n"
02615        "Cutouts:\n"
02616        "--------\n"
02617        " * The 'Cutouts' menu lets you select the number of regions to\n"
02618        "     be cut out of the volume prior to rendering (this is done\n"
02619        "     by setting the voxel opacity inside each cutout to zero).\n"
02620        "     Up to 9 cutouts can be combined at once.  There are 21 types\n"
02621        "     of cutouts, each of which is controlled by a single parameter.\n"
02622        "     For example, the parameter for a 'Right of' cutout is an\n"
02623        "     x-coordinate, and all the voxels to the right of this value\n"
02624        "     will be included in the cutout.\n"
02625        "   N.B.: Right     (of midline)   = negative x\n"
02626        "         Left      (of midline)   = positive x\n"
02627        "         Anterior  (to the AC)    = negative y\n"
02628        "         Posterior (to the AC)    = positive y\n"
02629        "         Inferior  (to the AC-PC) = negative z\n"
02630        "         Superior  (to the AC-PC) = positive z\n"
02631        "\n"
02632        " * The 'Expr > 0' cutout is a special (and slow) case. Instead\n"
02633        "     of a number, you enter an expression (using the 3dcalc\n"
02634        "     syntax) containing the symbols 'x', 'y', and 'z', which\n"
02635        "     represent the spatial coordinates of each voxel.  Voxels\n"
02636        "     where the expression evaluates to a positive number will\n"
02637        "     be cut out.  For example, '900-x*x-y*y-z*z' will cut out\n"
02638        "     the INTERIOR of a sphere of radius 30 mm, centered at the\n"
02639        "     origin of coordinates; 'x*x+y*y+z*z-900' will remove the\n"
02640        "     EXTERIOR of this sphere.\n"
02641        "\n"
02642        " * The 'TT Ellipsoid' cutout will remove all voxels exterior to\n"
02643        "     an ellipsoid that approximates the outer contour of the\n"
02644        "     Talairach-Tournoux atlas, when its 'Percentage' parameter\n"
02645        "     is set to 100.  Smaller percentages will shrink the ellipsoid\n"
02646        "     in towards the center of the brain; large percentages will\n"
02647        "     expand it outwards.\n"
02648        "\n"
02649        " * The 12 'Behind', 'Above', etc. cutouts are relative to planes at\n"
02650        "     45 degrees to the standard views.  For example, 'Behind AL-PR'\n"
02651        "     cuts out behind a slice that starts at Anterior-Left (AL) and\n"
02652        "     ends up at Posterior-Right (PR) -- halfway between a coronal\n"
02653        "     and a sagittal slice.  The simplest way to set the value\n"
02654        "     parameter for these (at least to start) is to use 'Get'.\n"
02655        "\n"
02656        " * The 'NonOverlay++' cutout will remove all voxels that would not\n"
02657        "     get colored if the overlay were turned on.  (If the parameter\n"
02658        "     'Radius++' is positive, then the region is dilated by that\n"
02659        "     many mm in all directions.)  This can be useful for seeing\n"
02660        "     exactly the anatomy that is deemed to be 'active'.\n"
02661        "   Notes:\n"
02662        "     + If there is no overlay dataset loaded, then this type of cutout\n"
02663        "       has no effect.\n"
02664        "     + 'Get' does nothing for this type of cutout.\n"
02665        "     + Viewing the color overlay with Radius++ set to a positive\n"
02666        "       value may be confusing, since the colored voxels will be\n"
02667        "       buried inside the visible tissue.  The combination of bright\n"
02668        "       colors with high color opacity and the use of a small\n"
02669        "       underlay opacity factor can make it possible to see the\n"
02670        "       color overlay through the translucent surrounding shell\n"
02671        "       of thickness Radius++.\n"
02672        "\n"
02673        " * Cutouts can be combined with the 'OR' logic, which means that\n"
02674        "     the union of all the specified cutout regions will be\n"
02675        "     removed.  They can also be combined with the 'AND' logic,\n"
02676        "     which means that the intersection of the cutout regions\n"
02677        "     will be removed.\n"
02678        "   N.B.: If the 'AND' logic is selected, a cutout can still be\n"
02679        "         forced to be removed in its entirety using the 'Must Do'\n"
02680        "         control.  (That is, 'AND' only applies to those that\n"
02681        "         do NOT have 'Must Do' selected; 'OR' applies to those\n"
02682        "         that DO have 'Must Do' selected.)  For an example, try\n"
02683        "         combining 'Right of', 'Anterior to', and 'Superior to'\n"
02684        "         cutouts first with 'OR', then with 'AND', and finally\n"
02685        "         with 'AND' but with the 'Superior to' cutout set to\n"
02686        "         'Must Do'.\n"
02687        "\n"
02688        "Automating the Calculation of Many Renderings:\n"
02689        "----------------------------------------------\n"
02690        " * If you depress 'Automate', then the automatic generation\n"
02691        "     of renderings as some parameter varies is enabled.\n"
02692        "     The 'Frames' field controls how many renderings will\n"
02693        "     be made.  To vary some parameter, you type an\n"
02694        "     arithmetic expression in the variable 't' in the\n"
02695        "     parameter control field.  The parameters that can\n"
02696        "     be so varied are the viewing angles and the cutout\n"
02697        "     parameters (i.e., those whose data entry field is\n"
02698        "     drawn with a raised border).  For the first rendering\n"
02699        "     t=0, for the second t=1, etc., up to t=N-1, where N is\n"
02700        "     the number of frames ordered.  (You can also use the\n"
02701        "     variable 'N' in the parameter expressions.) Once the\n"
02702        "     expressions are set up, press 'Compute' to begin\n"
02703        "     rendering automation.  (Then go have a pumpernickel\n"
02704        "     bagel and a cup of lapsang souchong tea.)\n"
02705        "\n"
02706        " * Notes about Automate:\n"
02707        "   1) If none of the parameters has an expression involving\n"
02708        "       't', then each frame in the rendering will be identical,\n"
02709        "       but the program won't detect that and you will waste a\n"
02710        "       lot of CPU time and memory.\n"
02711        "   2) Use the same expression syntax as with program 3dcalc.\n"
02712        "       An illegal expression (e.g., '2+*3t') will silently\n"
02713        "       evaluate to zero.\n"
02714        "   3) It is legal to have more than one parameter depend on 't'.\n"
02715        "        For example, combining cutouts\n"
02716        "           Anterior To:  -50+2*t\n"
02717        "           Posterior To: -40+2*t\n"
02718        "        with the OR logic produces a 10 mm thick coronal slice\n"
02719        "        that slides backwards at 2 mm per frame.\n"
02720        "   4) If Accumulate is on, then the frames created by automated\n"
02721        "       rendering will be added to the list of stored images.  If\n"
02722        "       Accumulate is off, the previously saved images will be\n"
02723        "       discarded, and only the newly generated image sequence will\n"
02724        "       be available for viewing.\n"
02725        "   5) There is no way to save an animation to disk as a unit.\n"
02726        "       However, you could use the 'Save:bkg' button on the image\n"
02727        "       viewer to save each image to disk in PNM format, then convert\n"
02728        "       the collection of individual image files to some movie format,\n"
02729        "       using software outside of the AFNI package.\n"
02730        "   6) Using an arrow to change a field with an expression\n"
02731        "       entered will result in the destruction of the expression\n"
02732        "       string and its replacement by a number.\n"
02733        "   7) At the end of an Automate run, you can convert a field\n"
02734        "       with an expression to its final numerical value by\n"
02735        "       clicking in the data field and then pressing the\n"
02736        "       Enter (or Return) key.  In combination with Accumulate,\n"
02737        "       this makes it easy to chain together the results of\n"
02738        "       multiple automated rendering computations, first varying\n"
02739        "       one parameter and then another.\n"
02740        "   8) During an Automate run, a 'CANCEL' button to the right\n"
02741        "       of 'Compute' becomes visible.  If you press this, then\n"
02742        "       the automation will be interrupted when it finishes the\n"
02743        "       image on which it is working (you have to wait until\n"
02744        "       that time -- pressing the button twice won't help!).\n"
02745 #ifdef USE_SCRIPTING
02746        "   Z) The 'Scripts' method, described below, is an entirely\n"
02747        "       separate method of generating multiple renderings at once.\n"
02748 #endif
02749        "\n"
02750        "Color Overlays\n"
02751        "--------------\n"
02752        "By pressing the 'Overlay' button, you can access the controls for\n"
02753        "displaying a second dataset in color on top of the underlay dataset.\n"
02754        "(Unlike the underlay dataset, the voxel data in the overlay may be\n"
02755        "stored as floats, as well as shorts or bytes.)  The controls are\n"
02756        "designed to be similar to the controls in the 'Define Function'\n"
02757        "control panel in a main AFNI window, and so only the principal\n"
02758        "differences will be explained here.\n"
02759        "\n"
02760        " * One brick ('Color') is chosen to determine the colors shown, and\n"
02761        "     another brick ('Thr') to determine which voxels from the overlay\n"
02762        "     dataset will be shown at all.  If you don't want thresholding\n"
02763        "     applied, just set the threshold slider down to 0.\n"
02764        "\n"
02765        " * The 'Color Opacity' control determines how opaque each supra-\n"
02766        "     threshold voxel will be.  If it is set to 'Underlay', then\n"
02767        "     the opacity of a colored voxel will be determined from the\n"
02768        "     underlay opacity at that location.\n"
02769        "   N.B.: The special value of 'ShowThru' will make the color overlay\n"
02770        "         be opaque (opacity=1.0), and also show through the grayscale\n"
02771        "         underlay no matter how far it is embedded inside the brain.\n"
02772        "         This is done by doing 2 renderings, 1 with the underlay only\n"
02773        "         and one with the overlay only.  The resulting 2 images are\n"
02774        "         then merged.  The default merger is to use an overlay pixel\n"
02775        "         if it is nonzero, otherwise use the corresponding underlay\n"
02776        "         pixel.  The environment variable AFNI_RENDER_SHOWTHRU_FAC\n"
02777        "         can be used to control the merging when the overlay image\n"
02778        "         pixel is nonzero.  This variable should be set to a value\n"
02779        "         between 0.0 and 1.0; suppose that its value is denoted by c.\n"
02780        "         Then the merging algorithm, at each image pixel, is\n"
02781        "           if( overlay == 0 ) pixel = underlay;\n"
02782        "           else               pixel = c * overlay + (1-c) * underlay;\n"
02783        "         I personally like the results with c=0.65.  This environment\n"
02784        "         variable (and others) can be set from the AFNI control panel\n"
02785        "         'Datamode->Misc->Edit Environment' menu item.\n"
02786        "   11 Sep 2001: The new option 'ST+Dcue' is the same as ShowThru,\n"
02787        "         with the addition of Depth cueing to the color overlay.\n"
02788        "         This means that colored voxels in the back half of the\n"
02789        "         rendered volume will be darkened, simulating fading off\n"
02790        "         with depth.  This helps cue your visual system to understand\n"
02791        "         which objects are where in the image.\n"
02792        "\n"
02793        " * 'See Overlay' is used to toggle the color overlay computations\n"
02794        "     on and off - it should be pressed IN for the overlay to become\n"
02795        "     visible.\n"
02796        " * 'TT Atlas' is used to toggle the overlay of regions from the\n"
02797        "     Talairach Atlas on and off.  This option only has effect if\n"
02798        "     the underlay dataset being viewed in the the +tlrc coordinate\n"
02799        "     system and has 1 mm cubical voxels (the default).\n"
02800        "\n"
02801        " * 'Cutout Overlay' determines if the cutout operations affect the\n"
02802        "     overlaid voxels.  If it is pressed IN, then cutouts will include\n"
02803        "     the overlay; if OUT, then colored voxels will hang free in\n"
02804        "     empty space where the underlay was cutout beneath them.\n"
02805        "   N.B.: If 'Color Opacity' is set to 'Underlay', the cutouts will\n"
02806        "         hit the overlay in all cases, since cutouts are implemented\n"
02807        "         by setting the opacity of the underlay to zero in the chosen\n"
02808        "         regions.\n"
02809        "\n"
02810        " * 'Remove Small Clusters', if pressed IN, will cause clusters\n"
02811        "     of voxels below a given threshold volume to be excised before\n"
02812        "     rendering.  The parameters defining this cluster editing are\n"
02813        "     determined by the controls immmediately beneath, which use the\n"
02814        "     same conventions as program 3dclust.\n"
02815        "\n"
02816        " * None of the overlay controls are hooked up to 'DynaDraw' or to\n"
02817        "     'Automate'.  You must manually press 'Draw' to see the effects\n"
02818        "     of changes to these settings.\n"
02819        "\n"
02820        " * A slightly different colormap is used when rendering overlays than\n"
02821        "     when only underlays are visible.  The result is that the grayscale\n"
02822        "     underlay will look a little different between the 'See Overlay'\n"
02823        "     IN and OUT conditions.  Also, the colormaps are rendered into\n"
02824        "     24 bit RGB images, which might not be faithfully displayed in\n"
02825        "     the image window if your system is using an X11 PseudoColor visual\n"
02826        "     (the most common display mode). If the 'Save:bkg' button is used\n"
02827        "     to save a set of RGB images, they will be saved in their internal\n"
02828        "     color resolution (in PPM format); they might appear slightly\n"
02829        "     different when viewed outside AFNI (e.g., using program xv).\n"
02830        "   N.B.: When viewing an RGB image, most of the image processing\n"
02831        "         options available from the 'Disp' control panel do not\n"
02832        "         function.  'Sharpen' still works, and is very useful.\n"
02833        "\n"
02834        " * The Button-3 popup menu under the 'Color' label above the pbar\n"
02835        "     has an extra menu that lets you control the way in which colors\n"
02836        "     are mixed in the final display.\n"
02837        "     In the Volpack color computations, colors are composited along rays\n"
02838        "     that pass through the volume.  This can produce peculiar mixes of\n"
02839        "     colors (e.g., a blue voxel behind a red voxel will produce a\n "
02840        "     purple shade, which may not be on the color pbar).\n"
02841        "     The 'Mixing' menu lets you excise these mixed colors:\n"
02842        "     * 'Normal' gives the full range of Volpack generated colors.\n"
02843        "     * 'NoShade' means the overlaid colors generated by Volpack\n"
02844        "          will be remapped to the set shown on the pbar.\n"
02845        "     * 'NoMix' means that the overlay colors rendered will be remapped\n"
02846        "          to shades of the set shown on the pbar (that is, the hues will\n"
02847        "          be the same, but the intensities will vary).\n"
02848        "   N.B.: Volpack controls the color composition along each pixel ray.\n"
02849        "         All that these options do is remap the composed colors back to\n"
02850        "         a more limited set.  If no good match is found, then a gray shade\n"
02851        "         with the same intensity is chosen.  The results of this remapping\n"
02852        "         may or may not look good!\n"
02853        "   N.B.: As discussed above, when shown on a PseudoColor display, shaded\n"
02854        "         colors may look peculiar, but will be saved to a PPM file\n"
02855        "         properly.\n"
02856        "   N.B.: You may want to set 'Color Opacity' to 1.0 when using the 'NoMix'\n"
02857        "         and 'NoShade' options.\n"
02858 #ifdef USE_SCRIPTING
02859        "   N.B.: The setting of the 'Mixing' control is NOT saved or restored by\n"
02860        "         any of the 'Scripts' options!\n"
02861 #endif
02862        "\n"
02863 #ifdef USE_SCRIPTING
02864        "Scripts: [July 1999]\n"
02865        "--------\n"
02866        " * This facility, controlled from the 'Scripts' menu button, lets you\n"
02867        "     save rendering settings and recall them later.  This is useful\n"
02868        "     when you want to render multiple datasets in the same fashion.\n"
02869        "\n"
02870        " * 'Save This' will store the current state of the rendering settings\n"
02871        "     to a file.  Rendering settings are stored in files with suffix\n"
02872        "     '.rset', and are ASCII files that can be edited -- with care!\n"
02873        "\n"
02874        " * 'Save Many' will store all the rendering settings used to create\n"
02875        "     the currently accumulated images.\n"
02876        "\n"
02877        " * 'Read This' will read one rendering state from a .rset file and\n"
02878        "     make the interface widgets reflect that state.  Nothing will\n"
02879        "     be rendered until you press the 'Draw' button.  If the .rset\n"
02880        "     file has more than one rendering state (e.g., from ''Save Many')\n"
02881        "     you will be asked to choose which state you want to load.\n"
02882        "\n"
02883        " * 'Read & Exec' will read a set of rendering states from a .rset file\n"
02884        "     and execute them, producing a new set of images.  If more than\n"
02885        "     one rendering is being computed, you can use the CANCEL button\n"
02886        "     (as in Automate) to stop the rendering.\n"
02887        "\n"
02888        " * The toggle button 'Load Widgets', when activated, will cause the\n"
02889        "     interface widgets to be loaded with the rendering state used to\n"
02890        "     create the currently visible image.  When you move the slider\n"
02891        "     to see a different image from the accumulation, the widgets will\n"
02892        "     change accordingly.  This lets you recall how you created a\n"
02893        "     particular image.  If this button is deactivated, then the\n"
02894        "     widgets will reflect the last image rendered, no matter which\n"
02895        "     image is actually visible.\n"
02896        "\n"
02897        " * The toggle button 'Brick Index?' controls whether the sub-brick\n"
02898        "     indexes are to be changed when new rendering values are loaded\n"
02899        "     via one of the 'Read' buttons, or via the 'Load Widgets' toggle.\n"
02900 #ifdef SCRIPT_GRAFS
02901        "\n"
02902        " * The toggle button 'Alter Grafs?' controls whether the Brightness\n"
02903        "     and Opacity interactive graphs are to be restored when new\n"
02904        "     rendering values are loaded (via 'Read' or 'Load Widgets').\n"
02905 #endif
02906 #ifdef SCRIPT_DSETS
02907        "\n"
02908        " * The toggle button 'Alter Dsets?' controls whether the datasets\n"
02909        "     will be changed (from the dataset ID codes) when new\n"
02910        "     rendering values are loaded (via 'Read' or 'Load Widgets').\n"
02911 #endif
02912        "\n"
02913        " N.B.: When you render a new image, it always goes at the END of\n"
02914        "         the accumulation, no matter which image you happen to be\n"
02915        "         viewing when you press 'Draw', or otherwise cause rendering.\n"
02916        " N.B.: The format of a .rset file is described in the documentation\n"
02917        "         file README.render_scripts.  By editing such a file, you can\n"
02918        "         create a script that can be used to create many renderings\n"
02919        "         at once (via the 'Read & Exec' button).\n"
02920        "\n"
02921 #endif  /* USE_SCRIPTING */
02922        "Final Notes:\n"
02923        "------------\n"
02924        " * The rendering is done using the VolPack library from Stanford,\n"
02925        "     by Philippe Lacroute (http://www-graphics.stanford.edu).\n"
02926        "     This library behaves peculiarly on some SGI systems (perhaps\n"
02927        "     due to compiler bugs) , and may produce incorrect images\n"
02928        "     in 'Medium' and 'High' modes.  'Low' mode seem always to work\n"
02929        "     well, but is unfortunately quite slow.\n"
02930        "\n"
02931        " * The images produced may look a little blurry, due to the linear\n"
02932        "     interpolation scheme used by VolPack.  You can use the 'Sharpen'\n"
02933        "     option on the image viewer 'Disp' control panel to make them\n"
02934        "     look nicer.\n"
02935        "\n"
02936        " * When only one image is rendered (i.e., Accumulate is off), the\n"
02937        "     image viewer window does not show the control widgets.  The 'Disp'\n"
02938        "     controls can be accessed by the combination keypress-mouseclick\n"
02939        "     'Shift-Button3' in the image window, and the 'Save' controls by\n"
02940        "     'Alt-Button3' (some systems don't allow this last combination\n"
02941        "     to be detected by the application program; in such a case, you\n"
02942        "     must have at least 2 images accumulated to be able to use 'Save').\n"
02943        "\n"
02944        " * This plugin is very CPU and memory intensive, and will not run\n"
02945        "     at all decently on a computer with less than 128 MB of RAM.\n"
02946        "------------------------------------------------------------------------\n"
02947        "\n"
02948        "RW Cox, Milwaukee - February 1999 [first version]\n"
02949        "                  - July 1999     [Scripts]\n"
02950        "                  - April 2000    [Scripts can change datasets]\n"
02951 
02952     , TEXT_READONLY ) ;
02953    return ;
02954 }
02955 
02956 /*-------------------------------------------------------------------
02957   Callback for (underlay) choose button.
02958   Criteria for datasets that can be rendered:
02959     - must be in current session
02960     - must have actual bricks of bytes or shorts
02961     - bricks must have cubical grid
02962     - bricks must be in RAI orientation
02963 ---------------------------------------------------------------------*/
02964 
02965 /*-- 26 Apr 1999: relax requirement that dataset be axial --*/
02966 
02967 #ifdef ONLY_AXIAL
02968 # define IS_AXIAL_RAI(ds) ( ( (ds)->daxes->xxorient == ORI_R2L_TYPE ) && \
02969                             ( (ds)->daxes->yyorient == ORI_A2P_TYPE ) && \
02970                             ( (ds)->daxes->zzorient == ORI_I2S_TYPE )     )
02971 # define IS_AXIAL_LPI(ds) ( ( (ds)->daxes->xxorient == ORI_L2R_TYPE ) && \
02972                             ( (ds)->daxes->yyorient == ORI_P2A_TYPE ) && \
02973                             ( (ds)->daxes->zzorient == ORI_I2S_TYPE )     )
02974 # define IS_AXIAL(ds) ( IS_AXIAL_RAI(ds) || IS_AXIAL_LPI(ds) )
02975 #else
02976 # define IS_AXIAL(ds) (1)
02977 #endif
02978 
02979 #define USEFUL_DSET(ds)                                    \
02980     (( ISVALID_DSET(ds)                      )          && \
02981      ( DSET_INMEMORY(ds)                     )          && \
02982      ( DSET_CUBICAL(ds)                      )          && \
02983      ( DSET_BRICK_TYPE(ds,0) == MRI_short ||               \
02984        DSET_BRICK_TYPE(ds,0) == MRI_byte  ||               \
02985       (DSET_BRICK_TYPE(ds,0) == MRI_float && float_ok)) && \
02986      IS_AXIAL(ds)                                            )
02987 
02988 static int                  ndsl = 0 ;
02989 static PLUGIN_dataset_link * dsl = NULL ;
02990 
02991 void REND_load_dsl( THD_3dim_dataset * mset , int float_ok )
02992 {
02993    THD_session * ss  = im3d->ss_now ;           /* current session */
02994    int           vv  = im3d->vinfo->view_type ; /* view type */
02995    THD_3dim_dataset * qset ;
02996    int id , nx,ny,nz ;
02997 
02998    ndsl = 0 ; /* initialize */
02999 
03000    if( ISVALID_DSET(mset) ){
03001       nx = DSET_NX(mset) ; ny = DSET_NY(mset) ; nz = DSET_NZ(mset) ;
03002    } else {
03003       nx = ny = nz = 0 ;
03004    }
03005 
03006    /* scan datasets */
03007 
03008    for( id=0 ; id < ss->num_dsset ; id++ ){
03009       qset = ss->dsset[id][vv] ;
03010 
03011       if( ! USEFUL_DSET(qset) ) continue ;   /* skip this one */
03012 
03013       if( nx > 0 && DSET_NX(qset) != nx ) continue ;  /* must match */
03014       if( ny > 0 && DSET_NY(qset) != ny ) continue ;  /* brick size */
03015       if( nz > 0 && DSET_NZ(qset) != nz ) continue ;
03016 
03017       ndsl++ ;
03018       dsl = (PLUGIN_dataset_link *)
03019               XtRealloc( (char *) dsl , sizeof(PLUGIN_dataset_link)*ndsl ) ;
03020 
03021       make_PLUGIN_dataset_link( qset , dsl + (ndsl-1) ) ;  /* cf. afni_plugin.c */
03022    }
03023 
03024    return ;
03025 }
03026 
03027 void REND_choose_CB( Widget w, XtPointer client_data, XtPointer call_data )
03028 {
03029    int vv = im3d->vinfo->view_type ; /* view type */
03030    THD_3dim_dataset * qset ;
03031    int id , ltop , llen , dofunc ;
03032    char qnam[THD_MAX_NAME] , label[THD_MAX_NAME] ;
03033    static char ** strlist = NULL ;
03034 
03035    int isl = -2 ;     /* 03 Apr 1999 */
03036    MCW_idcode midc ;
03037 
03038    /*-- decide if we want overlay (func) or underlay --*/
03039 
03040    dofunc = (w == wfunc_choose_pb) ;
03041 
03042    if( dofunc && !ISVALID_DSET(dset) ){
03043       (void) MCW_popup_message( w ,
03044                                    "Can't choose overlay\nbefore underlay!" ,
03045                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
03046       XBell(dc->display,100) ; return ;
03047    }
03048 
03049    if( dofunc )
03050       REND_load_dsl( dset , 1 ) ;
03051    else
03052       REND_load_dsl( NULL , 0 ) ;
03053 
03054    /* found nothing?  exit */
03055 
03056    if( ndsl < 1 ){
03057       (void) MCW_popup_message( w ,
03058                                    "Didn't find\nany datasets\nto render!" ,
03059                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
03060       XBell(dc->display,100) ; return ;
03061    }
03062 
03063    /*--- loop over dataset links and patch their titles
03064          to include an indicator of the dataset type    ---*/
03065 
03066    ltop = 4 ;
03067    for( id=0 ; id < ndsl ; id++ ){
03068       llen = strlen(dsl[id].title) ;
03069       ltop = MAX(ltop,llen) ;
03070    }
03071 
03072    for( id=0 ; id < ndsl ; id++ ){
03073       qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;
03074       if( ! ISVALID_DSET(qset) ) continue ;
03075       if( ISANAT(qset) ){
03076          if( ISANATBUCKET(qset) )         /* 30 Nov 1997 */
03077             sprintf(qnam,"%-*s [%s:%d]" ,
03078                     ltop,dsl[id].title ,
03079                     ANAT_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
03080 
03081          else if( DSET_NUM_TIMES(qset) == 1 )
03082             sprintf(qnam,"%-*s [%s]" ,
03083                     ltop,dsl[id].title ,
03084                     ANAT_prefixstr[qset->func_type] ) ;
03085 
03086          else
03087             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
03088                     ltop,dsl[id].title ,
03089                     ANAT_prefixstr[qset->func_type] , DSET_NUM_TIMES(qset) ) ;
03090 
03091       } else {
03092          if( ISFUNCBUCKET(qset) )         /* 30 Nov 1997 */
03093             sprintf(qnam,"%-*s [%s:%d]" ,
03094                     ltop,dsl[id].title ,
03095                     FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
03096 
03097          else if( DSET_NUM_TIMES(qset) == 1 )
03098             sprintf(qnam,"%-*s [%s]" ,
03099                     ltop,dsl[id].title ,
03100                     FUNC_prefixstr[qset->func_type] ) ;
03101 
03102          else
03103             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
03104                     ltop,dsl[id].title ,
03105                     FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
03106       }
03107 
03108       if( DSET_COMPRESSED(qset) ) strcat(qnam,"z") ;
03109 
03110       strcpy( dsl[id].title , qnam ) ;
03111    }
03112 
03113    /*--- make a popup chooser for the user to browse ---*/
03114 
03115    POPDOWN_strlist_chooser ;
03116 
03117    strlist = (char **) XtRealloc( (char *)strlist , sizeof(char *)*ndsl ) ;
03118    for( id=0 ; id < ndsl ; id++ ) strlist[id] = dsl[id].title ;
03119 
03120    /*-- 03 Apr 1999: set the initial selection in the chooser --*/
03121 
03122         if(  dofunc && func_dset != NULL ){ midc = func_dset_idc; isl = -1; }
03123    else if( !dofunc && dset      != NULL ){ midc = dset_idc     ; isl = -1; }
03124 
03125    if( isl == -1 ){
03126       for( id=0 ; id < ndsl ; id++ ){
03127          if( EQUIV_IDCODES(midc,dsl[id].idcode) ){ isl = id ; break ; }
03128       }
03129    }
03130 
03131    /*-- popup the chooser -- */
03132 
03133    sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
03134 
03135    MCW_choose_strlist( w , label , ndsl , isl , strlist ,
03136                        (dofunc) ? REND_finalize_func_CB
03137                                 : REND_finalize_dset_CB , NULL ) ;
03138 
03139    return ;
03140 }
03141 
03142 void REND_finalize_dset_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
03143 {
03144    int id = cbs->ival ;
03145    THD_3dim_dataset * qset ;
03146    XmString xstr ;
03147    char str[2*THD_MAX_NAME] ;
03148    float fac ;
03149 
03150    /* check for errors */
03151 
03152    if( ! renderer_open ){ POPDOWN_strlist_chooser ; XBell(dc->display,100) ; return ; }
03153 
03154    if( id < 0 || id >= ndsl ){ XBell(dc->display,100) ; return ; }
03155 
03156    qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;  /* the new dataset? */
03157 
03158    if( qset == NULL ){ XBell(dc->display,100) ; return ; }
03159 
03160    if( ! DSET_CUBICAL(qset) ){ XBell(dc->display,100) ; return ; }
03161 
03162    /* if there was an existing renderer, kill it off */
03163 
03164    if( render_handle != NULL ){
03165       destroy_MREN_renderer(render_handle) ;
03166       render_handle = NULL ; func_cmap_set = 0 ;
03167    }
03168    FREE_VOLUMES ; INVALIDATE_OVERLAY ;
03169 
03170    /* accept this dataset */
03171 
03172    dset = qset ;
03173    dset_idc = qset->idcode ;  /* 31 Mar 1999 */
03174 
03175    npixels = 256 ;                             /* size of image to render */
03176    npixels = MAX( npixels , DSET_NX(dset) ) ;
03177    npixels = MAX( npixels , DSET_NY(dset) ) ;
03178    npixels = MAX( npixels , DSET_NZ(dset) ) ;
03179 
03180    /* refit the sub-brick selector menu */
03181 
03182    if( dset_ival >= DSET_NVALS(dset) ) dset_ival = DSET_NVALS(dset)-1 ;
03183 
03184    refit_MCW_optmenu( choose_av ,
03185                       0 ,                       /* new minval */
03186                       DSET_NVALS(dset)-1 ,      /* new maxval */
03187                       dset_ival ,               /* new inival */
03188                       0 ,                       /* new decim? */
03189                       REND_choose_av_label_CB , /* text routine */
03190                       dset                      /* text data */
03191                     ) ;
03192 
03193    AV_SENSITIZE( choose_av , (DSET_NVALS(dset) > 1) ) ;
03194 
03195    /* write the informational label */
03196 
03197    strcpy( dset_title , dsl[id].title ) ;
03198    fac = DSET_BRICK_FACTOR(dset,dset_ival) ;
03199 
03200    if( fac == 0.0 || fac == 1.0 ){
03201       strcpy(str,dset_title) ;
03202    } else {
03203       char abuf[16] ;
03204       AV_fval_to_char( fac , abuf ) ;
03205       sprintf(str,"%s [* %s]", dset_title , abuf ) ;
03206    }
03207    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
03208    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
03209    XmStringFree(xstr) ;
03210 
03211    /* if the existing overlay dataset doesn't match this one, kill the overlay */
03212 
03213    if( func_dset != NULL && ( DSET_NX(dset) != DSET_NX(func_dset) ||
03214                               DSET_NY(dset) != DSET_NY(func_dset) ||
03215                               DSET_NZ(dset) != DSET_NZ(func_dset)   ) ){
03216 
03217       INVALIDATE_OVERLAY ;
03218       func_dset = NULL ;
03219 
03220       TURNOFF_OVERLAY_WIDGETS ;
03221 
03222       (void) MCW_popup_message( choose_pb ,
03223                                    " \n"
03224                                    "** New underlay dataset did  **\n"
03225                                    "** not match dimensions of   **\n"
03226                                    "** existing overlay dataset, **\n"
03227                                    "** so the latter was removed **\n" ,
03228                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
03229    }
03230 
03231    /* read the new data */
03232 
03233    new_dset = 1 ;           /* flag it as new */
03234    REND_reload_dataset() ;  /* load the data */
03235 
03236    return ;
03237 }
03238 
03239 void REND_finalize_func_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
03240 {
03241    int id = cbs->ival ;
03242    THD_3dim_dataset * qset , * oset ;
03243    XmString xstr ;
03244    char str[2*THD_MAX_NAME] ;
03245    float fac ;
03246 
03247    /* check for errors */
03248 
03249    if( ! renderer_open ){ POPDOWN_strlist_chooser ; XBell(dc->display,100) ; return ; }
03250 
03251    if( id < 0 || id >= ndsl ){ XBell(dc->display,100) ; return ; }
03252 
03253    qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;  /* the new dataset? */
03254 
03255    if( qset == NULL ){ XBell(dc->display,100) ; return ; }
03256 
03257    /* accept this dataset */
03258 
03259    FREE_VOLUMES ; INVALIDATE_OVERLAY ;
03260 
03261    oset      = func_dset ;
03262    func_dset = qset ;
03263    func_dset_idc = qset->idcode ;  /* 31 Mar 1999 */
03264 
03265    /* refit the sub-brick selector menus */
03266 
03267    if( oset == NULL ){ func_color_ival = 0 ; func_thresh_ival = 1 ; }
03268 
03269    if( func_color_ival >= DSET_NVALS(func_dset) )
03270       func_color_ival = DSET_NVALS(func_dset)-1;
03271 
03272    refit_MCW_optmenu( wfunc_color_av ,
03273                       0 ,                       /* new minval */
03274                       DSET_NVALS(func_dset)-1 , /* new maxval */
03275                       func_color_ival ,         /* new inival */
03276                       0 ,                       /* new decim? */
03277                       REND_choose_av_label_CB , /* text routine */
03278                       func_dset                 /* text data */
03279                     ) ;
03280 
03281    AV_SENSITIZE( wfunc_color_av , (DSET_NVALS(func_dset) > 1) ) ;
03282 
03283    if( func_thresh_ival >= DSET_NVALS(func_dset) )
03284       func_thresh_ival = DSET_NVALS(func_dset)-1;
03285 
03286    refit_MCW_optmenu( wfunc_thresh_av ,
03287                       0 ,                       /* new minval */
03288                       DSET_NVALS(func_dset)-1 , /* new maxval */
03289                       func_thresh_ival ,        /* new inival */
03290                       0 ,                       /* new decim? */
03291                       REND_choose_av_label_CB , /* text routine */
03292                       func_dset                 /* text data */
03293                     ) ;
03294 
03295    AV_SENSITIZE( wfunc_thresh_av , (DSET_NVALS(func_dset) > 1) ) ;
03296 
03297    /* write the informational label */
03298 
03299    strcpy( func_dset_title , dsl[id].title ) ;
03300    fac = DSET_BRICK_FACTOR(func_dset,func_color_ival) ;
03301 
03302    if( fac == 0.0 || fac == 1.0 ){
03303       strcpy(str,func_dset_title) ;
03304    } else {
03305       char abuf[16] ;
03306       AV_fval_to_char( fac , abuf ) ;
03307       sprintf(str,"%s [* %s]", func_dset_title , abuf ) ;
03308    }
03309    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
03310    XtVaSetValues( wfunc_info_lab , XmNlabelString , xstr , NULL ) ;
03311    XmStringFree(xstr) ;
03312 
03313    /* fix the range labels */
03314 
03315    xstr = REND_range_label() ;
03316    XtVaSetValues( wfunc_range_label , XmNlabelString , xstr , NULL ) ;
03317    XmStringFree(xstr) ;
03318 
03319    xstr = REND_autorange_label() ;
03320    XtVaSetValues( wfunc_range_bbox->wbut[0], XmNlabelString,xstr , NULL ) ;
03321    XmStringFree(xstr) ;
03322 
03323    /* fix the p-value label */
03324 
03325    REND_set_thr_pval() ;
03326 
03327    /* read the new data */
03328 
03329 #if 0
03330    new_dset = 1 ;           /* flag it as new */
03331    REND_reload_dataset() ;  /* load the data */
03332 #endif
03333 
03334    AFNI_hintize_pbar( wfunc_color_pbar , FUNC_RANGE ) ; /* 30 Jul 2001 */
03335 
03336    return ;
03337 }
03338 
03339 /*-------------------------------------------------------------------
03340   Callback for precalc menu
03341 ---------------------------------------------------------------------*/
03342 
03343 void REND_precalc_CB( MCW_arrowval * av , XtPointer cd )
03344 {
03345    precalc_ival = av->ival ;
03346    return ;
03347 }
03348 
03349 /*-------------------------------------------------------------------
03350   Callback for angle arrowvals
03351 ---------------------------------------------------------------------*/
03352 
03353 void REND_angle_CB( MCW_arrowval * av , XtPointer cd )
03354 {
03355    float na ;
03356 
03357 /*==========================================================================*/
03358 #ifdef ALLOW_INCROT  /* 26 Apr 2002 - RWCox */
03359    if( cd == NULL && MCW_val_bbox(incrot_bbox) ){  /* increment mode  */
03360       REND_do_incrot( av ) ;                       /* ==> do work here */
03361       return ;
03362    }
03363 #endif
03364 /*==========================================================================*/
03365 
03366    if( av == roll_av  ){
03367 
03368       na = angle_roll = av->fval ;
03369            if( na <    0.0 ) na += 360 ;
03370       else if( na >= 360.0 ) na -= 360.0 ;
03371       if( na != av->fval ){ AV_assign_fval( av , na ) ; angle_roll = na ; }
03372 
03373    } else if( av == pitch_av ){
03374 
03375      na = angle_pitch = av->fval ;
03376            if( na <    0.0 ) na += 360 ;
03377       else if( na >= 360.0 ) na -= 360.0 ;
03378       if( na != av->fval ){ AV_assign_fval( av , na ) ; angle_pitch = na ; }
03379 
03380    } else if( av == yaw_av   ){
03381 
03382       na = angle_yaw = av->fval ;
03383            if( na <    0.0 ) na += 360 ;
03384       else if( na >= 360.0 ) na -= 360.0 ;
03385       if( na != av->fval ){ AV_assign_fval( av , na ) ; angle_yaw = na ; }
03386 
03387    } else {
03388       return ;  /* should never happen */
03389    }
03390 
03391    if( cd == NULL && dynamic_flag && render_handle != NULL )
03392       REND_draw_CB(NULL,NULL,NULL) ;
03393 
03394    return ;
03395 }
03396 
03397 /*==========================================================================*/
03398 #ifdef ALLOW_INCROT  /* 26 Apr 2002 - RWCox */
03399 
03400 void REND_incrot_CB( Widget w , XtPointer cld , XtPointer cad )
03401 {
03402    if( MCW_val_bbox(automate_bbox) ){       /* don't allow incrot */
03403       MCW_set_bbox( incrot_bbox , 0 ) ;     /* if Automate is set */
03404       return ;
03405    }
03406 
03407    /* if incrot is on, then force arrowvals back to numerical
03408       values in case they are now encoded as Automate expressions */
03409 
03410    if( MCW_val_bbox(incrot_bbox) ){
03411       REND_textact_CB( roll_av ->wtext , (XtPointer)roll_av  , NULL ) ;
03412       REND_textact_CB( pitch_av->wtext , (XtPointer)pitch_av , NULL ) ;
03413       REND_textact_CB( yaw_av  ->wtext , (XtPointer)yaw_av   , NULL ) ;
03414    }
03415 }
03416 
03417 /*--------------------------------------------------------------------------*/
03418 
03419 void REND_do_incrot( MCW_arrowval * av )
03420 {
03421    int ax ;
03422    float th , roll,pitch,yaw ;
03423 
03424    /* read angles from arrowval's current status */
03425 
03426    roll  = roll_av ->fval ;
03427    pitch = pitch_av->fval ;
03428    yaw   = yaw_av  ->fval ;
03429 
03430    /* choose axis of rotation based on what was just clicked,
03431     *       and set current angle for that axis to last value (before click) */
03432 
03433         if( av == roll_av  ){ ax = 2; roll  = av->old_fval; }
03434    else if( av == pitch_av ){ ax = 0; pitch = av->old_fval; }
03435    else if( av == yaw_av   ){ ax = 1; yaw   = av->old_fval; }
03436    else
03437         return ;   /* should never happen */
03438 
03439    th = av->fval - av->old_fval ;  /* angle increment */
03440 
03441    roll  *= (PI/180) ;  /* convert to radians */
03442    pitch *= (PI/180) ;
03443    yaw   *= (PI/180) ;
03444    th    *= (PI/180) ;
03445 
03446    /* compute new angles */
03447 
03448    REND_inc_angles( ax, th, &yaw , &pitch, &roll ) ;
03449 
03450    roll  = 0.001 * rint( (180000.0/PI)*roll  ) ;  /* convert to degrees */
03451    pitch = 0.001 * rint( (180000.0/PI)*pitch ) ;  /* (rounded to 1/1000) */
03452    yaw   = 0.001 * rint( (180000.0/PI)*yaw   ) ;
03453 
03454    /* put back into arrowvals */
03455 
03456    AV_assign_fval( roll_av  , roll  ) ; angle_roll  = roll  ;
03457    AV_assign_fval( yaw_av   , yaw   ) ; angle_yaw   = yaw   ;
03458    AV_assign_fval( pitch_av , pitch ) ; angle_pitch = pitch ;
03459 
03460    /* redraw if desirable */
03461 
03462    if( dynamic_flag && render_handle != NULL )
03463       REND_draw_CB(NULL,NULL,NULL) ;
03464 
03465    return ;
03466 }
03467 #endif /* ALLOW_INCROT */
03468 /*==========================================================================*/
03469 
03470 /*-----------------------------------------------------------------------
03471    Callback for xhair toggle button
03472 -------------------------------------------------------------------------*/
03473 
03474 #define CHECK_XHAIR_ERROR                                               \
03475   do{ if( xhair_flag && dset!=NULL &&                                   \
03476           ! EQUIV_DATAXES(dset->daxes,im3d->wod_daxes) ){               \
03477         MCW_set_bbox( xhair_bbox , 0 ) ; xhair_flag = 0 ;               \
03478         (void) MCW_popup_message( xhair_bbox->wrowcol ,                 \
03479                                      "Can't overlay AFNI crosshairs\n"  \
03480                                      "because dataset grid and AFNI\n"  \
03481                                      "viewing grid don't coincide."   , \
03482                                   MCW_USER_KILL | MCW_TIMER_KILL ) ;    \
03483         XBell(dc->display,100) ; return ;                               \
03484      } } while(0)
03485 
03486 void REND_xhair_CB( Widget w , XtPointer cd , XtPointer call_data )
03487 {
03488    int old_xh = xhair_flag ;
03489 
03490    xhair_flag = MCW_val_bbox( xhair_bbox ) ;
03491    if( old_xh == xhair_flag ) return ;
03492 
03493    CHECK_XHAIR_ERROR ;
03494    FREE_VOLUMES ; INVALIDATE_OVERLAY ;
03495 
03496    xhair_ixold = -666 ; xhair_jyold = -666 ; xhair_kzold = -666 ; /* forget */
03497 
03498    if( cd == NULL && dynamic_flag && render_handle != NULL )
03499       REND_draw_CB(NULL,NULL,NULL) ;
03500 
03501    return ;
03502 }
03503 
03504 /*------------------------------------------------------------------------
03505   Event handler for Button #3 popup on xhair toggle -- 08 Mar 2001
03506 --------------------------------------------------------------------------*/
03507 
03508 void REND_xhair_EV( Widget w , XtPointer cd ,
03509                     XEvent * ev , Boolean * continue_to_dispatch )
03510 {
03511    switch( ev->type ){
03512       case ButtonPress:{
03513          XButtonEvent * event = (XButtonEvent *) ev ;
03514          if( event->button == Button3 || event->button == Button2 ){
03515 #if 0
03516             allow_MCW_optmenu_popup(0) ;
03517 #endif
03518             MCW_choose_ovcolor( w,dc , xhair_ovc , REND_xhair_ovc_CB,NULL ) ;
03519 #if 0
03520             allow_MCW_optmenu_popup(1) ;
03521 #endif
03522          }
03523       }
03524       break ;
03525    }
03526    return ;
03527 }
03528 
03529 /*-------------------------------------------------------------------------*/
03530 
03531 void REND_xhair_ovc_CB( Widget w , XtPointer cd , MCW_choose_cbs * cbs )
03532 {
03533    xhair_ovc = cbs->ival ;
03534    INVALIDATE_OVERLAY ; FREE_VOLUMES ;
03535 }
03536 
03537 /*-------------------------------------------------------------------------
03538   29 Mar 1999: called by AFNI when the user changes the crosshair location
03539   30 Mar 1999: or when the user draws into the controller image window
03540 ---------------------------------------------------------------------------*/
03541 
03542 void REND_xhair_recv( int why , int np , int * ijk , void * junk )
03543 {
03544    switch( why ){
03545 
03546       /*-- change of crosshair location --*/
03547 
03548       case RECEIVE_VIEWPOINT:{
03549          if( !xhair_flag || !dynamic_flag || render_handle == NULL ) return ;
03550 
03551          CHECK_XHAIR_ERROR ;
03552 
03553          if( CHECK_XHAIR_MOTION ){
03554             FREE_VOLUMES ;
03555             REND_draw_CB(NULL,NULL,NULL) ;
03556          }
03557       }
03558       return ;
03559 
03560       /*-- user drew something --*/
03561 
03562       case RECEIVE_DRAWNOTICE:{   /* 30 Mar 1999 */
03563          int doit=0 ;
03564 
03565          if( EQUIV_DSETS(im3d->anat_now,dset) ||    /* can't tell if user */
03566              EQUIV_DSETS(im3d->fim_now,dset)    ){  /* is drawing on anat */
03567 
03568             doit = 1 ; FREE_VOLUMES ;
03569 
03570          }
03571 
03572          if( EQUIV_DSETS(im3d->anat_now,func_dset) ||    /* or is drawing */
03573              EQUIV_DSETS(im3d->fim_now,func_dset)    ){  /* on the fim    */
03574 
03575             doit = 1 ; INVALIDATE_OVERLAY ;
03576 
03577             /* 15 Jun 1999: fix the range labels */
03578 
03579             { XmString xstr ;
03580               xstr = REND_range_label() ;
03581               XtVaSetValues( wfunc_range_label , XmNlabelString , xstr , NULL ) ;
03582               XmStringFree(xstr) ;
03583 
03584               xstr = REND_autorange_label() ;
03585               XtVaSetValues( wfunc_range_bbox->wbut[0], XmNlabelString,xstr , NULL ) ;
03586               XmStringFree(xstr) ;
03587             }
03588          }
03589 
03590          if( doit && dynamic_flag && render_handle != NULL )
03591             REND_draw_CB(NULL,NULL,NULL) ;
03592       }
03593       return ;
03594 
03595       /*-- dataset pointers have changed --*/
03596 
03597       case RECEIVE_DSETCHANGE:{   /* 31 Mar 1999 */
03598 
03599          if( dset != NULL )
03600             dset = PLUTO_find_dset( &dset_idc ) ;
03601 
03602          if( func_dset != NULL )
03603             func_dset = PLUTO_find_dset( &func_dset_idc ) ;
03604 
03605          FREE_VOLUMES ; INVALIDATE_OVERLAY ;
03606 
03607          (void) MCW_popup_message( reload_pb ,
03608                                      "********** NOTICE ***********\n"
03609                                      "* Session rescan has forced *\n"
03610                                      "* purge of dataset brick(s) *\n"
03611                                      "* from memory.              *\n"
03612                                      "*****************************" ,
03613                                    MCW_USER_KILL | MCW_TIMER_KILL     ) ;
03614       }
03615       return ;
03616 
03617    }  /* end of switch on "why" */
03618 
03619    return ;
03620 }
03621 
03622 /*-------------------------------------------------------------------------
03623    callbacks for other toggle buttons
03624 ---------------------------------------------------------------------------*/
03625 
03626 void REND_dynamic_CB( Widget w , XtPointer client_data , XtPointer call_data )
03627 {
03628    dynamic_flag = MCW_val_bbox( dynamic_bbox ) ;
03629    return ;
03630 }
03631 
03632 void REND_accum_CB( Widget w , XtPointer client_data , XtPointer call_data )
03633 {
03634    accum_flag = MCW_val_bbox( accum_bbox ) ;
03635    return ;
03636 }
03637 
03638 /*-----------------------------------------------------------------------
03639    Overlay some white lines showing the crosshair location.
03640    Note that this function assumes that the current anat dataset
03641    in AFNI is defined on exactly the same grid as the rendering dataset.
03642 -------------------------------------------------------------------------*/
03643 
03644 #define GR(i,j,k) gar[(i)+(j)*nx+(k)*nxy]
03645 #define OP(i,j,k) oar[(i)+(j)*nx+(k)*nxy]
03646 
03647 #define GXH_GRAY  255
03648 #define GXH_COLOR 127
03649 #define OXH       255
03650 
03651 void REND_xhair_underlay(void)
03652 {
03653    int ix,jy,kz , nx,ny,nz,nxy , ii , gap , om ;
03654    byte * gar , * oar ;
03655    byte   gxh ,   oxh=OXH ;
03656 
03657    if( grim == NULL || opim == NULL ) return ;  /* error */
03658 
03659    if( xhair_ovc > 0 && DO_OVERLAY ) return ;   /* 08 Mar 2001 */
03660 
03661    gxh = (func_computed) ? GXH_COLOR : GXH_GRAY ;
03662 
03663    CHECK_XHAIR_ERROR ;
03664 
03665    ix = im3d->vinfo->i1 ; nx = grim->nx ;
03666    jy = im3d->vinfo->j2 ; ny = grim->ny ; nxy = nx * ny ;
03667    kz = im3d->vinfo->k3 ; nz = grim->nz ;
03668 
03669    om = im3d->vinfo->xhairs_orimask ;  /* 02 Jun 1999 */
03670 
03671    if( ix < 0 || ix >= nx ) return ;  /* error */
03672    if( jy < 0 || jy >= ny ) return ;  /* error */
03673    if( kz < 0 || kz >= nz ) return ;  /* error */
03674 
03675    gap = im3d->vinfo->crosshair_gap ;
03676    gar = MRI_BYTE_PTR(grim) ;
03677    oar = MRI_BYTE_PTR(opim) ;
03678 
03679    /* 02 Jun 1999: allow for partial crosshair drawing */
03680 
03681    if( (om & ORIMASK_LR) != 0 ){
03682       for( ii=0 ; ii < nx ; ii++ ){
03683          if( abs(ii-ix) > gap ){ GR(ii,jy,kz) = gxh ; OP(ii,jy,kz) = oxh ; }
03684       }
03685    }
03686 
03687    if( (om & ORIMASK_AP) != 0 ){
03688       for( ii=0 ; ii < ny ; ii++ ){
03689          if( abs(ii-jy) > gap ){ GR(ix,ii,kz) = gxh ; OP(ix,ii,kz) = oxh ; }
03690       }
03691    }
03692 
03693    if( (om & ORIMASK_IS) != 0 ){
03694       for( ii=0 ; ii < nz ; ii++ ){
03695          if( abs(ii-kz) > gap ){ GR(ix,jy,ii) = gxh ; OP(ix,jy,ii) = oxh ; }
03696       }
03697    }
03698 
03699    xhair_ixold = ix ; xhair_jyold = jy ; xhair_kzold = kz ;  /* memory */
03700    xhair_omold = om ;                                        /* 02 Jun 1999 */
03701    return ;
03702 }
03703 
03704 /*------------------------------------------------------------------
03705    Called when the user changes a graph - just signals that we
03706    need to reload the data.
03707 --------------------------------------------------------------------*/
03708 
03709 void REND_graf_CB( MCW_graf * gp , void * cd )
03710 {
03711    FREE_VOLUMES ;  /* free the volumes, will force reloading at redraw */
03712    return ;
03713 }
03714 
03715 /*-------------------------------------------------------------------
03716   Callback for clipping arrowvals
03717 ---------------------------------------------------------------------*/
03718 
03719 void REND_clip_CB( MCW_arrowval * av , XtPointer cd )
03720 {
03721    FREE_VOLUMES ;  /* free the volumes, will force reloading */
03722 
03723    if( clipbot_av->ival >= cliptop_av->ival ){
03724       if( av == clipbot_av )
03725          AV_assign_ival( clipbot_av , cliptop_av->ival - 1 ) ;
03726       else
03727          AV_assign_ival( cliptop_av , clipbot_av->ival + 1 ) ;
03728    }
03729 
03730    /* if brick is scaled, re-show the scaled labels */
03731 
03732    if( brickfac != 0.0 && brickfac != 1.0 ){
03733       char minch[16] , maxch[16] , str[64] ;
03734       XmString xstr ;
03735 
03736       if( av == clipbot_av ){
03737          AV_fval_to_char( brickfac * clipbot_av->ival , minch ) ;
03738          sprintf(str,"[-> %s]",minch) ;
03739          xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
03740          XtVaSetValues( clipbot_faclab , XmNlabelString , xstr , NULL ) ;
03741          XmStringFree(xstr) ;
03742       } else {
03743          AV_fval_to_char( brickfac * cliptop_av->ival , maxch ) ;
03744          sprintf(str,"[-> %s]",maxch) ;
03745          xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
03746          XtVaSetValues( cliptop_faclab , XmNlabelString , xstr , NULL ) ;
03747          XmStringFree(xstr) ;
03748       }
03749    }
03750 
03751    return ;
03752 }
03753 
03754 /*-------------------------------------------------------------------
03755   Callback for cutout type optmenu
03756   -- change the appearance of the widgets that follow it
03757 ---------------------------------------------------------------------*/
03758 
03759 void REND_cutout_type_CB( MCW_arrowval * av , XtPointer cd )
03760 {
03761    int iv , val ;
03762    XmString xstr ;
03763    Boolean sens ;
03764 
03765    for( iv=0 ; iv < num_cutouts ; iv++ )
03766       if( av == cutouts[iv]->type_av ) break ;
03767    if( iv == num_cutouts ) return ;
03768 
03769    val = av->ival ;           /* new type */
03770 
03771    HIDE_SCALE ;
03772 
03773    if( val == CUT_NONE ){
03774       XtUnmanageChild( cutouts[iv]->param_lab ) ;
03775       XtUnmanageChild( cutouts[iv]->param_av->wrowcol ) ;
03776       XtUnmanageChild( cutouts[iv]->set_pb ) ;
03777       XtUnmanageChild( cutouts[iv]->mustdo_bbox->wrowcol ) ;
03778    } else {
03779       xstr = XmStringCreateLtoR( cutout_param_labels[val], XmFONTLIST_DEFAULT_TAG ) ;
03780       XtVaSetValues( cutouts[iv]->param_lab , XmNlabelString , xstr , NULL ) ;
03781       XmStringFree(xstr) ;
03782 
03783       XtManageChild( cutouts[iv]->param_lab ) ;
03784       XtManageChild( cutouts[iv]->param_av->wrowcol ) ;
03785       XtManageChild( cutouts[iv]->set_pb ) ;
03786       XtManageChild( cutouts[iv]->mustdo_bbox->wrowcol ) ;
03787 
03788 #undef DESENS
03789 #ifdef DESENS
03790       sens = (val != CUT_EXPRESSION) ;                    /* deactivate */
03791       XtSetSensitive(cutouts[iv]->param_av->wup  ,sens) ; /* if is an   */
03792       XtSetSensitive(cutouts[iv]->param_av->wdown,sens) ; /* Expr > 0   */
03793       XtSetSensitive(cutouts[iv]->set_pb         ,sens) ; /* cutout     */
03794 #else
03795       if( val == CUT_EXPRESSION ){                        /* if Expr > 0 */
03796          XtUnmanageChild( cutouts[iv]->param_av->wup   ); /* expand the  */
03797          XtUnmanageChild( cutouts[iv]->param_av->wdown ); /* size of the */
03798          XtUnmanageChild( cutouts[iv]->set_pb          ); /* text field  */
03799          XtVaSetValues( cutouts[iv]->param_av->wtext ,
03800                            XmNcolumns , AV_NCOL + 9 ,
03801                         NULL ) ;
03802       } else {                                          /* shrink size   */
03803          XtVaSetValues( cutouts[iv]->param_av->wtext ,  /* of text field */
03804                            XmNcolumns , AV_NCOL ,       /* to normal for */
03805                         NULL ) ;                        /* other cutouts */
03806          XtManageChild( cutouts[iv]->param_av->wup   );
03807          XtManageChild( cutouts[iv]->param_av->wdown );
03808          XtManageChild( cutouts[iv]->set_pb          );
03809       }
03810 #endif
03811    }
03812 
03813    FIX_SCALE_SIZE ;
03814    return ;
03815 }
03816 
03817 /*-------------------------------------------------------------------
03818   Callback for cutout number optmenu
03819 ---------------------------------------------------------------------*/
03820 
03821 void REND_numcutout_CB( MCW_arrowval * av , XtPointer cd )
03822 {
03823    int ii ;
03824    num_cutouts = av->ival ;
03825 
03826    HIDE_SCALE ;
03827 
03828    for( ii=0 ; ii < MAX_CUTOUTS ; ii++ ){
03829       if( ii < num_cutouts )
03830          XtManageChild( cutouts[ii]->hrc ) ;
03831       else
03832          XtUnmanageChild( cutouts[ii]->hrc ) ;
03833    }
03834 
03835    FIX_SCALE_SIZE ;
03836    return ;
03837 }
03838 
03839 /*---------------------------------------------------------------------
03840    Routines to load and compare cutout states
03841 -----------------------------------------------------------------------*/
03842 
03843 void REND_load_cutout_state(void)
03844 {
03845    int ii ;
03846    char * str ;
03847 
03848    current_cutout_state.num   = num_cutouts ;
03849    current_cutout_state.logic = logic_cutout = logiccutout_av->ival ;
03850 
03851    for( ii=0 ; ii < MAX_CUTOUTS ; ii++ ){
03852       current_cutout_state.type[ii]   = cutouts[ii]->type_av->ival ;
03853       current_cutout_state.mustdo[ii] = MCW_val_bbox( cutouts[ii]->mustdo_bbox ) ;
03854       current_cutout_state.param[ii]  = REND_evaluate( cutouts[ii]->param_av ) ;
03855 
03856       if( current_cutout_state.type[ii] == CUT_EXPRESSION ){
03857          str = XmTextFieldGetString( cutouts[ii]->param_av->wtext ) ;
03858          strcpy( current_cutout_state.param_str[ii] , str ) ;
03859          XtFree(str) ;
03860       } else {
03861          current_cutout_state.param_str[ii][0] = '\0' ;
03862       }
03863    }
03864 
03865    current_cutout_state.opacity_scale = REND_evaluate( opacity_scale_av ) ;
03866    current_cutout_state.opacity_scale = MAX( MIN_OPACITY_SCALE ,
03867                                              current_cutout_state.opacity_scale ) ;
03868    current_cutout_state.opacity_scale = MIN( 1.000 ,
03869                                              current_cutout_state.opacity_scale ) ;
03870    return ;
03871 }
03872 
03873 int REND_cutout_state_changed(void)
03874 {
03875    int ii ;
03876 
03877    if( current_cutout_state.opacity_scale != old_cutout_state.opacity_scale ) return 1;
03878 
03879    if( current_cutout_state.num != old_cutout_state.num ) return 1 ;
03880    if( current_cutout_state.num == 0                    ) return 0 ;
03881 
03882    if( current_cutout_state.num > 1 &&
03883        (current_cutout_state.logic != old_cutout_state.logic) ) return 1 ;
03884 
03885    for( ii=0 ; ii < current_cutout_state.num ; ii++ ){
03886       if( current_cutout_state.type[ii] != old_cutout_state.type[ii] ) return 1 ;
03887 
03888       if( current_cutout_state.type[ii] == CUT_NONE ) continue ;
03889 
03890       switch( current_cutout_state.type[ii] ){
03891          default :
03892           if( current_cutout_state.param[ii] != old_cutout_state.param[ii] ) return 1;
03893          break ;
03894 
03895          case CUT_EXPRESSION:
03896           if( strcmp( current_cutout_state.param_str[ii] ,
03897                       old_cutout_state.param_str[ii]      ) != 0 ) return 1 ;
03898 
03899           if( automate_flag &&
03900               strchr(current_cutout_state.param_str[ii],'t') != NULL ) return 1 ;
03901          break ;
03902       }
03903 
03904       if( current_cutout_state.logic != CUTOUT_OR &&
03905           current_cutout_state.num   >  1         &&
03906           current_cutout_state.mustdo[ii] != old_cutout_state.mustdo[ii] ) return 1 ;
03907    }
03908 
03909    return 0 ;
03910 }
03911 
03912 /*-------------------------------------------------------------------------------
03913    When the user presses a cutout "Get" button
03914 ---------------------------------------------------------------------------------*/
03915 
03916 #define TT_XMID   0.0   /* centroid */
03917 #define TT_YMID  16.0
03918 #define TT_ZMID   5.0
03919 
03920 #define TT_XSEMI 68.0   /* semi-axes */
03921 #define TT_YSEMI 86.0
03922 #define TT_ZSEMI 69.0
03923 
03924 void REND_cutout_set_CB( Widget w, XtPointer client_data, XtPointer call_data )
03925 {
03926    int iv , typ ;
03927    float val ;
03928    char str[16] ;
03929 
03930    for( iv=0 ; iv < num_cutouts ; iv++ )
03931       if( w == cutouts[iv]->set_pb ) break ;
03932    if( iv == num_cutouts ) return ;
03933 
03934    typ = cutouts[iv]->type_av->ival ;
03935    switch( typ ){
03936 
03937       default: XBell(dc->display,100) ; return ;  /* action is not defined */
03938 
03939       case CUT_RIGHT_OF:
03940       case CUT_LEFT_OF:      val = im3d->vinfo->xi ; break ;
03941 
03942       case CUT_ANTERIOR_TO:
03943       case CUT_POSTERIOR_TO: val = im3d->vinfo->yj ; break ;
03944 
03945       case CUT_INFERIOR_TO:
03946       case CUT_SUPERIOR_TO:  val = im3d->vinfo->zk ; break ;
03947 
03948       case CUT_TT_ELLIPSOID:{
03949          float x = im3d->vinfo->xi , y = im3d->vinfo->yj , z = im3d->vinfo->zk  ;
03950 
03951          val =  (x-TT_XMID) * (x-TT_XMID) / (TT_XSEMI * TT_XSEMI)
03952               + (y-TT_YMID) * (y-TT_YMID) / (TT_YSEMI * TT_YSEMI)
03953               + (z-TT_ZMID) * (z-TT_ZMID) / (TT_ZSEMI * TT_ZSEMI) ;
03954 
03955          val = 0.1 * rint( 1000.0 * sqrt(val) ) ;  /* round to 1 decimal place */
03956       } break ;
03957 
03958       case CUT_SLANT_XPY_GT:
03959       case CUT_SLANT_XPY_LT:
03960       case CUT_SLANT_XMY_GT:
03961       case CUT_SLANT_XMY_LT:
03962       case CUT_SLANT_YPZ_GT:
03963       case CUT_SLANT_YPZ_LT:
03964       case CUT_SLANT_YMZ_GT:
03965       case CUT_SLANT_YMZ_LT:
03966       case CUT_SLANT_XPZ_GT:
03967       case CUT_SLANT_XPZ_LT:
03968       case CUT_SLANT_XMZ_GT:
03969       case CUT_SLANT_XMZ_LT:{
03970          float x = im3d->vinfo->xi , y = im3d->vinfo->yj , z = im3d->vinfo->zk  ;
03971          int isl = typ - CUT_SLANT_BASE ;
03972 
03973          val =   cut_slant_normals[isl][0] * x
03974                + cut_slant_normals[isl][1] * y
03975                + cut_slant_normals[isl][2] * z ;
03976 
03977          val = 0.1 * rint( 10.0 * val ) ;  /* round to 0.1 mm */
03978       }
03979       break ;
03980    }
03981 
03982    AV_assign_fval( cutouts[iv]->param_av , val ) ;
03983 
03984    if( dynamic_flag && render_handle != NULL ) REND_draw_CB(NULL,NULL,NULL) ;
03985    return ;
03986 }
03987 
03988 /*--------------------------------------------------------------------
03989    Actually do the cutouts in the opacity brick
03990    11 Jan 2000: modified to pass opacity image in, rather
03991                 than use the global opim
03992 ----------------------------------------------------------------------*/
03993 
03994 void REND_cutout_blobs( MRI_IMAGE * oppim )
03995 {
03996    int ii,jj,kk , nx,ny,nz,nxy,nxyz , cc , typ , ncc,logic,nmust,nand,mus ;
03997    int ibot,itop , jbot,jtop , kbot,ktop ;
03998    float par ;
03999    float dx,dy,dz , xorg,yorg,zorg , xx,yy,zz ;
04000    byte * oar , * gar ;
04001    byte ncdone = 0 ;
04002 
04003    ncc   = current_cutout_state.num ;
04004    logic = current_cutout_state.logic ;
04005    if( ncc < 1 || oppim == NULL ) return ;      /* error */
04006 
04007    /* find out if the logic is effectively "OR" */
04008 
04009    if( ncc == 1 ){
04010       logic = CUTOUT_OR ;
04011    } else {
04012       for( nmust=cc=0 ; cc < ncc ; cc++ )
04013          if( current_cutout_state.mustdo[cc] ) nmust++ ;
04014       if( nmust >= ncc-1 ) logic = CUTOUT_OR ;
04015    }
04016 
04017    /* initialize */
04018 
04019    oar = MRI_BYTE_PTR(oppim) ; if( oar == NULL ) return ;
04020    nx  = oppim->nx ;
04021    ny  = oppim->ny ; nxy  = nx * ny ;
04022    nz  = oppim->nz ; nxyz = nxy * nz ;
04023 
04024    if( logic == CUTOUT_AND ){
04025       gar = (byte *) malloc( sizeof(byte) * nxyz ) ;  /* counts of hits */
04026       memset( gar , 0 , sizeof(byte) * nxyz ) ;
04027    }
04028 
04029    dx   = dset->daxes->xxdel; dy   = dset->daxes->yydel; dz   = dset->daxes->zzdel;
04030    xorg = dset->daxes->xxorg; yorg = dset->daxes->yyorg; zorg = dset->daxes->zzorg;
04031 
04032    for( cc=0 ; cc < ncc ; cc++ ){              /* loop over cutouts */
04033       typ = current_cutout_state.type[cc] ;
04034       mus = current_cutout_state.mustdo[cc] ;
04035       par = current_cutout_state.param[cc] ;
04036       if( typ == CUT_NONE ) continue ;         /* error */
04037 
04038       switch( typ ){
04039 
04040          /*............................................................*/
04041 
04042          case CUT_RIGHT_OF:
04043          case CUT_LEFT_OF:
04044          case CUT_ANTERIOR_TO:
04045          case CUT_POSTERIOR_TO:
04046          case CUT_INFERIOR_TO:
04047          case CUT_SUPERIOR_TO:{         /* a rectangular region */
04048            int q ;
04049 
04050            ibot = 0 ; itop = nx-1 ;     /* everything */
04051            jbot = 0 ; jtop = ny-1 ;
04052            kbot = 0 ; ktop = nz-1 ;
04053            switch( typ ){
04054               case CUT_RIGHT_OF:
04055                  q = (int)( (par-xorg)/dx - 0.499 ); RANGE(q,0,itop); itop = q;
04056               break ;
04057               case CUT_LEFT_OF:
04058                  q = (int)( (par-xorg)/dx + 1.499 ); RANGE(q,0,itop); ibot = q;
04059               break ;
04060               case CUT_ANTERIOR_TO:
04061                  q = (int)( (par-yorg)/dy - 0.499 ); RANGE(q,0,jtop); jtop = q;
04062               break ;
04063               case CUT_POSTERIOR_TO:
04064                  q = (int)( (par-yorg)/dy + 1.499 ); RANGE(q,0,jtop); jbot = q;
04065               break ;
04066               case CUT_INFERIOR_TO:
04067                  q = (int)( (par-zorg)/dz - 0.499 ); RANGE(q,0,ktop); ktop = q;
04068               break ;
04069               case CUT_SUPERIOR_TO:
04070                  q = (int)( (par-zorg)/dz + 1.499 ); RANGE(q,0,ktop); kbot = q;
04071               break ;
04072            }
04073 
04074            if( logic == CUTOUT_AND && ! mus ){        /* count hits */
04075               ncdone++ ;
04076               for( kk=kbot ; kk <= ktop ; kk++ )
04077                  for( jj=jbot ; jj <= jtop ; jj++ )
04078                     for( ii=ibot ; ii <= itop ; ii++ ) GR(ii,jj,kk)++ ;
04079 
04080            } else {                                   /* just blast it */
04081               for( kk=kbot ; kk <= ktop ; kk++ )
04082                  for( jj=jbot ; jj <= jtop ; jj++ )
04083                     for( ii=ibot ; ii <= itop ; ii++ ) OP(ii,jj,kk) = 0 ;
04084            }
04085          }
04086          break ;  /* end of rectangular region cutout */
04087 
04088          /*............................................................*/
04089 
04090          case CUT_TT_ELLIPSOID:{                 /* an ellipsoid */
04091 
04092            float dxa=dx/TT_XSEMI  , dya=dy/TT_YSEMI  , dza=dz/TT_ZSEMI   ;
04093            float xga=(xorg-TT_XMID)/TT_XSEMI ,
04094                  yga=(yorg-TT_YMID)/TT_YSEMI ,
04095                  zga=(zorg-TT_ZMID)/TT_ZSEMI , ebot=0.0001*par*par ;
04096 
04097            if( logic == CUTOUT_AND && ! mus ){        /* count hits */
04098               ncdone++ ;
04099               for( kk=0 ; kk < nz ; kk++ ){
04100                 zz = zga + kk*dza ; zz = zz*zz ;
04101                 for( jj=0 ; jj < ny ; jj++ ){
04102                   yy = yga + jj*dya ; yy = yy*yy + zz ;
04103                   if( yy < ebot ){
04104                     for( ii=0 ; ii < nx ; ii++ ){
04105                       xx = xga + ii*dxa ; xx = xx*xx + yy ;
04106                       if( xx > ebot ) GR(ii,jj,kk)++ ;
04107                     }
04108                   } else {
04109                     for( ii=0 ; ii < nx ; ii++ ) GR(ii,jj,kk)++ ;
04110                   }
04111               }}
04112 
04113            } else {                                   /* blast it */
04114               for( kk=0 ; kk < nz ; kk++ ){
04115                 zz = zga + kk*dza ; zz = zz*zz ;
04116                 for( jj=0 ; jj < ny ; jj++ ){
04117                   yy = yga + jj*dya ; yy = yy*yy + zz ;
04118                   if( yy < ebot ){
04119                     for( ii=0 ; ii < nx ; ii++ ){
04120                       xx = xga + ii*dxa ; xx = xx*xx + yy ;
04121                       if( xx > ebot ) OP(ii,jj,kk) = 0 ;
04122                     }
04123                   } else {
04124                     for( ii=0 ; ii < nx ; ii++ ) OP(ii,jj,kk) = 0 ;
04125                   }
04126               }}
04127            }
04128          }
04129          break ;  /* end of ellipsoid cutout */
04130 
04131          /*............................................................*/
04132 
04133 #define VSIZE nx
04134          case CUT_EXPRESSION:{      /* expression > 0 */
04135             PARSER_code * pcode ;
04136             double * abc[26] , * temp ;
04137 
04138             /* parse the expression */
04139 
04140             pcode = PARSER_generate_code( current_cutout_state.param_str[cc] ) ;
04141             if( pcode == NULL ) break ;  /* skip this cutout */
04142 
04143             /* create the evaluation workspaces */
04144 
04145             temp = (double *) malloc( sizeof(double) * VSIZE ) ;
04146             for( jj=0 ; jj < 26 ; jj++ )
04147                abc[jj] = (double *) malloc( sizeof(double) * VSIZE ) ;
04148 
04149             for( jj=0 ; jj < 23 ; jj++ )       /* load zeros for */
04150                for( ii=0 ; ii < VSIZE; ii++ )  /* 'a' ... 'w'    */
04151                   abc[jj][ii] = 0.0 ;
04152 
04153             for( ii=0 ; ii < VSIZE ; ii++ ){   /* load 't' and 'n' */
04154                abc[N_IND][ii] = atoz[N_IND] ;
04155                abc[T_IND][ii] = atoz[T_IND] ;
04156             }
04157 
04158             /* loop over rows of voxels and evaluate expressions */
04159 
04160             for( kk=0 ; kk < nz ; kk++ ){
04161               zz = zorg + kk*dz ;
04162               for( jj=0 ; jj < ny ; jj++ ){
04163                 yy = yorg + jj*dy ;
04164 
04165                 for( ii=0 ; ii < nx ; ii++ ){      /* load row */
04166                    abc[X_IND][ii] = xorg + ii*dx ;
04167                    abc[Y_IND][ii] = yy ;
04168                    abc[Z_IND][ii] = zz ;
04169                 }
04170 
04171                 /* evaluate the expression */
04172 
04173                 PARSER_evaluate_vector(pcode, abc, VSIZE, temp);
04174 
04175                 /* cut cut cut */
04176 
04177                 if( logic == CUTOUT_AND && ! mus ){        /* count hits */
04178                    for( ii=0 ; ii < nx ; ii++ )
04179                      if( temp[ii] > 0.0 ) GR(ii,jj,kk)++ ;
04180 
04181                 } else {                                   /* blast'em */
04182                    for( ii=0 ; ii < nx ; ii++ )
04183                      if( temp[ii] > 0.0 ) OP(ii,jj,kk) = 0 ;
04184                 }
04185             }} /* end of loops over jj,kk (y,z) */
04186 
04187             if( logic == CUTOUT_AND && ! mus ) ncdone++ ;
04188 
04189             /* free workspaces */
04190 
04191             for( jj=0 ; jj < 26 ; jj++ ) free(abc[jj]) ;
04192             free(temp) ; free(pcode) ;
04193          }
04194          break ;  /* end of expression cutout */
04195 
04196          /*............................................................*/
04197 
04198          case CUT_SLANT_XPY_GT:   /* the slanted cut planes */
04199          case CUT_SLANT_XPY_LT:
04200          case CUT_SLANT_XMY_GT:
04201          case CUT_SLANT_XMY_LT:
04202          case CUT_SLANT_YPZ_GT:
04203          case CUT_SLANT_YPZ_LT:
04204          case CUT_SLANT_YMZ_GT:
04205          case CUT_SLANT_YMZ_LT:
04206          case CUT_SLANT_XPZ_GT:
04207          case CUT_SLANT_XPZ_LT:
04208          case CUT_SLANT_XMZ_GT:
04209          case CUT_SLANT_XMZ_LT:{
04210             int isl = typ - CUT_SLANT_BASE ;
04211             float xn = cut_slant_normals[isl][0] , dxn = dx * xn ,
04212                   yn = cut_slant_normals[isl][1] , dyn = dy * yn ,
04213                   zn = cut_slant_normals[isl][2] , dzn = dz * zn , pval ;
04214 
04215             pval = par - xn*xorg - yn*yorg - zn*zorg ;
04216 
04217             if( logic == CUTOUT_AND && ! mus ){        /* count hits */
04218               ncdone++ ;
04219               for( kk=0,zz=-pval ; kk < nz ; kk++,zz+=dzn ){
04220                 /* zz = kk * dzn - pval ; */
04221                 for( jj=0,yy=zz ; jj < ny ; jj++,yy+=dyn ){
04222                   /* yy = jj * dyn + zz ; */
04223                   for( ii=0,xx=yy ; ii < nx ; ii++,xx+=dxn ){
04224                     /* xx = ii * dxn + yy ; */
04225                     if( xx > 0.0 ) GR(ii,jj,kk)++ ;
04226                   }
04227               }}
04228             } else {                                   /* blast it */
04229               for( kk=0,zz=-pval ; kk < nz ; kk++,zz+=dzn ){
04230                 /* zz = kk * dzn - pval ; */
04231                 for( jj=0,yy=zz ; jj < ny ; jj++,yy+=dyn ){
04232                   /* yy = jj * dyn + zz ; */
04233                   for( ii=0,xx=yy ; ii < nx ; ii++,xx+=dxn ){
04234                     /* xx = ii * dxn + yy ; */
04235                     if( xx > 0.0 ) OP(ii,jj,kk) = 0 ;
04236                   }
04237               }}
04238             }
04239          }
04240          break ;  /* end of slant cutout */
04241 
04242          /*............................................................*/
04243 
04244 #define OVAR(i,j,k) ovar[(i)+(j)*nx+(k)*nxy]
04245 #define KEEP(i,j,k) keep[(i)+(j)*nx+(k)*nxy]
04246 
04247          case CUT_NONOVERLAY:
04248          if( DO_OVERLAY ){  /* 24 Jul 2001: changed condition from func_dset != NULL */
04249             byte * ovar ;
04250             float adx=fabs(dx) , ady=fabs(dy) , adz=fabs(dz) ;
04251 
04252             if( ovim == NULL ) REND_reload_func_dset() ; /* get the global */
04253             ovar = MRI_BYTE_PTR(ovim) ;                  /* overlay image */
04254 
04255             if( par < adx && par < ady && par < adz ){   /* no dilation */
04256 
04257               if( logic == CUTOUT_AND && ! mus ){        /* count hits */
04258                 ncdone++ ;
04259                 for( ii=0 ; ii < nxyz ; ii++ )
04260                    if( ovar[ii] == 0 ) gar[ii]++ ;
04261               } else {                                   /* nuke'em */
04262                 for( ii=0 ; ii < nxyz ; ii++ )
04263                    if( ovar[ii] == 0 ) oar[ii] = 0 ;
04264               }
04265 
04266             } else {                                     /* dilation */
04267 
04268               MCW_cluster * mask = MCW_build_mask( nx,ny,nz, adx,ady,adz, par ) ;
04269               int mnum = mask->num_pt , pp,ip,jp,kp ;
04270               short * mi = mask->i , * mj = mask->j , * mk = mask->k ;
04271               byte * keep = calloc(nxyz,sizeof(byte)) ;
04272 
04273               for( kk=0 ; kk < nz ; kk++ )       /* make list of points to keep */
04274                 for( jj=0 ; jj < ny ; jj++ )
04275                   for( ii=0 ; ii < nx ; ii++ )
04276                      if( OVAR(ii,jj,kk) != 0 ){  /* keep nbhd of this point */
04277                         KEEP(ii,jj,kk) = 1 ;
04278                         for( pp=0 ; pp < mnum ; pp++ ){
04279                            ip = ii + mi[pp]; jp = jj + mj[pp]; kp = kk + mk[pp];
04280                            if( ip >= 0 && ip < nx &&
04281                                jp >= 0 && jp < ny &&
04282                                kp >= 0 && kp < nz   ) KEEP(ip,jp,kp) = 1 ;
04283                         }
04284                      }
04285               KILL_CLUSTER(mask) ;  /* toss the trash */
04286 
04287               /* now do the cutting */
04288 
04289               if( logic == CUTOUT_AND && ! mus ){        /* count hits */
04290                 ncdone++ ;
04291                 for( ii=0 ; ii < nxyz ; ii++ )
04292                    if( keep[ii] == 0 ) gar[ii]++ ;
04293               } else {                                   /* nuke'em */
04294                 for( ii=0 ; ii < nxyz ; ii++ )
04295                    if( keep[ii] == 0 ) oar[ii] = 0 ;
04296               }
04297 
04298               free(keep) ;  /* toss the trash */
04299             }
04300          }
04301          break ;  /* end of nonoverlay cutout */
04302 
04303       } /* end of switch over type of cutout */
04304    } /* end of loop over cutouts */
04305 
04306    /* with AND, blast only those that were hit every time */
04307 
04308    if( logic == CUTOUT_AND && ncdone > 0 ){
04309       for( ii=0 ; ii < nxyz ; ii++ ) if( gar[ii] == ncdone ) oar[ii] = 0 ;
04310       free(gar) ;
04311    }
04312 
04313    return ;
04314 }
04315 
04316 /*-----------------------------------------------------------------------
04317    Callback for cutout parameter arrowval
04318    -- only action is to redraw if dynamic mode is on
04319 -------------------------------------------------------------------------*/
04320 
04321 void REND_param_CB( MCW_arrowval * av , XtPointer cd )
04322 {
04323    if( cd == NULL && dynamic_flag && render_handle != NULL )
04324       REND_draw_CB(NULL,NULL,NULL) ;
04325 }
04326 
04327 /*-----------------------------------------------------------------------
04328    Evaluate an arrowval string that may be a number or may be
04329    a more complicated arithmetic expression.  Input variables are
04330    stored in the global array atoz[] ;
04331 -------------------------------------------------------------------------*/
04332 
04333 float REND_evaluate( MCW_arrowval * av )
04334 {
04335    PARSER_code * pcode ;
04336    char * str , * cpt ;
04337    float val ;
04338 
04339    /* get the string to convert */
04340 
04341    if( av        == NULL ) return 0.0 ;        /* these cases should */
04342    if( av->wtext == NULL ) return av->fval ;   /* never happen       */
04343 
04344    str = XmTextFieldGetString( av->wtext ) ;
04345    if( str == NULL || str[0] == '\0' ){ XtFree(str) ; return 0.0 ; }
04346 
04347    /* try a regular numerical conversion */
04348 
04349    val = strtod( str , &cpt ) ;
04350 
04351    for( ; *cpt != '\0' && isspace(*cpt) ; cpt++ ) ; /* skip blanks */
04352 
04353    if( *cpt == '\0' ){ XtFree(str); AV_assign_fval(av,val); return val; }
04354 
04355    /* try to parse an expression */
04356 
04357    pcode = PARSER_generate_code( str ) ;
04358    if( pcode == NULL ){ XtFree(str) ; return 0.0 ; }
04359 
04360    val = PARSER_evaluate_one( pcode , atoz ) ; free(pcode) ;
04361 
04362    XtFree(str) ; return val ;
04363 }
04364 
04365 /*-------------------------------------------------------------------------
04366    When the user presses Enter in a textfield that might have an
04367    expression entered, evaluate the expression numerically and
04368    load that number back into the textfield.
04369 ---------------------------------------------------------------------------*/
04370 
04371 void REND_textact_CB( Widget wtex, XtPointer client_data, XtPointer call_data )
04372 {
04373    MCW_arrowval * av         = (MCW_arrowval *) client_data ;
04374    XmAnyCallbackStruct * cbs = (XmAnyCallbackStruct *) call_data ;
04375    float sval ;
04376    int iv ;
04377 
04378    for( iv=0 ; iv < num_cutouts ; iv++ )  /* skip if is an Expr > 0 cutout */
04379       if( av == cutouts[iv]->param_av &&
04380           cutouts[iv]->type_av->ival == CUT_EXPRESSION ) return ;
04381 
04382    MCW_invert_widget(wtex) ;
04383 
04384    sval = REND_evaluate( av ) ;
04385    AV_assign_fval( av , sval ) ;
04386 
04387    MCW_invert_widget(wtex) ;
04388    return ;
04389 }
04390 
04391 /**********************************************************************
04392    Stuff to deal with the image display window
04393 ***********************************************************************/
04394 
04395 /*-----------------------------------------------------------------------
04396    Open an image display window.
04397 -------------------------------------------------------------------------*/
04398 
04399 static int any_rgb_images ;
04400 
04401 void REND_open_imseq( void )
04402 {
04403    int ntot , ii ;
04404 
04405    if( imseq != NULL      ||
04406        renderings == NULL || IMARR_COUNT(renderings) == 0 ) return ;
04407 
04408    ntot = IMARR_COUNT(renderings) ;
04409 
04410    any_rgb_images = 0 ;
04411    for( ii=0 ; ii < ntot ; ii++ ){
04412       if( IMARR_SUBIMAGE(renderings,ii) != NULL &&
04413           IMARR_SUBIMAGE(renderings,ii)->kind == MRI_rgb ){
04414 
04415          any_rgb_images = 1 ; break ;
04416       }
04417    }
04418 
04419    imseq = open_MCW_imseq( dc , REND_imseq_getim , NULL ) ;
04420 
04421    drive_MCW_imseq( imseq , isqDR_clearstat , NULL ) ;
04422 
04423    { ISQ_options opt ;       /* change some options from the defaults */
04424 
04425      ISQ_DEFAULT_OPT(opt) ;
04426      opt.save_one = False ;  /* change to Save:bkg */
04427      opt.save_pnm = False ;
04428      opt.save_filter = -1 ;  /* 27 Jun 2001 */
04429      drive_MCW_imseq( imseq , isqDR_options      , (XtPointer) &opt ) ;
04430      drive_MCW_imseq( imseq , isqDR_periodicmont , (XtPointer) 0    ) ;
04431    }
04432 
04433    /* make it popup */
04434 
04435    drive_MCW_imseq( imseq , isqDR_realize, NULL ) ;
04436 
04437    NORMAL_cursorize( imseq->wimage ) ; /* 07 Dec 2001 */
04438 
04439    drive_MCW_imseq( imseq , isqDR_title, "AFNI Renderings" ) ;
04440 
04441    if( ntot == 1 )
04442       drive_MCW_imseq( imseq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
04443    else {
04444       drive_MCW_imseq( imseq , isqDR_onoffwid , (XtPointer) isqDR_onwid ) ;
04445       drive_MCW_imseq( imseq , isqDR_penbbox  , (XtPointer) 0 ) ; /* 18 Jul 2003 */
04446 #if 0
04447       drive_MCW_imseq( imseq , isqDR_opacitybut , (XtPointer) 0 ) ; /* 07 Mar 2001 */
04448       drive_MCW_imseq( imseq , isqDR_zoombut , (XtPointer) 0 ) ; /* 12 Mar 2002 */
04449 #endif
04450    }
04451 
04452    drive_MCW_imseq( imseq , isqDR_reimage , (XtPointer) (ntot-1) ) ;
04453 
04454 #ifndef DONT_INSTALL_ICONS
04455    if( afni48_good && afni48ren_pixmap == XmUNSPECIFIED_PIXMAP ){
04456       Pixel bg_pix , fg_pix  ;
04457 
04458       XtVaGetValues( info_lab ,
04459                        XmNforeground , &fg_pix ,
04460                        XmNbackground , &bg_pix ,
04461                      NULL ) ;
04462 
04463       afni48ren_pixmap = XCreatePixmapFromBitmapData(
04464                             XtDisplay(shell) ,
04465                             RootWindowOfScreen(XtScreen(shell)) ,
04466                             afni48ren_bits , afni48ren_width , afni48ren_height ,
04467                             bg_pix , fg_pix ,
04468                             DefaultDepthOfScreen(XtScreen(shell)) ) ;
04469 
04470    }
04471    if( afni48_good )
04472          drive_MCW_imseq( imseq,isqDR_icon , (XtPointer) afni48ren_pixmap ) ;
04473 #endif
04474 
04475    return ;
04476 }
04477 
04478 void REND_update_imseq( void )
04479 {
04480    int ntot , ii ;
04481 
04482    if( imseq == NULL ){ REND_open_imseq() ; return ; }
04483    if( renderings == NULL || IMARR_COUNT(renderings) == 0 ) return ;
04484 
04485    ntot = IMARR_COUNT(renderings) ;
04486 
04487    any_rgb_images = 0 ;
04488    for( ii=0 ; ii < ntot ; ii++ ){
04489       if( IMARR_SUBIMAGE(renderings,ii) != NULL &&
04490           IMARR_SUBIMAGE(renderings,ii)->kind == MRI_rgb ){
04491 
04492          any_rgb_images = 1 ; break ;
04493       }
04494    }
04495 
04496    drive_MCW_imseq( imseq , isqDR_newseq , NULL ) ;
04497 
04498    if( ntot == 1 )
04499       drive_MCW_imseq( imseq , isqDR_onoffwid , (XtPointer) isqDR_offwid ) ;
04500    else {
04501       drive_MCW_imseq( imseq , isqDR_onoffwid , (XtPointer) isqDR_onwid ) ;
04502       drive_MCW_imseq( imseq , isqDR_penbbox  , (XtPointer) 0 ) ; /* 18 Jul 2003 */
04503 #if 0
04504       drive_MCW_imseq( imseq , isqDR_opacitybut , (XtPointer) 0 ) ; /* 07 Mar 2001 */
04505       drive_MCW_imseq( imseq , isqDR_zoombut , (XtPointer) 0 ) ; /* 12 Mar 2002 */
04506 #endif
04507    }
04508 
04509    drive_MCW_imseq( imseq , isqDR_reimage , (XtPointer)(ntot-1) ) ;
04510 
04511    return ;
04512 }
04513 
04514 void REND_destroy_imseq( void )
04515 {
04516    if( imseq == NULL ) return ;
04517    drive_MCW_imseq( imseq , isqDR_destroy , NULL ) ;
04518    return ;
04519 }
04520 
04521 /*------------------------------------------------------------------
04522    Routine to provide data to the imseq.
04523    Just returns the control information, or the selected image.
04524 --------------------------------------------------------------------*/
04525 
04526 XtPointer REND_imseq_getim( int n , int type , XtPointer handle )
04527 {
04528    int ntot = 0 ;
04529 
04530    if( renderings != NULL ) ntot = IMARR_COUNT(renderings) ;
04531    if( ntot < 1 ) ntot = 1 ;
04532 
04533    /*--- send control info ---*/
04534 
04535    if( type == isqCR_getstatus ){
04536       MCW_imseq_status * stat = myXtNew( MCW_imseq_status ) ;  /* will be free-d */
04537                                                                /* when imseq is */
04538                                                                /* destroyed    */
04539       stat->num_total  = ntot ;
04540       stat->num_series = stat->num_total ;
04541       stat->send_CB    = REND_seq_send_CB ;
04542       stat->parent     = NULL ;
04543       stat->aux        = NULL ;
04544 
04545       stat->transforms0D = &(GLOBAL_library.registered_0D) ;
04546       stat->transforms2D = &(GLOBAL_library.registered_2D) ;
04547       stat->slice_proj   = NULL ;
04548 
04549       return (XtPointer) stat ;
04550    }
04551 
04552    /*--- no overlay, never ---*/
04553 
04554    if( type == isqCR_getoverlay ) return NULL ;
04555 
04556    /*--- return a copy of a rendered image
04557          (since the imseq will delete it when it is done) ---*/
04558 
04559    if( type == isqCR_getimage || type == isqCR_getqimage ){
04560       MRI_IMAGE * im = NULL , * rim ;
04561 
04562       if( renderings != NULL ){
04563          if( n < 0 ) n = 0 ; else if( n >= ntot ) n = ntot-1 ;
04564          rim = IMARR_SUBIMAGE(renderings,n) ;
04565          if( any_rgb_images )
04566             im = mri_to_rgb( rim ) ;
04567          else
04568             im = mri_to_mri( rim->kind , rim ) ;
04569 
04570 #ifdef USE_SCRIPTING
04571          if( renderings_state != NULL        &&
04572              n < RSA_COUNT(renderings_state) &&
04573              ! automate_flag                 &&
04574              script_load && script_load_last != n ){
04575 
04576             REND_state_to_widgets( RSA_SUBSTATE(renderings_state,n) ) ;
04577             script_load_last = n ;
04578          }
04579 #endif
04580       }
04581       return (XtPointer) im ;
04582    }
04583 
04584    return NULL ; /* should not occur, but who knows? */
04585 }
04586 
04587 /*---------------------------------------------------------------------------
04588    Routine called when the imseq wants to send a message.
04589    In this case, all we need to handle is the destroy message,
04590    so that we can free some memory.
04591 -----------------------------------------------------------------------------*/
04592 
04593 void REND_seq_send_CB( MCW_imseq * seq , XtPointer handle , ISQ_cbs * cbs )
04594 {
04595    switch( cbs->reason ){
04596       case isqCR_destroy:{
04597          myXtFree(imseq->status) ; myXtFree(imseq) ; imseq = NULL ;
04598       }
04599       break ;
04600    }
04601    return ;
04602 }
04603 
04604 /*----------------------------------------------------------------------------
04605    Automation callbacks
04606 ------------------------------------------------------------------------------*/
04607 
04608 void REND_autoflag_CB( Widget w , XtPointer client_data , XtPointer call_data )
04609 {
04610    int flag = MCW_val_bbox( automate_bbox ) ;
04611    XtSetSensitive( autocompute_pb , (Boolean) flag ) ;
04612 
04613 #ifdef ALLOW_INCROT  /* 26 Apr 2002 - RWCox */
04614    if( flag ) MCW_set_bbox( incrot_bbox , 0 ) ;
04615 #endif
04616 
04617    return ;
04618 }
04619 
04620 /*--------------------------------------------------------------------------
04621    Drive the automatic computation
04622 ----------------------------------------------------------------------------*/
04623 
04624 static int autokill ;
04625 
04626 void REND_autocompute_CB( Widget w, XtPointer client_data, XtPointer call_data )
04627 {
04628    int it , ntime = autoframe_av->ival ;
04629    float scl = 100.0/ntime ;
04630    Widget autometer ;
04631 
04632    automate_flag = 1 ;
04633    if( ! accum_flag ){
04634       DESTROY_IMARR(renderings) ;
04635 #ifdef USE_SCRIPTING
04636       DESTROY_RSA(renderings_state) ;
04637 #endif
04638    }
04639 
04640    atoz[N_IND] = ntime ;
04641 
04642    autometer = MCW_popup_meter( shell , METER_TOP_WIDE ) ;
04643 
04644    XtManageChild( autocancel_pb ) ; AFNI_add_interruptable( autocancel_pb ) ;
04645    autokill = 0 ;
04646 
04647    for( it=0 ; it < ntime ; it++ ){
04648       atoz[T_IND] = it ;
04649       AV_assign_ival( autoframe_av , it+1 ) ;
04650 
04651       REND_draw_CB(NULL,NULL,NULL) ;
04652 
04653       if( it < ntime-1 ){
04654          AFNI_process_interrupts(autocancel_pb) ;
04655          if( autokill ) break ;
04656       }
04657 
04658       MCW_set_meter( autometer , (int)(scl*(it+1)) ) ;
04659    }
04660 
04661    MCW_popdown_meter( autometer ) ;
04662 
04663    /*-- done: turn off automation --*/
04664 
04665    MCW_set_bbox( automate_bbox , 0 ) ;
04666    XtSetSensitive( autocompute_pb , False ) ;
04667 
04668    XtUnmanageChild( autocancel_pb ) ; AFNI_add_interruptable(NULL) ;
04669 
04670    automate_flag = 0 ;
04671    return ;
04672 }
04673 
04674 /*--------------------------------------------------------------------------
04675    Set a flag to cancel the automatic computation
04676 ----------------------------------------------------------------------------*/
04677 
04678 void REND_autocancel_CB( Widget w, XtPointer client_data, XtPointer call_data )
04679 {
04680    if( autokill ){ XBell(dc->display,100) ; return ; }
04681    autokill = 1 ;
04682 }
04683 
04684 /*--------------------------------------------------------------------------
04685    What happens when the user selects a sub-brick from a menu
04686 ----------------------------------------------------------------------------*/
04687 
04688 void REND_choose_av_CB( MCW_arrowval * av , XtPointer cd )
04689 {
04690    XmString xstr ;
04691    char str[2*THD_MAX_NAME] ;
04692 
04693    /*--- selection of a underlay sub-brick ---*/
04694 
04695    if( av == choose_av && dset != NULL && av->ival < DSET_NVALS(dset) ){
04696 
04697       float fac = DSET_BRICK_FACTOR(dset,av->ival) ;
04698 
04699       if( fac == 0.0 || fac == 1.0 ){  /* rewrite the informational label */
04700          strcpy(str,dset_title) ;
04701       } else {
04702          char abuf[16] ;
04703          AV_fval_to_char( fac , abuf ) ;
04704          sprintf(str,"%s [* %s]", dset_title , abuf ) ;
04705       }
04706       xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
04707       XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
04708       XmStringFree(xstr) ;
04709 
04710       dset_ival = av->ival ;   /* read this sub-brick    */
04711       new_dset = 1 ;           /* flag it as new         */
04712       FREE_VOLUMES ;           /* free the internal data */
04713       REND_reload_dataset() ;  /* load the data          */
04714 
04715       if( render_handle != NULL ) REND_draw_CB(NULL,NULL,NULL) ; /* draw */
04716 
04717    /*--- selection of overlay color sub-brick ---*/
04718 
04719    } else if( av == wfunc_color_av && func_dset != NULL && av->ival < DSET_NVALS(func_dset) ){
04720 
04721       float fac = DSET_BRICK_FACTOR(func_dset,av->ival) ;
04722 
04723       if( fac == 0.0 || fac == 1.0 ){  /* rewrite the informational label */
04724          strcpy(str,func_dset_title) ;
04725       } else {
04726          char abuf[16] ;
04727          AV_fval_to_char( fac , abuf ) ;
04728          sprintf(str,"%s [* %s]", func_dset_title , abuf ) ;
04729       }
04730       xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
04731       XtVaSetValues( wfunc_info_lab , XmNlabelString , xstr , NULL ) ;
04732       XmStringFree(xstr) ;
04733 
04734       func_color_ival = av->ival ;
04735 
04736       /* fix the range labels */
04737 
04738       xstr = REND_range_label() ;
04739       XtVaSetValues( wfunc_range_label , XmNlabelString , xstr , NULL ) ;
04740       XmStringFree(xstr) ;
04741 
04742       xstr = REND_autorange_label() ;
04743       XtVaSetValues( wfunc_range_bbox->wbut[0], XmNlabelString,xstr , NULL ) ;
04744       XmStringFree(xstr) ;
04745 
04746       INVALIDATE_OVERLAY ;
04747 
04748       AFNI_hintize_pbar( wfunc_color_pbar , FUNC_RANGE ) ; /* 30 Jul 2001 */
04749 
04750    /*--- selection of overlay threshold sub-brick ---*/
04751 
04752    } else if( av == wfunc_thresh_av && func_dset != NULL && av->ival < DSET_NVALS(func_dset) ){
04753 
04754       func_thresh_ival = av->ival ;
04755 
04756       /* fix the range label */
04757 
04758       xstr = REND_range_label() ;
04759       XtVaSetValues( wfunc_range_label , XmNlabelString , xstr , NULL ) ;
04760       XmStringFree(xstr) ;
04761 
04762       /* fix the p-value label */
04763 
04764       REND_set_thr_pval() ;
04765 
04766       INVALIDATE_OVERLAY ;
04767    }
04768 
04769    return ;
04770 }
04771 
04772 /*---------------------------------------------------------------------------
04773    Make a label for a sub-brick selector menu
04774 -----------------------------------------------------------------------------*/
04775 
04776 char * REND_choose_av_label_CB( MCW_arrowval * av , XtPointer cd )
04777 {
04778    static char blab[32] ;
04779    THD_3dim_dataset * dset = (THD_3dim_dataset *) cd ;
04780    static char * lfmt[3] = { "#%1d %-14.14s" , "#%2d %-14.14s" , "#%3d %-14.14s"  } ;
04781    static char * rfmt[3] = { "%-14.14s #%1d" , "%-14.14s #%2d" , "%-14.14s #%3d"  } ;
04782 
04783    if( ISVALID_3DIM_DATASET(dset) ){
04784 
04785 #ifdef USE_RIGHT_BUCK_LABELS
04786       if( DSET_NVALS(dset) < 10 )
04787         sprintf(blab, rfmt[0] , DSET_BRICK_LABEL(dset,av->ival) , av->ival ) ;
04788       else if( DSET_NVALS(dset) < 100 )
04789         sprintf(blab, rfmt[1] , DSET_BRICK_LABEL(dset,av->ival) , av->ival ) ;
04790       else
04791         sprintf(blab, rfmt[2] , DSET_BRICK_LABEL(dset,av->ival) , av->ival ) ;
04792 #else
04793       if( DSET_NVALS(dset) < 10 )
04794         sprintf(blab, lfmt[0] , av->ival , DSET_BRICK_LABEL(dset,av->ival) ) ;
04795       else if( DSET_NVALS(dset) < 100 )
04796         sprintf(blab, lfmt[1] , av->ival , DSET_BRICK_LABEL(dset,av->ival) ) ;
04797       else
04798         sprintf(blab, lfmt[2] , av->ival , DSET_BRICK_LABEL(dset,av->ival) ) ;
04799 #endif
04800    }
04801    else
04802       sprintf(blab," #%d ",av->ival) ;  /* should not happen! */
04803 
04804    return blab ;
04805 }
04806 
04807 /*----------------------------------------------------------------------------------
04808    Make the widgets for the functional overlay
04809 ------------------------------------------------------------------------------------*/
04810 
04811 void REND_func_widgets(void)
04812 {
04813    XmString xstr ;
04814    Widget   wqqq ;
04815    int      sel_height ;
04816 
04817    /* top level managers */
04818 
04819    wfunc_vsep = SEP_VER(top_rowcol) ;
04820 
04821    wfunc_frame = XtVaCreateWidget(
04822                    "AFNI" , xmFrameWidgetClass , top_rowcol ,
04823                       XmNshadowType , XmSHADOW_ETCHED_IN ,
04824                       XmNshadowThickness , 5 ,
04825                       XmNtraversalOn , False ,
04826                       XmNinitialResourcesPersistent , False ,
04827                    NULL ) ;
04828 
04829    wfunc_uber_rowcol = XtVaCreateWidget(
04830                     "AFNI" , xmRowColumnWidgetClass , wfunc_frame ,
04831                        XmNorientation , XmVERTICAL ,
04832                        XmNpacking , XmPACK_TIGHT ,
04833                        XmNtraversalOn , False ,
04834                        XmNinitialResourcesPersistent , False ,
04835                     NULL ) ;
04836 
04837    xstr = XmStringCreateLtoR( NO_DATASET_STRING ,
04838                               XmFONTLIST_DEFAULT_TAG ) ;
04839    wfunc_info_lab = XtVaCreateManagedWidget(
04840                       "AFNI" , xmLabelWidgetClass , wfunc_uber_rowcol ,
04841                          XmNlabelString , xstr ,
04842                          XmNrecomputeSize , False ,
04843                          XmNinitialResourcesPersistent , False ,
04844                       NULL ) ;
04845    XmStringFree(xstr) ;
04846 
04847    SEP_HOR(wfunc_uber_rowcol) ;
04848 
04849    xstr = XmStringCreateLtoR( "Choose Overlay Dataset" , XmFONTLIST_DEFAULT_TAG ) ;
04850    wfunc_choose_pb = XtVaCreateManagedWidget(
04851                   "AFNI" , xmPushButtonWidgetClass , wfunc_uber_rowcol ,
04852                      XmNalignment   , XmALIGNMENT_CENTER ,
04853                      XmNlabelString , xstr ,
04854                      XmNtraversalOn , False ,
04855                      XmNinitialResourcesPersistent , False ,
04856                   NULL ) ;
04857    XmStringFree(xstr) ;
04858    XtAddCallback( wfunc_choose_pb, XmNactivateCallback, REND_choose_CB, NULL ) ;
04859 
04860    SEP_HOR(wfunc_uber_rowcol) ;
04861 
04862    wfunc_rowcol = XtVaCreateWidget(
04863                     "AFNI" , xmRowColumnWidgetClass , wfunc_uber_rowcol ,
04864                        XmNorientation , XmHORIZONTAL ,
04865                        XmNpacking , XmPACK_TIGHT ,
04866                        XmNtraversalOn , False ,
04867                        XmNinitialResourcesPersistent , False ,
04868                     NULL ) ;
04869 
04870    /*---------------------------- 1st column: threshold stuff ----------------------------*/
04871 
04872    wfunc_thr_rowcol = XtVaCreateWidget(
04873                         "AFNI" , xmRowColumnWidgetClass , wfunc_rowcol ,
04874                            XmNorientation , XmVERTICAL ,
04875                            XmNpacking , XmPACK_TIGHT ,
04876                            XmNmarginHeight, 0 ,
04877                            XmNmarginWidth , 0 ,
04878                            XmNtraversalOn , False ,
04879                            XmNinitialResourcesPersistent , False ,
04880                         NULL ) ;
04881 
04882    xstr = XmStringCreateLtoR( "Thresh" , XmFONTLIST_DEFAULT_TAG ) ;
04883    wfunc_thr_label = XtVaCreateManagedWidget(
04884                        "AFNI" , xmLabelWidgetClass , wfunc_thr_rowcol ,
04885                           XmNlabelString , xstr ,
04886                           XmNrecomputeSize , False ,
04887                           XmNinitialResourcesPersistent , False ,
04888                        NULL ) ;
04889    XmStringFree(xstr) ;
04890 
04891  { int smax , stop , decim , sstep ;                  /* 30 Nov 1997:       */
04892    decim = THR_TOP_EXPON ;                            /* compute parameters */
04893    smax  = (int)( pow(10.0,decim) + 0.001 ) ;         /* for scale display. */
04894    stop  = smax - 1 ;
04895    sstep = smax / 1000 ;  if( sstep < 1 ) sstep = 1 ;
04896    { char *eee = getenv("AFNI_THRESH_BIGSTEP") ;      /* 09 May 2003 */
04897      if( eee != NULL ){ int iq=strtol(eee,NULL,10); if(iq > 0) sstep=iq; }
04898    }
04899 
04900 #ifdef BOXUP_SCALE
04901    wqqq = XtVaCreateManagedWidget(
04902            "AFNI" , xmFrameWidgetClass , wfunc_thr_rowcol ,
04903             XmNshadowType , XmSHADOW_ETCHED_IN ,
04904             XmNtraversalOn , False ,
04905             XmNinitialResourcesPersistent , False ,
04906           NULL ) ;
04907 #else
04908    wqqq = wfunc_thr_rowcol ;
04909 #endif
04910 
04911 #if 1
04912    MCW_widget_geom( anat_frame , &sel_height , NULL,NULL,NULL ) ;
04913    sel_height -= (74 + 24*MAX_CUTOUTS) ;  /* shorter allows for widgets below */
04914 #else
04915    sel_height = 290 ;                     /* a hardwired approach */
04916 #endif
04917 
04918    wfunc_thr_scale =
04919       XtVaCreateManagedWidget(
04920          "scale" , xmScaleWidgetClass , wqqq ,
04921             XmNminimum , 0 ,
04922             XmNmaximum , stop ,
04923             XmNscaleMultiple , sstep ,
04924             XmNdecimalPoints , decim ,
04925             XmNshowValue , True ,
04926             XmNvalue , (int)(smax*func_threshold) ,
04927             XmNorientation , XmVERTICAL ,
04928             XmNheight , sel_height ,
04929             XmNborderWidth , 0 ,
04930             XmNtraversalOn , False ,
04931             XmNinitialResourcesPersistent , False ,
04932          NULL ) ;
04933   }
04934 
04935 #ifdef FIX_SCALE_SIZE_PROBLEM
04936    XtVaSetValues( wfunc_thr_scale , XmNuserData , (XtPointer) sel_height , NULL ) ;
04937 #endif
04938 
04939 #ifdef USING_LESSTIF
04940    XtVaSetValues( wfunc_thr_scale , XmNscaleWidth,24 , NULL ) ;
04941 #endif
04942 
04943    XtAddCallback( wfunc_thr_scale , XmNvalueChangedCallback ,
04944                   REND_thr_scale_CB , NULL ) ;
04945 
04946    XtAddCallback( wfunc_thr_scale , XmNdragCallback ,
04947                   REND_thr_scale_drag_CB , NULL ) ;
04948 
04949    /** label for computed p-value, under scale **/
04950 
04951    xstr = XmStringCreateLtoR( THR_PVAL_LABEL_NONE , XmFONTLIST_DEFAULT_TAG ) ;
04952    wfunc_thr_pval_label =
04953       XtVaCreateManagedWidget(
04954          "AFNI" , xmLabelWidgetClass , wfunc_thr_rowcol ,
04955             XmNlabelString , xstr ,
04956             XmNrecomputeSize , False ,
04957             XmNinitialResourcesPersistent , False ,
04958          NULL ) ;
04959    XmStringFree(xstr) ;
04960 
04961    /** optmenu to choose top value for scale **/
04962 
04963    wfunc_thr_top_av = new_MCW_arrowval( wfunc_thr_rowcol ,
04964                                         "**" ,
04965                                         MCW_AV_optmenu ,
04966                                         0,THR_TOP_EXPON,0 ,
04967                                         MCW_AV_notext , 0 ,
04968                                         REND_thresh_top_CB , NULL ,
04969                                         REND_thresh_tlabel_CB , NULL ) ;
04970    XtManageChild(wfunc_thr_rowcol) ;
04971 
04972    /*--------------- column 2: color chooser stuff ------------------------------*/
04973 
04974    wfunc_color_rowcol =
04975       XtVaCreateWidget(
04976          "AFNI" , xmRowColumnWidgetClass , wfunc_rowcol ,
04977             XmNorientation , XmVERTICAL ,
04978             XmNmarginHeight, 0 ,
04979             XmNmarginWidth , 0 ,
04980             XmNpacking , XmPACK_TIGHT ,
04981             XmNtraversalOn , False ,
04982             XmNinitialResourcesPersistent , False ,
04983          NULL ) ;
04984 
04985    xstr = XmStringCreateLtoR( "Color" , XmFONTLIST_DEFAULT_TAG ) ;
04986    wfunc_color_label =
04987       XtVaCreateManagedWidget(
04988          "AFNI" , xmLabelWidgetClass , wfunc_color_rowcol ,
04989             XmNlabelString , xstr ,
04990             XmNinitialResourcesPersistent , False ,
04991          NULL ) ;
04992    XmStringFree(xstr) ;
04993 
04994    /**-- Popup menu to control some facets of the pbar --**/
04995 
04996 #ifdef BAD_BUTTON3_POPUPS   /* 21 Jul 2003 */
04997    wfunc_pbar_menu = XmCreatePopupMenu( wfunc_color_rowcol, "menu" , NULL , 0 ) ;
04998 #else
04999    wfunc_pbar_menu = XmCreatePopupMenu( wfunc_color_label , "menu" , NULL , 0 ) ;
05000 #endif
05001 
05002    SAVEUNDERIZE(XtParent(wfunc_pbar_menu)) ; /* 27 Feb 2001 */
05003 
05004    VISIBILIZE_WHEN_MAPPED(wfunc_pbar_menu) ;
05005 
05006    XtInsertEventHandler( wfunc_color_label ,     /* handle events in label */
05007 
05008                                0
05009                              | ButtonPressMask   /* button presses */
05010                             ,
05011                             FALSE ,              /* nonmaskable events? */
05012                             REND_pbarmenu_EV ,   /* handler */
05013                             NULL ,               /* client data */
05014                             XtListTail           /* last in queue */
05015                           ) ;
05016 
05017 #if 0
05018    allow_MCW_optmenu_popup(0) ;  /* 12 Dec 2001 */
05019 #endif
05020 
05021    (void) XtVaCreateManagedWidget(
05022             "dialog" , xmLabelWidgetClass , wfunc_pbar_menu ,
05023                LABEL_ARG("-- Cancel --") ,
05024                XmNrecomputeSize , False ,
05025                XmNinitialResourcesPersistent , False ,
05026             NULL ) ;
05027 
05028    (void) XtVaCreateManagedWidget(
05029             "dialog" , xmSeparatorWidgetClass , wfunc_pbar_menu ,
05030              XmNseparatorType , XmSINGLE_LINE , NULL ) ;
05031 
05032    wfunc_pbar_equalize_pb =
05033       XtVaCreateManagedWidget(
05034          "dialog" , xmPushButtonWidgetClass , wfunc_pbar_menu ,
05035             LABEL_ARG("Equalize Spacing") ,
05036             XmNmarginHeight , 0 ,
05037             XmNtraversalOn , False ,
05038             XmNinitialResourcesPersistent , False ,
05039          NULL ) ;
05040 
05041    XtAddCallback( wfunc_pbar_equalize_pb , XmNactivateCallback ,
05042                   REND_pbarmenu_CB , im3d ) ;
05043 
05044    wfunc_pbar_settop_pb =
05045       XtVaCreateManagedWidget(
05046          "dialog" , xmPushButtonWidgetClass , wfunc_pbar_menu ,
05047             LABEL_ARG("Set Top Value") ,
05048             XmNmarginHeight , 0 ,
05049             XmNtraversalOn , False ,
05050             XmNinitialResourcesPersistent , False ,
05051          NULL ) ;
05052 
05053    XtAddCallback( wfunc_pbar_settop_pb , XmNactivateCallback ,
05054                   REND_pbarmenu_CB , im3d ) ;
05055 
05056    /* 15 Jun 2000: image save button */
05057 
05058    wfunc_pbar_saveim_pb =
05059       XtVaCreateManagedWidget(
05060          "dialog" , xmPushButtonWidgetClass , wfunc_pbar_menu ,
05061             LABEL_ARG("Save to PPM") ,
05062             XmNmarginHeight , 0 ,
05063             XmNtraversalOn , False ,
05064             XmNinitialResourcesPersistent , False ,
05065          NULL ) ;
05066 
05067    MCW_register_hint( wfunc_pbar_saveim_pb ,
05068                       "Write out as image file" );
05069 
05070    XtAddCallback( wfunc_pbar_saveim_pb , XmNactivateCallback ,
05071                   REND_pbarmenu_CB , im3d ) ;
05072 
05073    (void) XtVaCreateManagedWidget(
05074             "dialog" , xmSeparatorWidgetClass , wfunc_pbar_menu ,
05075              XmNseparatorType , XmSINGLE_LINE , NULL ) ;
05076 
05077  { static char * pb_dum_label[2] = { "Dummy" , "Dummy" } ;
05078    wfunc_pbar_palette_av = new_MCW_arrowval(
05079                              wfunc_pbar_menu ,     /* parent Widget */
05080                              "Set Pal " ,          /* label */
05081                              MCW_AV_optmenu ,      /* option menu style */
05082                              0 ,                   /* first option */
05083                              1 ,                   /* last option */
05084                              0 ,                   /* initial selection */
05085                              MCW_AV_readtext ,     /* ignored but needed */
05086                              0 ,                   /* ditto */
05087                              REND_palette_av_CB ,  /* callback when changed */
05088                              NULL ,                /* data for above */
05089                              MCW_av_substring_CB , /* text creation routine */
05090                              pb_dum_label          /* data for above */
05091                            ) ;
05092    }
05093 
05094    (void) XtVaCreateManagedWidget(
05095             "dialog" , xmSeparatorWidgetClass , wfunc_pbar_menu ,
05096              XmNseparatorType , XmSINGLE_LINE , NULL ) ;
05097 
05098  { static char * pb_dum_label[3] = { "Normal" , "NoShade" , "NoMix" } ;  /* 21 Dec 1999 */
05099    wfunc_pbar_mixshade_av = new_MCW_arrowval(
05100                              wfunc_pbar_menu ,     /* parent Widget */
05101                              "Mixing  " ,          /* label */
05102                              MCW_AV_optmenu ,      /* option menu style */
05103                              0 ,                   /* first option */
05104                              2 ,                   /* last option */
05105                              0 ,                   /* initial selection */
05106                              MCW_AV_readtext ,     /* ignored but needed */
05107                              0 ,                   /* ditto */
05108                              REND_mixshade_av_CB , /* callback when changed */
05109                              NULL ,                /* data for above */
05110                              MCW_av_substring_CB , /* text creation routine */
05111                              pb_dum_label          /* data for above */
05112                            ) ;
05113    }
05114 
05115    if( GPT != NULL && PALTAB_NUM(GPT) > 0 ){
05116       refit_MCW_optmenu( wfunc_pbar_palette_av ,
05117                            0 ,                     /* new minval */
05118                            PALTAB_NUM(GPT)-1 ,     /* new maxval */
05119                            0 ,                     /* new inival */
05120                            0 ,                     /* new decim? */
05121                            AFNI_palette_label_CB , /* text routine */
05122                            NULL                    /* text data */
05123                         ) ;
05124    } else {
05125       XtUnmanageChild( wfunc_pbar_palette_av->wrowcol ) ;
05126    }
05127 
05128 #if 0
05129    allow_MCW_optmenu_popup(1) ;  /* 12 Dec 2001 */
05130 #endif
05131 
05132    /**-- Color pbar to control intensity-to-color mapping --**/
05133 
05134  { float pmin=-1.0 , pmax=1.0 ;
05135    int npane = INIT_panes_sgn ;  /* from afni.h */
05136 
05137    sel_height -= 22 ;            /* a little shorter than the scale */
05138 
05139    wfunc_color_pbar = new_MCW_pbar(
05140                         wfunc_color_rowcol ,        /* parent */
05141                         dc ,                        /* display */
05142                         npane ,                     /* number panes */
05143                         sel_height / npane ,        /* init pane height */
05144                         pmin , pmax ,               /* value range */
05145                         REND_color_pbar_CB ,        /* callback */
05146                         NULL                ) ;     /* callback data */
05147 
05148    wfunc_color_pbar->parent       = NULL ;
05149    wfunc_color_pbar->mode         = 0 ;
05150    wfunc_color_pbar->npan_save[0] = INIT_panes_sgn ;  /* from afni.h */
05151    wfunc_color_pbar->npan_save[1] = INIT_panes_pos ;
05152    wfunc_color_pbar->hide_changes = INIT_panes_hide ;
05153 
05154    REND_setup_color_pbar() ;  /* other setup stuff */
05155 
05156    (void) XtVaCreateManagedWidget(
05157             "AFNI" , xmSeparatorWidgetClass , wfunc_color_rowcol ,
05158                 XmNseparatorType , XmSINGLE_LINE ,
05159             NULL ) ;
05160 
05161    wfunc_colornum_av = new_MCW_arrowval(
05162                        wfunc_color_rowcol ,
05163                         "#" ,
05164                         MCW_AV_optmenu ,
05165                         NPANE_MIN , NPANE_MAX , npane ,
05166                         MCW_AV_notext , 0 ,
05167                         REND_colornum_av_CB , NULL ,
05168                         NULL,NULL ) ;
05169 
05170    if( NPANE_MAX >= COLSIZE )
05171       AVOPT_columnize( wfunc_colornum_av , 1+(NPANE_MAX+1)/COLSIZE ) ;
05172   }
05173 
05174    /*--- toggle button to control posfunc option for pbar ---*/
05175 
05176  { char * color_bbox_label[1] = { "Pos?" } ;
05177    wfunc_color_bbox = new_MCW_bbox( wfunc_color_rowcol ,
05178                                       1 , color_bbox_label ,
05179                                       MCW_BB_check ,
05180                                       MCW_BB_noframe ,
05181                                       REND_color_bbox_CB , NULL ) ;
05182  }
05183 
05184    XtManageChild(wfunc_color_rowcol) ;
05185 
05186    /*---------- Column 3:  Choices controls -------------------------------*/
05187 
05188    wfunc_choices_rowcol =
05189       XtVaCreateWidget(
05190          "AFNI" , xmRowColumnWidgetClass , wfunc_rowcol ,
05191             XmNorientation , XmVERTICAL ,
05192             XmNpacking , XmPACK_TIGHT ,
05193             XmNmarginHeight, 0 ,
05194             XmNmarginWidth , 0 ,
05195             XmNtraversalOn , False ,
05196             XmNinitialResourcesPersistent , False ,
05197          NULL ) ;
05198 
05199    xstr = XmStringCreateLtoR( "Choices" , XmFONTLIST_DEFAULT_TAG ) ;
05200    wfunc_choices_label =
05201       XtVaCreateManagedWidget(
05202          "AFNI" , xmLabelWidgetClass , wfunc_choices_rowcol ,
05203             XmNlabelString , xstr ,
05204             XmNinitialResourcesPersistent , False ,
05205          NULL ) ;
05206    XmStringFree(xstr) ;
05207 
05208    /*--- 30 Nov 1997: sub-brick menus ---*/
05209 
05210    wfunc_buck_frame =
05211       XtVaCreateWidget(
05212          "AFNI" , xmFrameWidgetClass , wfunc_choices_rowcol ,
05213             XmNshadowType , XmSHADOW_ETCHED_IN ,
05214             XmNtraversalOn , False ,
05215             XmNinitialResourcesPersistent , False ,
05216          NULL ) ;
05217 
05218    wfunc_buck_rowcol =
05219       XtVaCreateWidget(
05220          "AFNI" , xmRowColumnWidgetClass , wfunc_buck_frame ,
05221             XmNorientation , XmVERTICAL ,
05222             XmNpacking , XmPACK_TIGHT ,
05223             XmNtraversalOn , False ,
05224             XmNinitialResourcesPersistent , False ,
05225          NULL ) ;
05226 
05227    /*--- Sub-brick selectors for Color & Threshold ---*/
05228    /*    (Actual labels are set when used)            */
05229 
05230    wfunc_color_av = new_MCW_arrowval(
05231                           wfunc_buck_rowcol    ,  /* parent Widget */
05232                           "Color" ,               /* label */
05233                           MCW_AV_optmenu ,        /* option menu style */
05234                           0 ,                     /* first option */
05235                           1 ,                     /* last option */
05236                           0 ,                     /* initial selection */
05237                           MCW_AV_readtext ,       /* ignored but needed */
05238                           0 ,                     /* decimal shift */
05239                           REND_choose_av_CB ,     /* callback when changed */
05240                           NULL ,                  /* data for above */
05241                           MCW_av_substring_CB ,   /* text creation routine */
05242                           REND_dummy_av_label     /* data for above */
05243                         ) ;
05244 
05245    wfunc_thresh_av = new_MCW_arrowval(
05246                           wfunc_buck_rowcol    ,  /* parent Widget */
05247                           "Thr  " ,               /* label */
05248                           MCW_AV_optmenu ,        /* option menu style */
05249                           0 ,                     /* first option */
05250                           1 ,                     /* last option */
05251                           0 ,                     /* initial selection */
05252                           MCW_AV_readtext ,       /* ignored but needed */
05253                           0 ,                     /* decimal shift */
05254                           REND_choose_av_CB ,     /* callback when changed */
05255                           NULL ,                  /* data for above */
05256                           MCW_av_substring_CB ,   /* text creation routine */
05257                           REND_dummy_av_label     /* data for above */
05258                         ) ;
05259 
05260    XtManageChild( wfunc_buck_rowcol ) ;
05261    XtManageChild( wfunc_buck_frame ) ;
05262 
05263    AV_SENSITIZE( wfunc_color_av  , False ) ;  /* turn these off for now */
05264    AV_SENSITIZE( wfunc_thresh_av , False ) ;
05265 
05266    /*--- menus to control opacity of color ---*/
05267 
05268    wfunc_opacity_frame =
05269       XtVaCreateWidget(
05270          "AFNI" , xmFrameWidgetClass , wfunc_choices_rowcol ,
05271             XmNshadowType , XmSHADOW_ETCHED_IN ,
05272             XmNtraversalOn , False ,
05273             XmNinitialResourcesPersistent , False ,
05274          NULL ) ;
05275 
05276    wfunc_opacity_rowcol =
05277       XtVaCreateWidget(
05278          "AFNI" , xmRowColumnWidgetClass , wfunc_opacity_frame ,
05279             XmNorientation , XmVERTICAL ,
05280             XmNpacking , XmPACK_TIGHT ,
05281             XmNtraversalOn , False ,
05282             XmNinitialResourcesPersistent , False ,
05283          NULL ) ;
05284 
05285  { static char * func_opacity_labels[13] = { /* 11 Sep 2001: add ST+Dcue */
05286                        "Underlay" ,
05287                        " 0.1" , " 0.2" , " 0.3" , " 0.4" , " 0.5" ,
05288                        " 0.6" , " 0.7" , " 0.8" , " 0.9" , " 1.0" ,
05289                        "ShowThru" , "ST+Dcue" } ;
05290 
05291    wfunc_opacity_av = new_MCW_arrowval(
05292                           wfunc_opacity_rowcol  , /* parent Widget */
05293                           "Color Opacity " ,      /* label */
05294                           MCW_AV_optmenu ,        /* option menu style */
05295                           0 ,                     /* first option */
05296                           12 ,                    /* last option */
05297                           5 ,                     /* initial selection */
05298                           MCW_AV_readtext ,       /* ignored but needed */
05299                           0 ,                     /* decimal shift */
05300                           REND_color_opacity_CB , /* callback when changed */
05301                           NULL ,                  /* data for above */
05302                           MCW_av_substring_CB ,   /* text creation routine */
05303                           func_opacity_labels     /* data for above */
05304                         ) ;
05305    }
05306 
05307    /*--- toggle switches to control if we see function ---*/
05308 
05309    { char * see_overlay_label[1]   = { "See Overlay" } ;
05310      char * cut_overlay_label[1]   = { "Cutout Overlay" } ;
05311      char * kill_clusters_label[1] = { "Remove Small Clusters" } ;
05312      char * see_ttatlas_label[1]   = { "TT Atlas" } ;              /* 24 Jul 2001 */
05313      Widget wrc ;
05314 
05315      wrc = XtVaCreateWidget(                                       /* 24 Jul 2001 */
05316              "AFNI" , xmRowColumnWidgetClass , wfunc_opacity_rowcol ,
05317                 XmNorientation , XmHORIZONTAL ,
05318                 XmNpacking , XmPACK_TIGHT ,
05319                 XmNmarginHeight, 0 ,
05320                 XmNmarginWidth , 0 ,
05321                 XmNtraversalOn , False ,
05322                 XmNinitialResourcesPersistent , False ,
05323              NULL ) ;
05324 
05325      wfunc_see_overlay_bbox = new_MCW_bbox( wrc ,
05326                                             1 , see_overlay_label ,
05327                                             MCW_BB_check ,
05328                                             MCW_BB_noframe ,
05329                                             REND_see_overlay_CB , NULL ) ;
05330 
05331      wfunc_see_ttatlas_bbox = new_MCW_bbox( wrc ,                  /* 24 Jul 2001 */
05332                                             1 , see_ttatlas_label ,
05333                                             MCW_BB_check ,
05334                                             MCW_BB_noframe ,
05335                                             REND_see_ttatlas_CB , NULL ) ;
05336 
05337      if( TT_retrieve_atlas() == NULL )
05338        XtSetSensitive( wfunc_see_ttatlas_bbox->wrowcol , False ) ;
05339 
05340      XtManageChild(wrc) ;                                          /* 24 Jul 2001 */
05341 
05342      wfunc_cut_overlay_bbox = new_MCW_bbox( wfunc_opacity_rowcol ,
05343                                             1 , cut_overlay_label ,
05344                                             MCW_BB_check ,
05345                                             MCW_BB_noframe ,
05346                                             REND_cut_overlay_CB , NULL ) ;
05347 
05348      wfunc_kill_clusters_bbox = new_MCW_bbox( wfunc_opacity_rowcol ,
05349                                               1 , kill_clusters_label ,
05350                                               MCW_BB_check ,
05351                                               MCW_BB_noframe ,
05352                                               REND_kill_clusters_CB , NULL ) ;
05353 
05354      wfunc_clusters_rmm_av =
05355          new_MCW_arrowval( wfunc_opacity_rowcol , "   rmm  " , MCW_AV_downup ,
05356                            0 , 99 , (int)(10*func_clusters_rmm) ,
05357                            MCW_AV_edittext , 1 ,
05358                            REND_clusters_av_CB,NULL,NULL,NULL
05359                          ) ;
05360 
05361      wfunc_clusters_vmul_av =
05362          new_MCW_arrowval( wfunc_opacity_rowcol , "   vmul " , MCW_AV_downup ,
05363                            0 , 9999 , (int)(0.1*func_clusters_vmul),
05364                            MCW_AV_edittext , -1 ,
05365                            REND_clusters_av_CB,NULL,NULL,NULL
05366                          ) ;
05367 
05368      AV_SENSITIZE( wfunc_clusters_rmm_av , False ) ;
05369      AV_SENSITIZE( wfunc_clusters_vmul_av, False ) ;
05370    }
05371 
05372    XtManageChild( wfunc_opacity_rowcol ) ;
05373    XtManageChild( wfunc_opacity_frame ) ;
05374 
05375    /*--- range controls ---*/
05376 
05377    wfunc_range_frame =
05378       XtVaCreateManagedWidget(
05379          "AFNI" , xmFrameWidgetClass , wfunc_choices_rowcol ,
05380             XmNshadowType , XmSHADOW_ETCHED_IN ,
05381             XmNtraversalOn , False ,
05382             XmNinitialResourcesPersistent , False ,
05383          NULL ) ;
05384 
05385    wfunc_range_rowcol =
05386       XtVaCreateWidget(
05387          "AFNI" , xmRowColumnWidgetClass , wfunc_range_frame ,
05388             XmNorientation , XmVERTICAL ,
05389             XmNpacking , XmPACK_TIGHT ,
05390             XmNtraversalOn , False ,
05391             XmNinitialResourcesPersistent , False ,
05392          NULL ) ;
05393 
05394    /*--- label to show the data ranges from the overlay dataset ---*/
05395 
05396    xstr = REND_range_label() ;  /* make a dummy label */
05397    wfunc_range_label =
05398       XtVaCreateManagedWidget(
05399          "AFNI" , xmLabelWidgetClass , wfunc_range_rowcol ,
05400             XmNrecomputeSize , False ,
05401             XmNlabelString , xstr ,
05402             XmNtraversalOn , False ,
05403             XmNinitialResourcesPersistent , False ,
05404          NULL ) ;
05405    XmStringFree(xstr) ;
05406 
05407    /*--- toggle button to control automatic range scaling for pbar ---*/
05408 
05409  { char * range_bbox_label[1] = { "autoRange:xxxxxxxxx" } ;
05410 
05411    wfunc_range_bbox =
05412       new_MCW_bbox( wfunc_range_rowcol ,
05413                     1 , range_bbox_label ,
05414                     MCW_BB_check ,
05415                     MCW_BB_noframe ,
05416                     REND_range_bbox_CB , NULL ) ;
05417 
05418    MCW_set_bbox( wfunc_range_bbox , 1 ) ;
05419 
05420    xstr = REND_autorange_label() ;
05421    XtVaSetValues( wfunc_range_bbox->wbut[0], XmNlabelString,xstr , NULL ) ;
05422    XmStringFree(xstr) ;
05423  }
05424 
05425    /*--- 30 Mar 2001: put next 2 things in a horizontal rowcol ---*/
05426 
05427    wqqq = XtVaCreateWidget(
05428          "dialog" , xmRowColumnWidgetClass , wfunc_range_rowcol ,
05429             XmNorientation , XmHORIZONTAL ,
05430             XmNpacking , XmPACK_TIGHT ,
05431             XmNtraversalOn , False ,
05432             XmNinitialResourcesPersistent , False ,
05433          NULL ) ;
05434 
05435    /*--- arrowval to provide user control for pbar scaling ---*/
05436 
05437    wfunc_range_av =
05438       new_MCW_arrowval( wqqq               ,  /* parent */
05439                         NULL ,                /* label */
05440                         MCW_AV_downup ,       /* arrow directions */
05441                         0  ,                  /* min value */
05442                         9999999 ,             /* max value */
05443                         (int)(func_range) ,   /* init value */
05444                         MCW_AV_editext ,      /* input/output text display */
05445                         0 ,                   /* decimal shift */
05446                         REND_range_av_CB ,    /* routine to call when button */
05447                         NULL ,                /* is pressed, and its data */
05448                         NULL,NULL             /* no special display */
05449                      ) ;
05450    AV_SENSITIZE( wfunc_range_av , False ) ;
05451 
05452    /*--- 30 Mar 2001: rotate pbar ---*/
05453 
05454    wfunc_range_rotate_av = new_MCW_arrowval(
05455                              wqqq , "Rota" ,
05456                              MCW_AV_downup , 0,0,0 ,
05457                              MCW_AV_notext , 0 ,
05458                              AFNI_range_rotate_av_CB , (XtPointer) wfunc_color_pbar ,
05459                              NULL,NULL ) ;
05460 
05461    XtManageChild( wqqq ) ;
05462    XtManageChild( wfunc_range_rowcol ) ;
05463    XtManageChild( wfunc_range_frame ) ;
05464 
05465    XtManageChild( wfunc_choices_rowcol ) ;
05466 
05467    XtManageChild( wfunc_rowcol ) ;
05468    XtManageChild( wfunc_uber_rowcol ) ;
05469 
05470 #if 0
05471    XtVaSetValues( wfunc_uber_rowcol , XmNresizeWidth , False , NULL ) ;
05472 #endif
05473 
05474    return ;
05475 }
05476 
05477 /*---------------------------------------------------------------------------------
05478    Initialize the functional colormap
05479 -----------------------------------------------------------------------------------*/
05480 
05481 void REND_init_cmap(void)
05482 {
05483    int ii , nc ;
05484 
05485    for( ii=0 ; ii < 127 ; ii++ )                             /* gray part */
05486       func_rmap[ii] = func_gmap[ii] = func_bmap[ii] = 2*ii ;
05487 
05488    func_rmap[127] = func_gmap[127] = func_bmap[127] = 255 ;  /* white pixel */
05489 
05490    nc = MIN( dc->ovc->ncol_ov , 129 ) ;   /* don't allow colormap overflow */
05491 
05492    for( ii=1 ; ii < nc ; ii++ ){                             /* color part */
05493       func_rmap[127+ii] = DCOV_REDBYTE(dc,ii) ;              /* [skips #0] */
05494       func_gmap[127+ii] = DCOV_GREENBYTE(dc,ii) ;
05495       func_bmap[127+ii] = DCOV_BLUEBYTE(dc,ii) ;
05496    }
05497 
05498    func_ncmap = 127 + nc ;                                   /* size of map */
05499 
05500    if( render_handle != NULL ){
05501        MREN_set_rgbmap( render_handle, func_ncmap, func_rmap,func_gmap,func_bmap ) ;
05502        func_cmap_set = 1 ;
05503    } else {
05504        func_cmap_set = 0 ;
05505    }
05506 
05507    return ;
05508 }
05509 
05510 /*------------------------------------------------------------------------
05511   09 May 2001: fix a Solaris stupidity, where the scale is resized
05512                improperly when the Define Function panel is opened!
05513 --------------------------------------------------------------------------*/
05514 
05515 #ifdef FIX_SCALE_SIZE_LATER
05516 static void fixscale( XtPointer client_data , XtIntervalId * id )
05517 {
05518    FIX_SCALE_SIZE ;
05519 
05520 #if 0
05521    XtVaSetValues( wfunc_thr_scale , XmNscaleWidth,24 , NULL ) ;
05522 #endif
05523 
05524 }
05525 #endif
05526 
05527 
05528 /*---------------------------------------------------------------------------
05529    Open or close the overlay control panel
05530 -----------------------------------------------------------------------------*/
05531 
05532 void REND_open_func_CB( Widget w, XtPointer client_data, XtPointer call_data )
05533 {
05534    if( wfunc_frame == NULL ) REND_func_widgets() ;  /* need to make them */
05535 
05536    if( XtIsManaged(wfunc_frame) ){          /* if open, close */
05537       XtUnmanageChild(wfunc_vsep ) ;
05538       XtUnmanageChild(wfunc_frame) ;
05539    } else {                                 /* if closed, open */
05540       HIDE_SCALE ;
05541       XtManageChild(wfunc_vsep ) ;
05542       XtManageChild(wfunc_frame) ;
05543       update_MCW_pbar( wfunc_color_pbar ) ; /* may need to be redrawn */
05544       FIX_SCALE_SIZE ;
05545 #ifdef FIX_SCALE_SIZE_LATER
05546       (void) XtAppAddTimeOut( XtWidgetToApplicationContext(wfunc_frame),
05547                               50,fixscale,NULL ) ; /* 09 May 2001 */
05548 #endif
05549       REND_init_cmap() ;                    /* setup the colormap */
05550 
05551       POPUP_cursorize(wfunc_color_label) ;
05552    }
05553 
05554    MCW_invert_widget(wfunc_open_pb) ;       /* a flag */
05555    return ;
05556 }
05557 
05558 /*---------------------------------------------------------------------------
05559    Makes the labels for the thresh_top menu (narrower than the default)
05560 -----------------------------------------------------------------------------*/
05561 
05562 char * REND_thresh_tlabel_CB( MCW_arrowval * av , XtPointer junk )
05563 {
05564    static char tlab[8] ;
05565    sprintf(tlab,"%d",av->ival) ;
05566    return tlab ;
05567 }
05568 
05569 /*---------------------------------------------------------------------------
05570    Initialize the memory of the color selector
05571 -----------------------------------------------------------------------------*/
05572 
05573 void REND_setup_color_pbar(void)
05574 {
05575   MCW_pbar * pbar = wfunc_color_pbar ;
05576   int np , i , jm , lcol ;
05577 
05578   jm   = pbar->mode ;
05579   lcol = dc->ovc->ncol_ov - 1 ;
05580 
05581   /** load the 'save' values for all possible pane counts **/
05582 
05583   for( np=NPANE_MIN ; np <= NPANE_MAX ; np++ ){
05584 
05585       for( i=0 ; i <= np ; i++ ){
05586          pbar->pval_save[np][i][0] = INIT_pval_sgn[np][i] ;  /* from afni.h */
05587          pbar->pval_save[np][i][1] = INIT_pval_pos[np][i] ;
05588       }
05589 
05590       for( i=0 ; i <  np ; i++ ){
05591          pbar->ovin_save[np][i][0] = MIN( lcol , INIT_ovin_sgn[np][i] ) ;
05592          pbar->ovin_save[np][i][1] = MIN( lcol , INIT_ovin_pos[np][i] ) ;
05593       }
05594   }
05595 
05596   /** load the values for the current pane count **/
05597 
05598   np = pbar->num_panes ;
05599   jm = pbar->mode ;
05600 
05601   for( i=0 ; i <= np ; i++ ) pbar->pval[i]     = pbar->pval_save[np][i][jm] ;
05602   for( i=0 ; i <  np ; i++ ) pbar->ov_index[i] = pbar->ovin_save[np][i][jm] ;
05603 
05604   pbar->update_me = 1 ;
05605   return ;
05606 }
05607 
05608 /*-------------------------------------------------------------------------
05609   Create label for range display in function control panel
05610 ---------------------------------------------------------------------------*/
05611 
05612 XmString REND_range_label(void)
05613 {
05614    char fim_minch[10]  = " --------" , fim_maxch[10]  = " --------" ,
05615         thr_minch[10]  = " --------" , thr_maxch[10]  = " --------"   ;
05616    char buf[256] , qbuf[16] ;
05617    XmString xstr ;
05618    int iv ;
05619 
05620    if( ISVALID_DSET(func_dset) && ISVALID_STATISTIC(func_dset->stats) ){
05621 
05622       iv = func_color_ival ;
05623 
05624       if( DSET_VALID_BSTAT(func_dset,iv) ){
05625          AV_fval_to_char( func_dset->stats->bstat[iv].min , qbuf ) ;
05626          sprintf( fim_minch , "%9.9s" , qbuf ) ;
05627          AV_fval_to_char( func_dset->stats->bstat[iv].max , qbuf ) ;
05628          sprintf( fim_maxch , "%9.9s" , qbuf ) ;
05629       }
05630 
05631       iv = func_thresh_ival ;
05632 
05633       if( DSET_VALID_BSTAT(func_dset,iv) ){
05634          AV_fval_to_char( func_dset->stats->bstat[iv].min , qbuf ) ;
05635          sprintf( thr_minch , "%9.9s" , qbuf ) ;
05636          AV_fval_to_char( func_dset->stats->bstat[iv].max , qbuf ) ;
05637          sprintf( thr_maxch , "%9.9s" , qbuf ) ;
05638       }
05639    }
05640 
05641    sprintf( buf , "Color %s:%s\nThr   %s:%s" ,
05642             fim_minch,fim_maxch, thr_minch,thr_maxch ) ;
05643 
05644    xstr = XmStringCreateLtoR( buf , XmFONTLIST_DEFAULT_TAG ) ;
05645 
05646    return xstr ;
05647 }
05648 
05649 /*------------------------------------------------------------------------
05650    Find the autorange and make a label for the autorange control widget
05651 --------------------------------------------------------------------------*/
05652 
05653 XmString REND_autorange_label(void)
05654 {
05655    XmString xstr ;
05656    float rrr = DEFAULT_FUNC_RANGE ;
05657    char buf[32] , qbuf[16] ;
05658 
05659    if( ISVALID_DSET(func_dset) ){
05660 
05661       RELOAD_STATS(func_dset) ;
05662       if( ISVALID_STATISTIC(func_dset->stats) ){
05663          float s1 , s2 ; int iv ;
05664 
05665          iv = func_color_ival ;
05666 
05667          if( DSET_VALID_BSTAT(func_dset,iv) ){
05668             s1  = fabs(func_dset->stats->bstat[iv].min) ,
05669             s2  = fabs(func_dset->stats->bstat[iv].max) ;
05670             rrr = (s1<s2) ? s2 : s1 ;
05671             if( rrr == 0.0 ) rrr = 1.0 ;
05672          }
05673       }
05674    }
05675 
05676    func_autorange = rrr ;
05677    AV_fval_to_char( rrr , qbuf ) ;
05678    sprintf( buf , "autoRange:%s" , qbuf ) ;
05679    xstr = XmStringCreateLtoR( buf , XmFONTLIST_DEFAULT_TAG ) ;
05680 
05681    return xstr ;
05682 }
05683 
05684 /*-----------------------------------------------------------------------------
05685    Set the p-value label at the bottom of the threshold slider
05686 -------------------------------------------------------------------------------*/
05687 
05688 void REND_set_thr_pval(void)
05689 {
05690    float thresh , pval ;
05691    int   dec ;
05692    char  buf[16] ;
05693 
05694    if( !ISVALID_DSET(func_dset) ) return ;
05695 
05696    /* get the "true" threshold (scaled up from being in [0,1]) */
05697 
05698    thresh = func_threshold * func_thresh_top ;
05699 
05700    /* get the p-value that goes with this threshold, for this functional dataset */
05701 
05702 #if 0
05703    if( ISFUNCBUCKET(func_dset) )
05704       pval = THD_stat_to_pval( thresh ,
05705                                DSET_BRICK_STATCODE(func_dset,func_thresh_ival) ,
05706                                DSET_BRICK_STATAUX (func_dset,func_thresh_ival)  ) ;
05707 
05708    else if( func_thresh_ival == DSET_THRESH_VALUE(func_dset) )
05709       pval = THD_stat_to_pval( thresh , func_dset->func_type ,
05710                                         func_dset->stat_aux   ) ;
05711 
05712    else
05713       pval = -1.0 ;
05714 #else
05715    pval = THD_stat_to_pval( thresh ,
05716                             DSET_BRICK_STATCODE(func_dset,func_thresh_ival) ,
05717                             DSET_BRICK_STATAUX (func_dset,func_thresh_ival)  ) ;
05718 #endif
05719 
05720    if( pval < 0.0 ){
05721       strcpy( buf , THR_PVAL_LABEL_NONE ) ;
05722    } else {
05723       if( pval == 0.0 ){
05724          strcpy( buf , "p = 0" ) ;
05725       } else if( pval >= 0.9999 ){
05726          strcpy( buf , "p = 1" ) ;
05727       } else if( pval >= 0.0010 ){
05728          char qbuf[16] ;
05729          sprintf( qbuf , "%5.4f" , pval ) ;
05730          strcpy( buf , qbuf+1 ) ;
05731       } else {
05732          int dec = (int)(0.999 - log10(pval)) ;
05733          pval = pval * pow( 10.0 , (double) dec ) ;  /* between 1 and 10 */
05734          if( dec < 10 ) sprintf( buf , "%3.1f-%1d" ,      pval, dec ) ;
05735          else           sprintf( buf , "%1d.-%2d"  , (int)pval, dec ) ;
05736       }
05737    }
05738    MCW_set_widget_label( wfunc_thr_pval_label , buf ) ;
05739    return ;
05740 }
05741 
05742 /*------------------------------------------------------------------------------
05743    When the user alters the threshold [at the end]
05744 --------------------------------------------------------------------------------*/
05745 
05746 void REND_thr_scale_CB( Widget w, XtPointer client_data, XtPointer call_data )
05747 {
05748    XmScaleCallbackStruct * cbs = (XmScaleCallbackStruct *) call_data ;
05749    float fff ;
05750 
05751    fff = THR_FACTOR * cbs->value ;  /* between 0 and 1 now */
05752    if( fff >= 0.0 && fff <= 1.0 ) func_threshold = fff ; else return ;
05753    REND_set_thr_pval() ;
05754 
05755    INVALIDATE_OVERLAY ;
05756    FIX_SCALE_SIZE ;     /* 09 May 2001 */
05757    return ;
05758 }
05759 
05760 /*-------------------------------------------------------------------------------
05761   When the user drags the slider (just update the p-value)
05762 ---------------------------------------------------------------------------------*/
05763 
05764 void REND_thr_scale_drag_CB( Widget w, XtPointer client_data, XtPointer call_data )
05765 {
05766    XmScaleCallbackStruct * cbs = (XmScaleCallbackStruct *) call_data ;
05767    float fff ;
05768 
05769    fff = THR_FACTOR * cbs->value ;  /* between 0 and 1 now */
05770    if( fff >= 0.0 && fff <= 1.0 ) func_threshold = fff ; else return ;
05771    REND_set_thr_pval() ;
05772 
05773    return ;
05774 }
05775 
05776 
05777 /*-------------------------------------------------------------------------------
05778   Called when the user toggles the autorange button
05779 ---------------------------------------------------------------------------------*/
05780 
05781 void REND_range_bbox_CB( Widget w, XtPointer cd, XtPointer cb)
05782 {
05783    int newauto = MCW_val_bbox(wfunc_range_bbox) ;
05784 
05785    if( newauto == func_use_autorange ) return ;  /* no change? */
05786 
05787    func_use_autorange = newauto ;
05788 
05789    func_range = (newauto) ? (func_autorange)
05790                           : (wfunc_range_av->fval) ;
05791 
05792    AFNI_hintize_pbar( wfunc_color_pbar , FUNC_RANGE ) ; /* 30 Mar 2001 */
05793 
05794    AV_SENSITIZE( wfunc_range_av , ! newauto ) ;
05795 
05796    INVALIDATE_OVERLAY ;
05797    return ;
05798 }
05799 
05800 /*------------------------------------------------------------------------------
05801   Called when the user changes the function range
05802 --------------------------------------------------------------------------------*/
05803 
05804 void REND_range_av_CB( MCW_arrowval * av , XtPointer cd )
05805 {
05806    func_range = av->fval ;
05807 
05808    AFNI_hintize_pbar( wfunc_color_pbar , FUNC_RANGE ) ; /* 30 Mar 2001 */
05809 
05810    INVALIDATE_OVERLAY ;
05811    return ;
05812 }
05813 
05814 /*------------------------------------------------------------------------------
05815    Called to change the scaling on the threshold slider
05816 --------------------------------------------------------------------------------*/
05817 
05818 void REND_thresh_top_CB( MCW_arrowval * av , XtPointer cd )
05819 {
05820    static float dval[9] = { 1.0 , 10.0 , 100.0 , 1000.0 , 10000.0 ,
05821                             100000.0 , 1000000.0 , 10000000.0 , 100000000.0 } ;
05822    int decim ;
05823    float tval ;
05824 
05825    tval = dval[av->ival] ; if( tval <= 0.0 ) tval = 1.0 ;
05826 
05827    decim = (2*THR_TOP_EXPON) - (int)(THR_TOP_EXPON + 0.01 + log10(tval)) ;
05828    if( decim < 0 ) decim = 0 ;
05829 
05830    XtVaSetValues( wfunc_thr_scale, XmNdecimalPoints, decim, NULL ) ;
05831 
05832    func_thresh_top = tval ;
05833    REND_set_thr_pval() ;
05834 
05835    INVALIDATE_OVERLAY ;
05836    return ;
05837 }
05838 
05839 /*-------------------------------------------------------------------------------
05840   Called by the pbar routines when the pbar is altered.
05841 ---------------------------------------------------------------------------------*/
05842 
05843 void REND_color_pbar_CB( MCW_pbar * pbar , XtPointer cd , int reason )
05844 {
05845    FIX_SCALE_SIZE ;
05846    INVALIDATE_OVERLAY ;
05847 
05848    AFNI_hintize_pbar( wfunc_color_pbar , FUNC_RANGE ) ; /* 30 Mar 2001 */
05849    return ;
05850 }
05851 
05852 /*------------------------------------------------------------------------------
05853   Called to change the number of panels in the pbar
05854 --------------------------------------------------------------------------------*/
05855 
05856 void REND_colornum_av_CB( MCW_arrowval * av , XtPointer cd )
05857 {
05858    HIDE_SCALE ;
05859    alter_MCW_pbar( wfunc_color_pbar , av->ival , NULL ) ;
05860    FIX_SCALE_SIZE ;
05861    INVALIDATE_OVERLAY ;
05862    return ;
05863 }
05864 
05865 /*------------------------------------------------------------------------------
05866    Called when the user toggles the posfunc button
05867 --------------------------------------------------------------------------------*/
05868 
05869 void REND_color_bbox_CB( Widget w, XtPointer cd, XtPointer cb)
05870 {
05871    int jm , newpos=MCW_val_bbox(wfunc_color_bbox) ;
05872 
05873    if( newpos == func_posfunc ) return ;  /* no change? */
05874 
05875    func_posfunc = newpos ;
05876    jm = wfunc_color_pbar->mode = (newpos) ? 1 : 0 ;  /* pbar mode */
05877 
05878    HIDE_SCALE ;
05879    alter_MCW_pbar( wfunc_color_pbar , wfunc_color_pbar->npan_save[jm] , NULL ) ;
05880    FIX_SCALE_SIZE ;
05881 
05882    /* set the count on the pbar control arrowval to match */
05883 
05884    AV_assign_ival( wfunc_colornum_av , wfunc_color_pbar->npan_save[jm] ) ;
05885 
05886    INVALIDATE_OVERLAY ;
05887    return ;
05888 }
05889 
05890 /*------------------------------------------------------------------------------
05891    Called to set the overlay opacity factor
05892 --------------------------------------------------------------------------------*/
05893 
05894 void REND_color_opacity_CB( MCW_arrowval * av , XtPointer cd )
05895 {
05896    int ofs = func_showthru ;
05897    func_color_opacity = 0.1 * av->ival ;
05898    func_showthru = (av->ival == 11 || av->ival == 12) ;    /* 07 Jan 2000 */
05899    func_showthru_dcue = ( av->ival == 12 ) ;               /* 11 Sep 2001 */
05900    INVALIDATE_OVERLAY ;
05901 
05902    if( func_showthru != ofs ) FREE_VOLUMES ;
05903    return ;
05904 }
05905 
05906 /*------------------------------------------------------------------------------
05907    Called to toggle visibility of the overlay
05908 --------------------------------------------------------------------------------*/
05909 
05910 void REND_see_overlay_CB( Widget w, XtPointer cd, XtPointer cb)
05911 {
05912    int newsee = MCW_val_bbox(wfunc_see_overlay_bbox) ;
05913 
05914    if( newsee == func_see_overlay ) return ;
05915 
05916    func_see_overlay = newsee ;
05917    INVALIDATE_OVERLAY ; FREE_VOLUMES ;
05918    return ;
05919 }
05920 
05921 /*------------------------------------------------------------------------------
05922    Called to toggle visibility of the TT atlas -- 24 Jul 2001
05923 --------------------------------------------------------------------------------*/
05924 
05925 void REND_see_ttatlas_CB( Widget w, XtPointer cd, XtPointer cb)
05926 {
05927    int newsee = MCW_val_bbox(wfunc_see_ttatlas_bbox) ;
05928 
05929    if( newsee == func_see_ttatlas ) return ;
05930 
05931    func_see_ttatlas = newsee ;
05932    INVALIDATE_OVERLAY ; FREE_VOLUMES ;
05933    return ;
05934 }
05935 
05936 /*------------------------------------------------------------------------------
05937    Called to toggle whether or not cutouts affect the overlay
05938 --------------------------------------------------------------------------------*/
05939 
05940 void REND_cut_overlay_CB( Widget w, XtPointer cd, XtPointer cb)
05941 {
05942    int newcut = MCW_val_bbox(wfunc_cut_overlay_bbox) ;
05943 
05944    if( newcut == func_cut_overlay ) return ;
05945 
05946    func_cut_overlay = newcut ;
05947    if( num_cutouts > 0 ){ INVALIDATE_OVERLAY ; }
05948    return ;
05949 }
05950 
05951 /*------------------------------------------------------------------------------
05952    Called to toggle whether or not to kill clusters
05953 --------------------------------------------------------------------------------*/
05954 
05955 void REND_kill_clusters_CB( Widget w, XtPointer cd, XtPointer cb)
05956 {
05957    int cc , newkill = MCW_val_bbox(wfunc_kill_clusters_bbox) ;
05958 
05959    if( newkill == func_kill_clusters ) return ;
05960 
05961    func_kill_clusters = newkill ;
05962 
05963    AV_SENSITIZE( wfunc_clusters_rmm_av , newkill ) ;
05964    AV_SENSITIZE( wfunc_clusters_vmul_av, newkill ) ;
05965 
05966    INVALIDATE_OVERLAY ;
05967 
05968    for( cc=0 ; cc < current_cutout_state.num ; cc++ )
05969       if( current_cutout_state.type[cc] == CUT_NONOVERLAY ){
05970          FREE_VOLUMES ;
05971          break ;
05972       }
05973 
05974    return ;
05975 }
05976 
05977 void REND_clusters_av_CB( MCW_arrowval * av , XtPointer cd )
05978 {
05979    int cc ;
05980 
05981    INVALIDATE_OVERLAY ;
05982 
05983    for( cc=0 ; cc < current_cutout_state.num ; cc++ )
05984       if( current_cutout_state.type[cc] == CUT_NONOVERLAY ){
05985          FREE_VOLUMES ;
05986          break ;
05987       }
05988 
05989    return ;
05990 }
05991 
05992 /*-------------------------------------------------------------------------------
05993   Event handler to find #3 button press for pbar popup, and popup the menu
05994 ---------------------------------------------------------------------------------*/
05995 
05996 void REND_pbarmenu_EV( Widget w , XtPointer cd ,
05997                        XEvent * ev , Boolean * continue_to_dispatch )
05998 {
05999    static int old_paltab_num = 0 ;
06000 
06001    switch( ev->type ){
06002       case ButtonPress:{
06003          XButtonEvent * event = (XButtonEvent *) ev ;
06004          if( event->button == Button3 || event->button == Button1 ){
06005 
06006             /* in case the user read in any new palette, add them to menu */
06007 
06008             if( GPT != NULL && PALTAB_NUM(GPT) > old_paltab_num ){
06009                refit_MCW_optmenu( wfunc_pbar_palette_av ,
06010                                     0 ,                     /* new minval */
06011                                     PALTAB_NUM(GPT)-1 ,     /* new maxval */
06012                                     0 ,                     /* new inival */
06013                                     0 ,                     /* new decim? */
06014                                     AFNI_palette_label_CB , /* text routine */
06015                                     NULL                    /* text data */
06016                                  ) ;
06017                XtManageChild( wfunc_pbar_palette_av->wrowcol ) ;
06018                old_paltab_num = PALTAB_NUM(GPT) ;
06019             }
06020 
06021             XmMenuPosition( wfunc_pbar_menu , event ) ; /* where */
06022             XtManageChild ( wfunc_pbar_menu ) ;         /* popup */
06023          }
06024       }
06025       break ;
06026    }
06027    return ;
06028 }
06029 
06030 /*--------------------------------------------------------------------------------
06031   Callbacks for all actions in the pbar popup
06032 ----------------------------------------------------------------------------------*/
06033 
06034 void REND_pbarmenu_CB( Widget w , XtPointer cd , XtPointer cbs )
06035 {
06036    MCW_pbar * pbar ;
06037    int npane , jm , ii ;
06038    double pmax , pmin ;
06039    float pval[NPANE_MAX+1] ;
06040 
06041    pbar  = wfunc_color_pbar ;
06042    npane = pbar->num_panes ;
06043    jm    = pbar->mode ;
06044    pmax  = pbar->pval_save[npane][0][jm] ;
06045    pmin  = pbar->pval_save[npane][npane][jm] ;
06046 
06047    /*--- Equalize spacings ---*/
06048 
06049    if( w == wfunc_pbar_equalize_pb ){
06050       for( ii=0 ; ii <= npane ; ii++ )
06051          pval[ii] = pmax - ii * (pmax-pmin)/npane ;
06052 
06053       HIDE_SCALE ;
06054       alter_MCW_pbar( pbar , 0 , pval ) ;
06055       FIX_SCALE_SIZE ;
06056       INVALIDATE_OVERLAY ;
06057    }
06058 
06059    /*--- Set top value ---*/
06060 
06061    else if( w == wfunc_pbar_settop_pb ){
06062       MCW_choose_integer( wfunc_choices_label ,
06063                           "Pbar Top" , 0 , 99999 , 1 ,
06064                           REND_set_pbar_top_CB , NULL  ) ;
06065    }
06066 
06067    /*--- Save pbar into image file ---*/
06068 
06069    else if( w == wfunc_pbar_saveim_pb ){
06070       MCW_choose_string( wfunc_choices_label,
06071                          "PPM file prefix" , NULL ,
06072                          REND_finalize_saveim_CB , cd ) ;
06073    }
06074 
06075    return ;
06076 }
06077 
06078 void REND_palette_av_CB( MCW_arrowval * av , XtPointer cd )
06079 {
06080    if( GPT == NULL || av->ival < 0 || av->ival >= PALTAB_NUM(GPT) ) return ;
06081 
06082    HIDE_SCALE ;
06083    load_PBAR_palette_array( wfunc_color_pbar ,             /* cf. afni_setup.c */
06084                             PALTAB_ARR(GPT,av->ival) , 0 ) ;
06085    FIX_SCALE_SIZE ;
06086 
06087    INVALIDATE_OVERLAY ;
06088    return ;
06089 }
06090 
06091 void REND_mixshade_av_CB( MCW_arrowval * av , XtPointer cd )  /* 21 Dec 1999 */
06092 {
06093    func_mixshade = av->ival ;
06094    return ;
06095 }
06096 
06097 void REND_set_pbar_top_CB( Widget w , XtPointer cd , MCW_choose_cbs * cbs )
06098 {
06099    MCW_pbar * pbar ;
06100    float pval[NPANE_MAX+1] ;
06101    double pmax , fac ;
06102    int ii ;
06103 
06104    if( ! renderer_open ){ POPDOWN_integer_chooser; XBell(dc->display,100); return; }
06105 
06106    pmax = cbs->fval ; if( pmax <= 0.0 ) return ;           /* illegal */
06107    pbar = wfunc_color_pbar ;
06108    fac  = pmax / pbar->pval[0] ; if( fac == 1.0 ) return ; /* no change */
06109 
06110    for( ii=0 ; ii <= pbar->num_panes ; ii++ )
06111       pval[ii] = fac * pbar->pval[ii] ;
06112 
06113    HIDE_SCALE ;
06114    alter_MCW_pbar( pbar , 0 , pval ) ;
06115    FIX_SCALE_SIZE ;
06116 
06117    INVALIDATE_OVERLAY ;
06118    return ;
06119 }
06120 
06121 void REND_finalize_saveim_CB( Widget wcaller, XtPointer cd, MCW_choose_cbs * cbs )
06122 {
06123    Three_D_View * im3d = (Three_D_View *) cd ;
06124    char * fname , * ptr ;
06125    int ll , nx=20 , ny=256 ;
06126    MRI_IMAGE * im ;
06127 
06128    if( !renderer_open || cbs->reason != mcwCR_string ||
06129        cbs->cval == NULL || (ll=strlen(cbs->cval)) == 0   ) return;
06130 
06131    fname = (char *) malloc( sizeof(char) * (ll+8) ) ;
06132    strcpy( fname , cbs->cval ) ;
06133 
06134    if( ll > 240 || ! THD_filename_ok(fname) ){free(fname); return;}
06135 
06136                      ptr = strstr(fname,".ppm") ;
06137    if( ptr == NULL ) ptr = strstr(fname,".pnm") ;
06138    if( ptr == NULL ) ptr = strstr(fname,".jpg") ;
06139    if( ptr == NULL ) strcat(fname,".ppm") ;
06140 
06141    fprintf(stderr,"Writing palette image to %s\n",fname) ;
06142 
06143    ptr = getenv( "AFNI_PBAR_IMXY" );
06144    if( ptr != NULL ){
06145      ll = sscanf( ptr , "%dx%d" , &nx , &ny ) ;
06146      if( ll < 2 || nx < 1 || ny < 32 ){ nx=20; ny=256; }
06147    }
06148 
06149    im = MCW_pbar_to_mri( wfunc_color_pbar , nx,ny ) ;
06150    mri_write_pnm( fname , im ) ;
06151 
06152    POPDOWN_string_chooser; mri_free(im); free(fname); return;
06153 }
06154 
06155 /*-----------------------------------------------------------------------------------
06156    Load color index data from the functional dataset into the local overlay array
06157    (heavily adapted from AFNI_func_overlay in afni_func.c).
06158 -------------------------------------------------------------------------------------*/
06159 
06160 void REND_reload_func_dset(void)
06161 {
06162    MRI_IMAGE * cim , * tim ;
06163    void      * car , * tar ;
06164    float      cfac ,  tfac ;
06165    int ii , nvox , num_lp , lp ;
06166    byte * ovar ;
06167    MCW_pbar * pbar = wfunc_color_pbar ;
06168    byte fim_ovc[NPANE_MAX+1] ;
06169    float fim_thr[NPANE_MAX] , scale_factor , thresh ;
06170 
06171    INVALIDATE_OVERLAY ;              /* toss old overlay, if any */
06172 
06173    if( !func_see_overlay || func_dset == NULL ){ /* 24 Jul 2001: if not seeing */
06174                                                  /* function, make empty ovim  */
06175 
06176       ovim = mri_new_conforming( DSET_BRICK(dset,dset_ival) , MRI_byte ) ;
06177       ovar = MRI_BYTE_PTR(ovim) ;
06178       memset( ovar , 0 , DSET_NVOX(dset) ) ;
06179       goto EndOfFuncOverlay ;                 /* AHA! */
06180    }
06181 
06182    DSET_load(func_dset) ;            /* make sure is in memory */
06183 
06184    cim  = DSET_BRICK(func_dset,func_color_ival) ; nvox = cim->nvox ; /* color brick */
06185    car  = DSET_ARRAY(func_dset,func_color_ival) ;
06186    cfac = DSET_BRICK_FACTOR(func_dset,func_color_ival) ;
06187    if( cfac == 0.0 ) cfac = 1.0 ;
06188 
06189    tim  = DSET_BRICK(func_dset,func_thresh_ival) ;                   /* thresh brick */
06190    tar  = DSET_ARRAY(func_dset,func_thresh_ival) ;
06191    tfac = DSET_BRICK_FACTOR(func_dset,func_thresh_ival) ;
06192    if( tfac == 0.0 ) tfac = 1.0 ;
06193 
06194    ovim = mri_new_conforming( cim , MRI_byte ) ;                     /* new overlay */
06195    ovar = MRI_BYTE_PTR(ovim) ;
06196 
06197    scale_factor = FUNC_RANGE ;  /* for map from pbar to data value range  */
06198 
06199    num_lp = pbar->num_panes ;
06200    for( lp=0 ; lp < num_lp ; lp++ ) fim_ovc[lp] = pbar->ov_index[lp] ; /* top to bottom */
06201    fim_ovc[num_lp] = (func_posfunc) ? (0) : (fim_ovc[num_lp-1]) ;      /* off the bottom */
06202 
06203    thresh = func_threshold * func_thresh_top / tfac ;  /* threshold in tar[] scale */
06204 
06205    /*--- Load the overlay image with the color overlay index ---*/
06206 
06207    if( thresh < 1.0 || !func_use_thresh ){  /*--- no thresholding needed ---*/
06208 
06209       switch( cim->kind ){
06210 
06211          case MRI_short:{
06212             short * sar = (short *) car ;
06213 
06214             for( lp=0 ; lp < num_lp ; lp++ )                          /* pbar in     */
06215                fim_thr[lp] = scale_factor * pbar->pval[lp+1] / cfac ; /* car[] scale */
06216 
06217             for( ii=0 ; ii < nvox ; ii++ ){
06218                if( sar[ii] == 0 ){
06219                   ovar[ii] = 0 ;
06220                } else {
06221                   for( lp=0 ; lp < num_lp && sar[ii] < fim_thr[lp] ; lp++ ) ; /*nada*/
06222                   ovar[ii] = fim_ovc[lp] ;
06223                }
06224             }
06225          }
06226          break ;
06227 
06228          case MRI_float:{
06229             float * sar = (float *) car ;
06230 
06231             for( lp=0 ; lp < num_lp ; lp++ )
06232                fim_thr[lp] = scale_factor * pbar->pval[lp+1] / cfac ;
06233 
06234             for( ii=0 ; ii < nvox ; ii++ ){
06235                if( sar[ii] == 0.0 ){
06236                   ovar[ii] = 0 ;
06237                } else {
06238                   for( lp=0 ; lp < num_lp && sar[ii] < fim_thr[lp] ; lp++ ) ; /*nada*/
06239                   ovar[ii] = fim_ovc[lp] ;
06240                }
06241             }
06242          }
06243          break ;
06244 
06245          case MRI_byte:{
06246             byte * sar = (byte *) car ;
06247 
06248             for( lp=0 ; lp < num_lp ; lp++ )
06249                if( pbar->pval[lp+1] <= 0.0 )
06250                   fim_thr[lp] = 0 ;
06251                else
06252                   fim_thr[lp] = scale_factor * pbar->pval[lp+1] / cfac ;
06253 
06254             for( ii=0 ; ii < nvox ; ii++ ){
06255                if( sar[ii] == 0 ){
06256                   ovar[ii] = 0 ;
06257                } else {
06258                   for( lp=0 ; lp < num_lp && sar[ii] < fim_thr[lp] ; lp++ ) ; /*nada*/
06259                   ovar[ii] = fim_ovc[lp] ;
06260                }
06261             }
06262          }
06263          break ;
06264       }             /*--- end of no thresholding case ---*/
06265 
06266    } else {         /*--- start of thresholding ---*/
06267 
06268       switch( cim->kind ){
06269 
06270          case MRI_short:{
06271             short * sar = (short *) car ;
06272             short * qar = (short *) tar ;
06273             int     thr = (int) thresh  ;
06274 
06275             for( lp=0 ; lp < num_lp ; lp++ )
06276                fim_thr[lp] = scale_factor * pbar->pval[lp+1] / cfac ;
06277 
06278             for( ii=0 ; ii < nvox ; ii++ ){
06279                if( (qar[ii] > -thr && qar[ii] < thr) || sar[ii] == 0.0 ){
06280                   ovar[ii] = 0 ;
06281                } else {
06282                   for( lp=0 ; lp < num_lp && sar[ii] < fim_thr[lp] ; lp++ ) ; /*nada*/
06283                   ovar[ii] = fim_ovc[lp] ;
06284                }
06285             }
06286          }
06287          break ;
06288 
06289          case MRI_float:{
06290             float * sar = (float *) car ;
06291             float * qar = (float *) tar ;
06292             float   thr = thresh        ;
06293 
06294             for( lp=0 ; lp < num_lp ; lp++ )
06295                fim_thr[lp] = scale_factor * pbar->pval[lp+1] / cfac ;
06296 
06297             for( ii=0 ; ii < nvox ; ii++ ){
06298                if( (qar[ii] > -thr && qar[ii] < thr) || sar[ii] == 0 ){
06299                   ovar[ii] = 0 ;
06300                } else {
06301                   for( lp=0 ; lp < num_lp && sar[ii] < fim_thr[lp] ; lp++ ) ; /*nada*/
06302                   ovar[ii] = fim_ovc[lp] ;
06303                }
06304             }
06305          }
06306          break ;
06307 
06308          case MRI_byte:{
06309             byte * sar = (byte *) car ;
06310             byte * qar = (byte *) tar ;
06311             int    thr = (int) thresh ;
06312 
06313             for( lp=0 ; lp < num_lp ; lp++ )
06314                if( pbar->pval[lp+1] <= 0.0 )
06315                   fim_thr[lp] = 0 ;
06316                else
06317                   fim_thr[lp] = scale_factor * pbar->pval[lp+1] / cfac ;
06318 
06319             for( ii=0 ; ii < nvox ; ii++ ){
06320                if( qar[ii] < thr || sar[ii] == 0 ){
06321                   ovar[ii] = 0 ;
06322                } else {
06323                   for( lp=0 ; lp < num_lp && sar[ii] < fim_thr[lp] ; lp++ ) ; /*nada*/
06324                   ovar[ii] = fim_ovc[lp] ;
06325                }
06326             }
06327          }
06328          break ;
06329       }
06330    }
06331 
06332    /*----- if ordered, remove clusters -----*/
06333 
06334    if( func_kill_clusters ){
06335       int nx=ovim->nx , ny=ovim->ny , nz=ovim->nz , ptmin,iclu ;
06336       float dx = fabs(func_dset->daxes->xxdel) ,
06337             dy = fabs(func_dset->daxes->yydel) ,
06338             dz = fabs(func_dset->daxes->zzdel)  ;
06339       float rmm  = wfunc_clusters_rmm_av->fval ,
06340             vmul = wfunc_clusters_vmul_av->fval ;
06341       MCW_cluster_array * clar ;
06342       MCW_cluster * cl ;
06343 
06344       if( (rmm >= dx || rmm >= dy || rmm >= dz) && vmul > (dx*dy*dz) ){
06345          ptmin = vmul / (dx*dy*dz) + 0.99 ;
06346          clar  = MCW_find_clusters( nx,ny,nz , dx,dy,dz , MRI_byte,ovar , rmm ) ;
06347          if( clar != NULL ){
06348             for( iclu=0 ; iclu < clar->num_clu ; iclu++ ){
06349                cl = clar->clar[iclu] ;
06350                if( cl->num_pt >= ptmin )  /* put back into array */
06351                   MCW_cluster_to_vol( nx,ny,nz , MRI_byte,ovar , cl ) ;
06352             }
06353             DESTROY_CLARR(clar) ;
06354          }
06355       }
06356    }  /* end of cluster removal */
06357 
06358    /*----- other overlay stuff -----*/
06359 
06360 EndOfFuncOverlay:
06361 
06362    if( func_see_ttatlas ) REND_overlay_ttatlas() ;  /* 12 July 2001 */
06363 
06364    if( xhair_flag ) REND_xhair_overlay() ; /* 08 Mar 2001 */
06365 
06366    return ;
06367 }
06368 
06369 /*-----------------------------------------------------------------------
06370    Overlay regions from the Talairach Daemon database, if possible
06371 -------------------------------------------------------------------------*/
06372 
06373 #define HEMX 80         /* 1/2 the brain, in the x-direction */
06374 #define ALLX (2*HEMX+1) /* all the brain, in the x-direction */
06375 
06376 void REND_overlay_ttatlas(void)
06377 {
06378    TTRR_params *ttp ;
06379    THD_3dim_dataset *dseTT ;
06380    byte *b0 , *b1 , *ovar ;
06381    int nvox , ii,jj , xx ;
06382    int fwin , gwin , nreg , hemi,hbot ;
06383    byte *brik , *val , *ovc , g_ov , a_ov , final_ov ;
06384 
06385    /* sanity checks and setup */
06386 
06387    if( ovim == NULL ) return ;
06388 
06389    nvox = ovim->nvox ;
06390 
06391 #if 0
06392 # define RET(s) do{fprintf(stderr,s);return;}while(0)
06393 #else
06394 # define RET(s) return
06395 #endif
06396 
06397    /* 01 Aug 2001: retrieve Atlas dataset depending on size of brick */
06398 #if 1
06399    dseTT = TT_retrieve_atlas_nz(ovim->nz) ;
06400                                  if( dseTT == NULL ) RET("no dataset\n") ;
06401 #else
06402    dseTT = TT_retrieve_atlas() ; if( dseTT == NULL ) RET("no dataset\n") ;
06403 #endif
06404 
06405    if( DSET_NVOX(dseTT) != nvox )                    RET("dataset mismatch\n");
06406    ttp   = TTRR_get_params()   ; if( ttp   == NULL ) RET("no ttp\n") ;
06407 
06408    DSET_load(dseTT) ;
06409    b0 = DSET_ARRAY(dseTT,0) ; b1 = DSET_ARRAY(dseTT,1) ;
06410    if( b0 == NULL || b1 == NULL )                    RET("no bricks\n") ;
06411 
06412    ovar = MRI_BYTE_PTR(ovim) ;
06413 
06414    fwin = (ttp->meth == TTRR_METH_FGA) || (ttp->meth == TTRR_METH_FAG) ;
06415    gwin = (ttp->meth == TTRR_METH_FGA) || (ttp->meth == TTRR_METH_GAF) ;
06416 
06417    nreg = ttp->num ;
06418    brik = ttp->ttbrik ;
06419    val  = ttp->ttval ;
06420    ovc  = ttp->ttovc ;
06421 
06422    hemi = ttp->hemi ;
06423    switch( hemi ){
06424       case TTRR_HEMI_LEFT:  hbot=HEMX+1 ; break ;
06425       case TTRR_HEMI_RIGHT: hbot= 0     ; break ;
06426       case TTRR_HEMI_BOTH:  hbot= 0     ; break ;
06427    }
06428 
06429    /* ready to do something */
06430 
06431    for( xx=0,ii=hbot ; ii < nvox ; ii++ ){
06432 
06433       if( hemi != TTRR_HEMI_BOTH ){
06434          if( xx == HEMX ){
06435             xx = 0 ; ii += HEMX ; continue ;  /* skip ahead 1/2 row */
06436          }
06437          xx++ ;
06438       }
06439 
06440       if( ovar[ii] && fwin ) continue ;  /* function wins */
06441 
06442       /* check atlas dataset for hits */
06443 
06444       g_ov = a_ov = 0 ;
06445       for( jj=0 ; (g_ov==0 || a_ov==0) && jj<nreg ; jj++ ){
06446               if( b0[ii] == val[jj] ) g_ov = ovc[jj] ;
06447          else if( b1[ii] == val[jj] ) a_ov = ovc[jj] ;
06448       }
06449 
06450       if( g_ov==0 && a_ov==0 ) continue ;  /* no hit */
06451 
06452       if( g_ov && (gwin || a_ov==0) ) final_ov = g_ov ;
06453       else                            final_ov = a_ov ;
06454 
06455       ovar[ii] = final_ov ;
06456    }
06457 
06458    return ;
06459 }
06460 
06461 /*-----------------------------------------------------------------------
06462    Overlay some colored lines showing the crosshair location.
06463    Note that this function assumes that the current anat dataset
06464    in AFNI is defined on exactly the same grid as the rendering dataset.
06465    08 Mar 2001 -- Adapted from the grayscale underlay version
06466 -------------------------------------------------------------------------*/
06467 
06468 #define OV(i,j,k) ovar[(i)+(j)*nx+(k)*nxy]
06469 
06470 void REND_xhair_overlay(void)
06471 {
06472    int ix,jy,kz , nx,ny,nz,nxy , ii , gap , om ;
06473    byte * ovar ;
06474    byte   gxh = xhair_ovc ;
06475 
06476    if( ovim == NULL || xhair_ovc == 0 ) return ;  /* error */
06477 
06478    CHECK_XHAIR_ERROR ;
06479 
06480    ix = im3d->vinfo->i1 ; nx = ovim->nx ;
06481    jy = im3d->vinfo->j2 ; ny = ovim->ny ; nxy = nx * ny ;
06482    kz = im3d->vinfo->k3 ; nz = ovim->nz ;
06483 
06484    om = im3d->vinfo->xhairs_orimask ;  /* 02 Jun 1999 */
06485 
06486    if( ix < 0 || ix >= nx ) return ;  /* error */
06487    if( jy < 0 || jy >= ny ) return ;  /* error */
06488    if( kz < 0 || kz >= nz ) return ;  /* error */
06489 
06490    gap  = im3d->vinfo->crosshair_gap ;
06491    ovar = MRI_BYTE_PTR(ovim) ;
06492 
06493    /* 02 Jun 1999: allow for partial crosshair drawing */
06494 
06495    if( (om & ORIMASK_LR) != 0 ){
06496       for( ii=0 ; ii < nx ; ii++ ){
06497          if( abs(ii-ix) > gap ){ OV(ii,jy,kz) = gxh ; }
06498       }
06499    }
06500 
06501    if( (om & ORIMASK_AP) != 0 ){
06502       for( ii=0 ; ii < ny ; ii++ ){
06503          if( abs(ii-jy) > gap ){ OV(ix,ii,kz) = gxh ; }
06504       }
06505    }
06506 
06507    if( (om & ORIMASK_IS) != 0 ){
06508       for( ii=0 ; ii < nz ; ii++ ){
06509          if( abs(ii-kz) > gap ){ OV(ix,jy,ii) = gxh ; }
06510       }
06511    }
06512 
06513    xhair_ixold = ix ; xhair_jyold = jy ; xhair_kzold = kz ;  /* memory */
06514    xhair_omold = om ;                                        /* 02 Jun 1999 */
06515    return ;
06516 }
06517 
06518 /*---------------------------------------------------------------------------
06519   Callback for opacity scale factor selection
06520 -----------------------------------------------------------------------------*/
06521 
06522 void REND_opacity_scale_CB( MCW_arrowval * av , XtPointer cd )
06523 {
06524    if( av->fval < MIN_OPACITY_SCALE ) AV_assign_fval(av,MIN_OPACITY_SCALE) ;
06525    if( cd == NULL && dynamic_flag && render_handle != NULL )
06526       REND_draw_CB(NULL,NULL,NULL) ;
06527    return ;
06528 }
06529 
06530 /*****************************************************************************
06531   Functions for saving the internal rendering state to a script,
06532   reading it back in, et cetera.
06533 ******************************************************************************/
06534 
06535 #ifdef USE_SCRIPTING
06536 /*--------------------------------------------------------------------
06537    07 July 1999: Create the widgets for the script control menu
06538 ----------------------------------------------------------------------*/
06539 
06540 void REND_script_menu( Widget parent )
06541 {
06542    Widget rc , mbar ;
06543    static char * load_bbox_label[1]    = { "Load Widgets" } ;
06544    static char * brindex_bbox_label[1] = { "Brick Index?" } ;
06545 #ifdef SCRIPT_GRAFS
06546    static char * graf_bbox_label[1]    = { "Alter Grafs?" } ;
06547 #endif
06548    static char * dset_bbox_label[1]    = { "Alter Dsets?" } ;
06549 
06550    rc =  XtVaCreateWidget(
06551            "dialog" , xmRowColumnWidgetClass , parent ,
06552               XmNorientation , XmHORIZONTAL ,
06553               XmNpacking , XmPACK_TIGHT ,
06554               XmNtraversalOn , False ,
06555               XmNinitialResourcesPersistent , False ,
06556            NULL ) ;
06557 
06558    mbar = XmCreateMenuBar( rc , "dialog" , NULL,0 ) ;
06559    XtVaSetValues( mbar ,
06560                      XmNmarginWidth  , 0 ,
06561                      XmNmarginHeight , 0 ,
06562                      XmNspacing      , 3 ,
06563                      XmNborderWidth  , 0 ,
06564                      XmNborderColor  , 0 ,
06565                      XmNtraversalOn  , False ,
06566                      XmNbackground   , im3d->dc->ovc->pixov_brightest ,
06567                   NULL ) ;
06568    XtManageChild( mbar ) ;
06569 
06570    script_menu =
06571          XmCreatePulldownMenu( mbar , "menu" , NULL,0 ) ;
06572 
06573    VISIBILIZE_WHEN_MAPPED(script_menu) ;
06574 
06575    script_cbut =
06576          XtVaCreateManagedWidget(
06577             "dialog" , xmCascadeButtonWidgetClass , mbar ,
06578                LABEL_ARG("Scripts") ,
06579                XmNsubMenuId    , script_menu ,
06580                XmNmarginWidth  , 0 ,
06581                XmNmarginHeight , 0 ,
06582                XmNmarginBottom , 0 ,
06583                XmNmarginTop    , 0 ,
06584                XmNmarginRight  , 0 ,
06585                XmNmarginLeft   , 0 ,
06586                XmNtraversalOn  , False ,
06587                XmNinitialResourcesPersistent , False ,
06588             NULL ) ;
06589 
06590 #undef MENU_SLINE
06591 #define MENU_SLINE                                            \
06592    (void) XtVaCreateManagedWidget(                            \
06593             "dialog" , xmSeparatorWidgetClass , script_menu , \
06594              XmNseparatorType , XmSINGLE_LINE , NULL )
06595 
06596    /* macro to create a new script menu button */
06597 
06598 #define SCRIPT_MENU_BUT(wname,label)                           \
06599     wname =                                                    \
06600          XtVaCreateManagedWidget(                              \
06601             "dialog" , xmPushButtonWidgetClass , script_menu , \
06602                LABEL_ARG( label ) ,                            \
06603                XmNmarginHeight , 0 ,                           \
06604                XmNtraversalOn , False ,                        \
06605                XmNinitialResourcesPersistent , False ,         \
06606             NULL ) ;                                           \
06607       XtAddCallback( wname , XmNactivateCallback ,             \
06608                      REND_script_CB , NULL ) ;
06609 
06610    /*** top of menu = a label to click on that does nothing at all ***/
06611 
06612    (void) XtVaCreateManagedWidget(
06613             "dialog" , xmLabelWidgetClass , script_menu ,
06614                LABEL_ARG("-- Cancel --") ,
06615                XmNrecomputeSize , False ,
06616                XmNinitialResourcesPersistent , False ,
06617             NULL ) ;
06618 
06619    MENU_SLINE ;
06620 
06621    SCRIPT_MENU_BUT( script_save_this_pb , "Save This" ) ;
06622    SCRIPT_MENU_BUT( script_save_many_pb , "Save Many" ) ;
06623 
06624    MENU_SLINE ;
06625 
06626    SCRIPT_MENU_BUT( script_read_this_pb , "Read This"   ) ;
06627    SCRIPT_MENU_BUT( script_read_exec_pb , "Read & Exec" ) ;
06628 
06629    MENU_SLINE ;
06630 
06631    script_load_bbox = new_MCW_bbox( script_menu , 1 , load_bbox_label ,
06632                                     MCW_BB_check , MCW_BB_noframe ,
06633                                     REND_script_load_CB , NULL ) ;
06634    MCW_reghint_children( script_load_bbox->wrowcol ,
06635                          "Recall settings from images" ) ;
06636 
06637    script_brindex_bbox = new_MCW_bbox( script_menu , 1 , brindex_bbox_label ,
06638                                        MCW_BB_check , MCW_BB_noframe ,
06639                                        REND_script_brindex_CB , NULL ) ;
06640    MCW_reghint_children( script_brindex_bbox->wrowcol ,
06641                          "Set brick index when loading widgets?" ) ;
06642 
06643 #ifdef SCRIPT_GRAFS
06644    script_graf_bbox = new_MCW_bbox( script_menu , 1 , graf_bbox_label ,
06645                                     MCW_BB_check , MCW_BB_noframe ,
06646                                     REND_script_graf_CB , NULL ) ;
06647    MCW_reghint_children( script_graf_bbox->wrowcol ,
06648                          "Set grafs when loading widgets?" ) ;
06649 #endif
06650 
06651 #ifdef SCRIPT_DSETS
06652    /* 12 Apr 2000 - toggle button for dataset changing via scripts */
06653 
06654    script_dset_bbox = new_MCW_bbox( script_menu , 1 , dset_bbox_label ,
06655                                     MCW_BB_check , MCW_BB_noframe ,
06656                                     REND_script_dset_CB , NULL ) ;
06657    MCW_reghint_children( script_dset_bbox->wrowcol ,
06658                          "Change datasets when loading widgets?" ) ;
06659 #endif
06660 
06661    XtManageChild( rc ) ;
06662    return ;
06663 }
06664 
06665 #ifdef SCRIPT_DSETS
06666 /*-----------------------------------------------------------------------
06667    Callback when the "Alter Dsets?" button is toggled
06668 -------------------------------------------------------------------------*/
06669 
06670 void REND_script_dset_CB( Widget w , XtPointer cd , XtPointer cbs )
06671 {
06672    script_dsetchange = MCW_val_bbox( script_dset_bbox ) ;
06673    return ;
06674 }
06675 #endif
06676 
06677 #ifdef SCRIPT_GRAFS
06678 /*-----------------------------------------------------------------------
06679    Callback when the "Alter Grafs?" button is toggled
06680 -------------------------------------------------------------------------*/
06681 
06682 void REND_script_graf_CB( Widget w , XtPointer cd , XtPointer cbs )
06683 {
06684    script_graf = MCW_val_bbox( script_graf_bbox ) ;
06685    return ;
06686 }
06687 #endif
06688 
06689 /*-----------------------------------------------------------------------
06690    Callback when the "Brick Index?" button is toggled
06691 -------------------------------------------------------------------------*/
06692 
06693 void REND_script_brindex_CB( Widget w , XtPointer cd , XtPointer cbs )
06694 {
06695    script_brindex = MCW_val_bbox( script_brindex_bbox ) ;
06696    return ;
06697 }
06698 
06699 /*-----------------------------------------------------------------------
06700    Callback when the "Load Widgets" button is toggled
06701 -------------------------------------------------------------------------*/
06702 
06703 void REND_script_load_CB( Widget w , XtPointer cd , XtPointer cbs )
06704 {
06705    int sl = MCW_val_bbox( script_load_bbox ) ;
06706 
06707    if( sl == script_load ) return ;  /* no change? */
06708 
06709    script_load      = sl ;
06710    script_load_last = -1 ;
06711 
06712    if( script_load && imseq != NULL && renderings_state != NULL ){
06713       int nn ;
06714       drive_MCW_imseq( imseq , isqDR_getimnr , (XtPointer) &nn ) ;
06715       if( nn >= 0 && nn < RSA_COUNT(renderings_state) ){
06716          REND_state_to_widgets( RSA_SUBSTATE(renderings_state,nn) ) ;
06717          script_load_last = nn ;
06718       }
06719    } else if( !script_load && last_rendered_state != NULL ){
06720       REND_state_to_widgets( last_rendered_state ) ;
06721    }
06722 
06723    return ;
06724 }
06725 
06726 /*----------------------------------------------------------------------
06727    Callback when a script menu button is pressed
06728 ------------------------------------------------------------------------*/
06729 
06730 static char script_read_fname[THD_MAX_NAME] = "\0" ;
06731 
06732 void REND_script_CB( Widget w , XtPointer cd , XtPointer cbs )
06733 {
06734    if( w == script_save_this_pb ){
06735       MCW_choose_string( w , "[Save This] Filename prefix:" , NULL ,
06736                          REND_save_this_CB , NULL ) ;
06737       return ;
06738    }
06739 
06740    if( w == script_read_this_pb ){
06741       MCW_choose_string( w , "[Read This] Filename prefix:" ,
06742                          script_read_fname ,
06743                          REND_read_this_CB , NULL ) ;
06744       return ;
06745    }
06746 
06747    if( w == script_save_many_pb ){
06748       if( renderings_state == NULL || RSA_COUNT(renderings_state) < 1 ){
06749          (void) MCW_popup_message( script_cbut ,
06750                                       " \n"
06751                                       "** No rendering states\n"
06752                                       "** available to save!\n" ,
06753                                    MCW_USER_KILL | MCW_TIMER_KILL   ) ;
06754          PLUTO_beep() ; return ;
06755       }
06756       MCW_choose_string( w , "[Save Many] Filename prefix:" , NULL ,
06757                          REND_save_many_CB , NULL ) ;
06758       return ;
06759    }
06760 
06761    if( w == script_read_exec_pb ){
06762 #ifdef SCRIPT_DSETS
06763       if( dset == NULL && script_dsetchange == 0 )
06764 #else
06765       if( dset == NULL )
06766 #endif
06767       {
06768          (void) MCW_popup_message( script_cbut ,
06769                                       " \n"
06770                                       "** No dataset loaded\n"
06771                                       "** for rendering!\n" ,
06772                                    MCW_USER_KILL | MCW_TIMER_KILL   ) ;
06773          PLUTO_beep() ; return ;
06774       }
06775       MCW_choose_string( w , "[Read & Exec] Filename prefix:" ,
06776                          script_read_fname ,
06777                          REND_read_exec_CB , NULL ) ;
06778       return ;
06779    }
06780 
06781    /*-- should never be reached --*/
06782 
06783    PLUTO_beep() ; return ;
06784 }
06785 
06786 /*----------------------------------------------------------------------
06787    Called when the "Save This" filename chooser is activated
06788 ------------------------------------------------------------------------*/
06789 
06790 void REND_save_this_CB( Widget w , XtPointer cd , MCW_choose_cbs * cbs )
06791 {
06792    int ll ;
06793    char * fname , buf[256] , * sbuf ;
06794    RENDER_state rs ;
06795    FILE * fp ;
06796 
06797    if( !renderer_open ){ POPDOWN_string_chooser ; return ; }
06798 
06799    if( cbs->reason != mcwCR_string ||
06800        cbs->cval == NULL           || (ll = strlen(cbs->cval)) == 0 ){
06801 
06802       PLUTO_beep() ; return ;
06803    }
06804 
06805    fname = malloc( sizeof(char) * (ll+8) ) ;
06806    strcpy(fname,cbs->cval) ;
06807 
06808    if( strstr(fname,".rset") == NULL ){
06809       if( fname[ll-1] != '.' ){ fname[ll++] = '.'; fname[ll] = '\0'; }
06810       strcat(fname,"rset") ;
06811    }
06812 
06813    if( !THD_filename_ok(fname) ){
06814       sprintf(buf," \n"
06815                   "** Filename %s is illegal!\n"
06816                   "** Try something different.\n" , fname ) ;
06817       (void) MCW_popup_message( script_cbut , buf ,
06818                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
06819       free(fname) ; PLUTO_beep() ; return ;
06820    }
06821 
06822    if( THD_is_file(fname) ){
06823       sprintf(buf," \n"
06824                   "** File %s already exists!\n"
06825                   "** AFNI won't overwrite it.\n" , fname ) ;
06826       (void) MCW_popup_message( script_cbut , buf ,
06827                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
06828       free(fname) ; PLUTO_beep() ; return ;
06829    }
06830 
06831    REND_widgets_to_state( &rs ) ;
06832    sbuf = REND_save_state( &rs , NULL ) ;
06833 
06834    if( sbuf == NULL ){
06835       (void) MCW_popup_message( script_cbut ,
06836                                    "\n"
06837                                    "** Some error occured when\n"
06838                                    "** trying to save the state!\n" ,
06839                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
06840       free(fname) ; PLUTO_beep() ; return ;
06841    }
06842 
06843    fp = fopen( fname , "w" ) ;
06844    if( fp == NULL ){
06845       (void) MCW_popup_message( script_cbut ,
06846                                    "\n"
06847                                    "** Some error occured when\n"
06848                                    "** trying to open the file!\n" ,
06849                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
06850       free(sbuf) ; free(fname) ; PLUTO_beep() ; return ;
06851    }
06852 
06853    POPDOWN_string_chooser ;
06854    fwrite( sbuf , 1 , strlen(sbuf) , fp ) ;
06855    fclose( fp ) ;
06856    free( sbuf ) ; free(fname) ; return ;
06857 }
06858 
06859 /*----------------------------------------------------------------------
06860    Called when the "Read This" filename chooser is activated
06861 ------------------------------------------------------------------------*/
06862 
06863 void REND_read_this_CB( Widget w , XtPointer cd , MCW_choose_cbs * cbs )
06864 {
06865    int ll ;
06866    char * fname , buf[256] , * sbuf ;
06867    RENDER_state rs ;
06868    RENDER_state_array * rsa ;
06869    FILE * fp ;
06870 
06871    if( !renderer_open ){ POPDOWN_string_chooser ; return ; }
06872 
06873    if( cbs->reason != mcwCR_string ||
06874        cbs->cval == NULL           || (ll = strlen(cbs->cval)) == 0 ){
06875 
06876       PLUTO_beep() ; return ;
06877    }
06878 
06879    fname = malloc( sizeof(char) * (ll+8) ) ;
06880    strcpy(fname,cbs->cval) ; strcpy(script_read_fname,fname) ;
06881 
06882    if( strstr(fname,".rset") == NULL ){
06883       if( fname[ll-1] != '.' ){ fname[ll++] = '.'; fname[ll] = '\0'; }
06884       strcat(fname,"rset") ;
06885    }
06886 
06887    REND_widgets_to_state( &rs ) ;
06888    rsa = REND_read_states( fname , &rs ) ;
06889 
06890    if( rsa == NULL || RSA_COUNT(rsa) < 1 ){
06891       sprintf(buf, "\n"
06892                    "** Some error occured when\n"
06893                    "** trying to read file %s\n" , fname ) ;
06894       (void) MCW_popup_message( script_cbut , buf ,
06895                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
06896       free(fname) ; PLUTO_beep() ; return ;
06897    }
06898 
06899    free(fname) ; POPDOWN_string_chooser ;
06900 
06901    if( RSA_COUNT(rsa) == 1 ){
06902       MCW_choose_cbs cbs ;
06903       cbs.ival = 0 ; cbs.reason = mcwCR_integer ;
06904       REND_read_this_finalize_CB( NULL , (XtPointer) rsa , &cbs ) ;
06905    } else {
06906       MCW_choose_integer( w , "[Read This] State Index" ,
06907                           0 , RSA_COUNT(rsa)-1 , 0 ,
06908                           REND_read_this_finalize_CB , (XtPointer) rsa ) ;
06909    }
06910 
06911    return ;
06912 }
06913 
06914 void REND_read_this_finalize_CB( Widget w , XtPointer cd , MCW_choose_cbs * cbs )
06915 {
06916    RENDER_state_array * rsa = (RENDER_state_array *) cd ;
06917 
06918    POPDOWN_integer_chooser ;
06919 
06920    if( cbs->reason != mcwCR_integer ||
06921        cbs->ival < 0                || cbs->ival >= RSA_COUNT(rsa) ){
06922 
06923       PLUTO_beep() ; return ;
06924    }
06925 
06926    REND_state_to_widgets( RSA_SUBSTATE(rsa,cbs->ival) ) ;
06927 
06928    DESTROY_RSA(rsa) ;
06929    return ;
06930 }
06931 
06932 /*----------------------------------------------------------------------
06933    Called when the "Save Many" filename chooser is activated
06934 ------------------------------------------------------------------------*/
06935 
06936 void REND_save_many_CB( Widget w , XtPointer cd , MCW_choose_cbs * cbs )
06937 {
06938    int ll , ii ;
06939    char * fname , buf[256] , * sbuf ;
06940    RENDER_state * rs ;
06941    FILE * fp ;
06942 
06943    if( !renderer_open           ||
06944        renderings_state == NULL || RSA_COUNT(renderings_state) < 1 ){
06945 
06946       POPDOWN_string_chooser ; return ;
06947    }
06948 
06949    if( cbs->reason != mcwCR_string ||
06950        cbs->cval == NULL           || (ll = strlen(cbs->cval)) == 0 ){
06951 
06952       PLUTO_beep() ; return ;
06953    }
06954 
06955    fname = malloc( sizeof(char) * (ll+8) ) ;
06956    strcpy(fname,cbs->cval) ;
06957 
06958    if( strstr(fname,".rset") == NULL ){
06959       if( fname[ll-1] != '.' ){ fname[ll++] = '.'; fname[ll] = '\0'; }
06960       strcat(fname,"rset") ;
06961    }
06962 
06963    if( !THD_filename_ok(fname) ){
06964       sprintf(buf," \n"
06965                   "** Filename %s is illegal!\n"
06966                   "** Try something different.\n" , fname ) ;
06967       (void) MCW_popup_message( script_cbut , buf ,
06968                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
06969       free(fname) ; PLUTO_beep() ; return ;
06970    }
06971 
06972    if( THD_is_file(fname) ){
06973       sprintf(buf," \n"
06974                   "** File %s already exists!\n"
06975                   "** AFNI won't overwrite it.\n" , fname ) ;
06976       (void) MCW_popup_message( script_cbut , buf ,
06977                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
06978       free(fname) ; PLUTO_beep() ; return ;
06979    }
06980 
06981    fp = fopen( fname , "w" ) ;
06982    if( fp == NULL ){
06983       sprintf(buf, " \n"
06984                    "** Some error occured when\n"
06985                    "** trying to open file %s\n" , fname ) ;
06986       (void) MCW_popup_message( script_cbut , buf ,
06987                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
06988       free(fname) ; PLUTO_beep() ; return ;
06989    }
06990    free(fname) ; POPDOWN_string_chooser ;
06991 
06992    rs = NULL ;
06993    for( ii=0 ; ii < RSA_COUNT(renderings_state) ; ii++ ){
06994       sbuf = REND_save_state( RSA_SUBSTATE(renderings_state,ii) , rs ) ;
06995       fwrite( sbuf , 1 , strlen(sbuf) , fp ) ; free(sbuf) ;
06996       rs = RSA_SUBSTATE(renderings_state,ii) ;
06997    }
06998 
06999    fclose( fp ) ;
07000 }
07001 
07002 /*----------------------------------------------------------------------
07003    Called when the "Read & Exec" filename chooser is activated
07004 ------------------------------------------------------------------------*/
07005 
07006 void REND_read_exec_CB( Widget w , XtPointer cd , MCW_choose_cbs * cbs )
07007 {
07008    int ll , it , ntime ;
07009    char * fname , buf[256] , * sbuf ;
07010    RENDER_state rs ;
07011    RENDER_state_array * rsa ;
07012    FILE * fp ;
07013    float scl ;
07014    Widget autometer ;
07015 
07016    if( !renderer_open ){ POPDOWN_string_chooser ; return ; }
07017 
07018    if( cbs->reason != mcwCR_string ||
07019        cbs->cval == NULL           || (ll = strlen(cbs->cval)) == 0 ){
07020 
07021       PLUTO_beep() ; return ;
07022    }
07023 
07024    fname = malloc( sizeof(char) * (ll+8) ) ;
07025    strcpy(fname,cbs->cval) ; strcpy(script_read_fname,fname) ;
07026 
07027    if( strstr(fname,".rset") == NULL ){
07028       if( fname[ll-1] != '.' ){ fname[ll++] = '.'; fname[ll] = '\0'; }
07029       strcat(fname,"rset") ;
07030    }
07031 
07032    REND_widgets_to_state( &rs ) ;
07033    rsa = REND_read_states( fname , &rs ) ;
07034 
07035    if( rsa == NULL || RSA_COUNT(rsa) < 1 ){
07036       sprintf(buf, "\n"
07037                    "** Some error occured when\n"
07038                    "** trying to read file %s\n" , fname ) ;
07039       (void) MCW_popup_message( script_cbut , buf ,
07040                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
07041       free(fname) ; PLUTO_beep() ; return ;
07042    }
07043 
07044    free(fname) ; POPDOWN_string_chooser ;
07045 
07046    /*-- now execute the renderings (a la 'Automate' )--*/
07047 
07048    automate_flag = 1 ;
07049    if( ! accum_flag ){
07050       DESTROY_IMARR(renderings) ;
07051       DESTROY_RSA(renderings_state) ;
07052    }
07053    ntime = RSA_COUNT(rsa) ;
07054 
07055    if( ntime > 1 ){
07056       autometer = MCW_popup_meter( shell , METER_TOP_WIDE ) ;
07057       XtManageChild( autocancel_pb ) ; AFNI_add_interruptable( autocancel_pb ) ;
07058       autokill = 0 ; scl = 100.0/ntime ;
07059    }
07060 
07061    for( it=0 ; it < ntime ; it++ ){
07062 
07063       REND_state_to_widgets( RSA_SUBSTATE(rsa,it) ) ;
07064       if( dset == NULL ) break ;                        /* some error */
07065 
07066       REND_draw_CB(NULL,NULL,NULL) ;
07067 
07068       if( it < ntime-1 ){
07069          AFNI_process_interrupts(autocancel_pb) ;
07070          if( autokill ) break ;
07071       }
07072 
07073       if( ntime > 1 ) MCW_set_meter( autometer , (int)(scl*(it+1)) ) ;
07074    }
07075 
07076    /*-- done: cleanup time --*/
07077 
07078    DESTROY_RSA(rsa) ;
07079 
07080    if( ntime > 1 ){
07081       MCW_popdown_meter( autometer ) ;
07082       XtUnmanageChild( autocancel_pb ) ; AFNI_add_interruptable(NULL) ;
07083    }
07084 
07085    automate_flag = 0 ;
07086    return ;
07087 }
07088 
07089 /*--------------------------------------------------------------------------
07090    Read a file and return an array of rendering states.
07091    Code is adapted from afni_setup.c
07092 ----------------------------------------------------------------------------*/
07093 
07094 #define ISTARRED(s) ( (s)[0]=='*' && (s)[1]=='*' && (s)[2]=='*' )
07095 
07096 #define EOLSKIP                                                          \
07097   do{ for( ; fptr[0] != '\n' && fptr[0] != '\0' ; fptr++ ) ; /* nada */  \
07098       if( fptr[0] == '\0' ) goto Finished ;                              \
07099       fptr++ ; } while(0)
07100 
07101 #define GETSSS                                                            \
07102   do{ int nu=0,qq;                                                        \
07103       if( fptr-fbuf >= nbuf || fptr[0] == '\0' ) goto Finished ;          \
07104       str[0]='\0'; qq=sscanf(fptr,"%127s%n",str,&nu); nused+=nu;fptr+=nu; \
07105       if( str[0]=='\0' || qq==0 || nu==0 ) goto Finished ;                \
07106     } while(0)
07107 
07108 #define GETSTR                                                            \
07109   do{ GETSSS ;                                                            \
07110       while(str[0]=='!' || (str[0]=='/' && str[1]=='/') ||                \
07111             (str[0]=='#' && str[1]=='\0') ){EOLSKIP; GETSSS;}             \
07112     } while(0)
07113 
07114 #define GETEQN                                         \
07115   do{ GETSTR ; if(ISTARRED(str)) goto SkipSection ;    \
07116       strcpy(left,str) ;                               \
07117       GETSTR ; if(ISTARRED(str)) goto SkipSection ;    \
07118       strcpy(middle,str) ;                             \
07119       GETSTR ; if(ISTARRED(str)) goto SkipSection ;    \
07120       strcpy(right,str) ; } while(0)
07121 
07122 #define NSBUF 256
07123 
07124 /*--------------------------------------------------------------------------*/
07125 
07126 RENDER_state_array * REND_read_states( char * fname , RENDER_state * rsbase )
07127 {
07128    int    nbuf , nused , ii ;
07129    char * fbuf , * fptr ;
07130    char str[NSBUF] , left[NSBUF] , middle[NSBUF] , right[NSBUF] ;
07131    int ival ; float fval ;
07132    RENDER_state * rs ;
07133    RENDER_state_array * rsa = NULL ;
07134 
07135    /* setup & sanity checks */
07136 
07137    fbuf = AFNI_suck_file( fname ) ; if( fbuf == NULL ) return NULL ;
07138 
07139    nbuf = strlen(fbuf) ; fptr = fbuf ; nused = 0 ;
07140 
07141    /** scan for section strings, which start with "***" **/
07142 
07143    str[0] = '\0' ;  /* initialize string */
07144 
07145    /**----------------------------------------**/
07146    /**-- skip ahead to next section keyword --**/
07147 
07148    SkipSection:
07149       while( ! ISTARRED(str) ){ GETSTR; }
07150       if( strcmp(str,"***END") == 0 ) goto Finished ;
07151 
07152    /*-- the only thing we like are ***RENDER sections --*/
07153 
07154    if( strcmp(str,"***RENDER") != 0 ) goto SkipSection ;
07155 
07156    if( rsa == NULL ){ INIT_RSA(rsa) ; }                     /* create the output array */
07157 
07158    rs = (RENDER_state *) calloc( 1,sizeof(RENDER_state) ) ; /* create the new state */
07159 
07160    if( RSA_COUNT(rsa) == 0 && rsbase != NULL ){
07161       *rs = *rsbase ;                                /* copy base state */
07162    } else if( RSA_COUNT(rsa) > 0 ){
07163       *rs = *(RSA_SUBSTATE(rsa,RSA_COUNT(rsa)-1)) ;  /* copy previous state */
07164    }
07165 
07166    ADDTO_RSA(rsa,rs) ;                               /* put new state in output array */
07167 
07168    /*--- Scan for rendering variable assignments ---*/
07169 
07170 #undef  ASS_IVAL
07171 #define ASS_IVAL(a,b,c) { if( ival >= b && ival <= c ) a = ival ; }
07172 
07173 #undef  ASS_FVAL
07174 #define ASS_FVAL(a,b,c) { if( fval >= b && fval <= c ) a = fval ; }
07175 
07176    while(1){    /* loop, looking for 'name = value' */
07177 
07178       GETEQN ;  /* loop exits when this fails */
07179 
07180       /*-- dataset stuff --*/
07181 
07182       if( strcmp(left,"dset_name") == 0 ){
07183          MCW_strncpy(rs->dset_name,right,THD_MAX_NAME) ;
07184 #if 0
07185          ZERO_IDCODE(rs->dset_idc) ;
07186 #endif
07187          continue ;                                      /* the while(1) loop */
07188       }
07189 
07190       if( strcmp(left,"func_dset_name") == 0 ){
07191          MCW_strncpy(rs->func_dset_name,right,THD_MAX_NAME) ;
07192 #if 0
07193          ZERO_IDCODE(rs->func_dset_idc) ;
07194 #endif
07195          continue ;
07196       }
07197 
07198       if( strcmp(left,"dset_idc") == 0 ){
07199          MCW_strncpy(rs->dset_idc.str,right,MCW_IDSIZE) ;
07200 #if 0
07201          rs->dset_name[0] = '\0' ;
07202 #endif
07203          continue ;
07204       }
07205 
07206       if( strcmp(left,"func_dset_idc") == 0 ){
07207          MCW_strncpy(rs->func_dset_idc.str,right,MCW_IDSIZE) ;
07208 #if 0
07209          rs->func_dset_name[0] = '\0' ;
07210 #endif
07211          continue ;
07212       }
07213 
07214       /*-- cutout stuff --*/
07215 
07216       if( strcmp(left,"cutout_num") == 0 ){
07217          ival = strtol(right,NULL,10) ;
07218          ASS_IVAL( rs->current_cutout_state.num , 0 , MAX_CUTOUTS ) ;
07219          continue ;
07220       }
07221 
07222       if( strcmp(left,"cutout_logic") == 0 ){
07223          if( strcmp(right,"AND")==0 || strcmp(right,"and")==0 || strcmp(right,"And")==0 )
07224             rs->current_cutout_state.logic = CUTOUT_AND ;
07225          else if( strcmp(right,"OR")==0 || strcmp(right,"or")==0 || strcmp(right,"Or")==0 )
07226             rs->current_cutout_state.logic = CUTOUT_OR ;
07227          continue ;
07228       }
07229 
07230       if( strcmp(left,"opacity_scale") == 0 ){
07231          fval = strtod(right,NULL) ;
07232          ASS_FVAL( rs->current_cutout_state.opacity_scale , MIN_OPACITY_SCALE , 1.0 ) ;
07233          continue ;
07234       }
07235 
07236 #define ASS_CUT_TYPE(nnn) \
07237   if( strcmp(right,#nnn) == 0 ){ rs->current_cutout_state.type[iii] = nnn; continue;}
07238 
07239       if( strncmp(left,"cutout_type",strlen("cutout_type")) == 0 ){
07240          char * srb = strstr(left,"[") ;
07241          if( srb != NULL ){
07242             int iii = strtol(srb+1,NULL,10) ;
07243             if( iii >= 0 && iii < MAX_CUTOUTS ){
07244                if( isdigit(right[0]) ){
07245                   ival = strtol(right,NULL,10) ;
07246                   if( ival >= 0 && ival < NUM_CUTOUT_TYPES && ival != CUT_EXPRESSION )
07247                      rs->current_cutout_state.type[iii] = ival ;
07248                } else {
07249                   ASS_CUT_TYPE(CUT_NONE)         ;
07250                   ASS_CUT_TYPE(CUT_RIGHT_OF)     ;
07251                   ASS_CUT_TYPE(CUT_LEFT_OF)      ;
07252                   ASS_CUT_TYPE(CUT_ANTERIOR_TO)  ;
07253                   ASS_CUT_TYPE(CUT_POSTERIOR_TO) ;
07254                   ASS_CUT_TYPE(CUT_INFERIOR_TO)  ;
07255                   ASS_CUT_TYPE(CUT_SUPERIOR_TO)  ;
07256                   ASS_CUT_TYPE(CUT_TT_ELLIPSOID) ;
07257                   ASS_CUT_TYPE(CUT_SLANT_XPY_GT) ;
07258                   ASS_CUT_TYPE(CUT_SLANT_XPY_LT) ;
07259                   ASS_CUT_TYPE(CUT_SLANT_XMY_GT) ;
07260                   ASS_CUT_TYPE(CUT_SLANT_XMY_LT) ;
07261                   ASS_CUT_TYPE(CUT_SLANT_YPZ_GT) ;
07262                   ASS_CUT_TYPE(CUT_SLANT_YPZ_LT) ;
07263                   ASS_CUT_TYPE(CUT_SLANT_YMZ_GT) ;
07264                   ASS_CUT_TYPE(CUT_SLANT_YMZ_LT) ;
07265                   ASS_CUT_TYPE(CUT_SLANT_XPZ_GT) ;
07266                   ASS_CUT_TYPE(CUT_SLANT_XPZ_LT) ;
07267                   ASS_CUT_TYPE(CUT_SLANT_XMZ_GT) ;
07268                   ASS_CUT_TYPE(CUT_SLANT_XMZ_LT) ;
07269                   ASS_CUT_TYPE(CUT_NONOVERLAY)   ;
07270                }
07271             }
07272          }
07273          continue ;
07274       }
07275 
07276       if( strncmp(left,"cutout_mustdo",strlen("cutout_mustdo")) == 0 ){
07277          char * srb = strstr(left,"[") ;
07278          if( srb != NULL ){
07279             int iii = strtol(srb+1,NULL,10) ;
07280             if( iii >= 0 && iii < MAX_CUTOUTS ){
07281                if( strcmp(right,"TRUE") == 0 || strcmp(right,"true") == 0 ||
07282                    strcmp(right,"True") == 0 || strcmp(right,"YES")  == 0 ||
07283                    strcmp(right,"yes")  == 0 || strcmp(right,"Yes")  == 0 ||
07284                    strcmp(right,"1")    == 0   )
07285                   rs->current_cutout_state.mustdo[iii] = 1 ;
07286 
07287                else if( strcmp(right,"FALSE") == 0 || strcmp(right,"false") == 0 ||
07288                         strcmp(right,"False") == 0 || strcmp(right,"NO")    == 0 ||
07289                         strcmp(right,"no")    == 0 || strcmp(right,"No")    == 0 ||
07290                         strcmp(right,"0")     == 0   )
07291                   rs->current_cutout_state.mustdo[iii] = 0 ;
07292             }
07293          }
07294          continue ;
07295       }
07296 
07297       if( strncmp(left,"cutout_param",strlen("cutout_param")) == 0 ){
07298          char * srb = strstr(left,"[") ;
07299          if( srb != NULL ){
07300             int iii = strtol(srb+1,NULL,10) ;
07301             if( iii >= 0 && iii < MAX_CUTOUTS ){
07302                rs->current_cutout_state.param[iii] = strtod(right,NULL) ;
07303             }
07304          }
07305          continue ;
07306       }
07307 
07308       /*-- all other desiderata --*/
07309 
07310 #define ASS_INT(nnn) if( strcmp(left,#nnn) == 0 ){           \
07311                         rs -> nnn = strtol(right,NULL,10) ;  \
07312                         continue ;                           \
07313                      }
07314 
07315 #define ASS_FLOAT(nnn) if( strcmp(left,#nnn) == 0 ){         \
07316                            rs -> nnn = strtod(right,NULL) ;  \
07317                            continue ;                        \
07318                        }
07319 
07320 #define ASS_FLOAT_SUB(nnn,mmm)                                           \
07321    if( strncmp(left,#nnn,strlen(#nnn)) == 0 ){                           \
07322       char * srb = strstr(left,"[") ;                                    \
07323       if( srb != NULL ){                                                 \
07324          int iii = strtol(srb+1,NULL,10) ;                               \
07325          if( iii >= 0 && iii < mmm ) rs->nnn[iii] = strtod(right,NULL) ; \
07326       }                                                                  \
07327       continue ;                                                         \
07328    }
07329 
07330       ASS_INT(dset_ival) ; ASS_INT(func_color_ival) ; ASS_INT(func_thresh_ival) ;
07331 
07332       ASS_INT(clipbot) ; ASS_INT(cliptop) ;
07333 
07334       ASS_FLOAT(angle_roll) ; ASS_FLOAT(angle_pitch) ; ASS_FLOAT(angle_yaw) ;
07335 
07336       ASS_INT(xhair_flag) ;
07337       ASS_INT(xhair_ovc)  ;  /* 08 Mar 2001 */
07338 
07339       ASS_INT(   func_use_autorange ) ;
07340       ASS_FLOAT( func_threshold     ) ;
07341       ASS_FLOAT( func_thresh_top    ) ;
07342       ASS_FLOAT( func_color_opacity ) ;
07343       ASS_INT(   func_see_overlay   ) ;
07344       ASS_INT(   func_see_ttatlas   ) ;  /* 24 Jul 2001 */
07345       ASS_INT(   func_cut_overlay   ) ;
07346       ASS_INT(   func_kill_clusters ) ;
07347       ASS_FLOAT( func_clusters_rmm  ) ;
07348       ASS_FLOAT( func_clusters_vmul ) ;
07349       ASS_FLOAT( func_range         ) ;
07350 
07351       ASS_INT( pbar_mode ) ; ASS_INT( pbar_npane ) ;
07352 
07353       ASS_FLOAT_SUB(pbar_pval,NPANE_MAX+1) ;
07354 
07355 #ifdef SCRIPT_GRAFS
07356       /*-- read graf stuff  --*/
07357 
07358       if( strcmp(left,"bright_nhands") == 0 ){
07359          ival = strtol(right,NULL,10) ;
07360          if( ival > 1 && ival <= MAX_GHANDS ) rs->bright_graf_state.nh = ival ;
07361          continue ;
07362       }
07363 
07364       if( strcmp(left,"bright_spline") == 0 ){
07365          rs->bright_graf_state.spl = strtol(right,NULL,10) ;
07366          continue ;
07367       }
07368 
07369       if( strncmp(left,"bright_handx",strlen("bright_handx")) == 0 ){
07370          char * srb = strstr(left,"[") ;
07371          if( srb != NULL ){
07372             int iii = strtol(srb+1,NULL,10) ;
07373             if( iii >= 0 && iii < MAX_GHANDS ){
07374                rs->bright_graf_state.xh[iii] = strtol(right,NULL,10) ;
07375             }
07376          }
07377          continue ;
07378       }
07379 
07380       if( strncmp(left,"bright_handy",strlen("bright_handy")) == 0 ){
07381          char * srb = strstr(left,"[") ;
07382          if( srb != NULL ){
07383             int iii = strtol(srb+1,NULL,10) ;
07384             if( iii >= 0 && iii < MAX_GHANDS ){
07385                rs->bright_graf_state.yh[iii] = strtol(right,NULL,10) ;
07386             }
07387          }
07388          continue ;
07389       }
07390 
07391       if( strcmp(left,"opacity_nhands") == 0 ){
07392          ival = strtol(right,NULL,10) ;
07393          if( ival > 1 && ival <= MAX_GHANDS ) rs->opacity_graf_state.nh = ival ;
07394          continue ;
07395       }
07396 
07397       if( strcmp(left,"opacity_spline") == 0 ){
07398          rs->opacity_graf_state.spl = strtol(right,NULL,10) ;
07399          continue ;
07400       }
07401 
07402       if( strncmp(left,"opacity_handx",strlen("opacity_handx")) == 0 ){
07403          char * srb = strstr(left,"[") ;
07404          if( srb != NULL ){
07405             int iii = strtol(srb+1,NULL,10) ;
07406             if( iii >= 0 && iii < MAX_GHANDS ){
07407                rs->opacity_graf_state.xh[iii] = strtol(right,NULL,10) ;
07408             }
07409          }
07410          continue ;
07411       }
07412 
07413       if( strncmp(left,"opacity_handy",strlen("opacity_handy")) == 0 ){
07414          char * srb = strstr(left,"[") ;
07415          if( srb != NULL ){
07416             int iii = strtol(srb+1,NULL,10) ;
07417             if( iii >= 0 && iii < MAX_GHANDS ){
07418                rs->opacity_graf_state.yh[iii] = strtol(right,NULL,10) ;
07419             }
07420          }
07421          continue ;
07422       }
07423 #endif /* SCRIPT_GRAFS */
07424 
07425    }  /* end of loop over "equations" in the ***RENDER section */
07426 
07427    /* loop exits when GETEQN fails miserably (i.e., at EOF) */
07428 
07429    Finished:
07430       free(fbuf) ;
07431       if( rsa != NULL && RSA_COUNT(rsa) == 0 ){ FREE_RSA(rsa) ; }
07432       return rsa ;
07433 }
07434 
07435 /*-------------------------------------------------------------------------------
07436   Write a rendering state into a character buffer.
07437   (Free the return value when done with it.)
07438 ---------------------------------------------------------------------------------*/
07439 
07440 #define RSDIFF_STR(nnn) (rsbase == NULL || strcmp(rsbase->nnn,rs->nnn) != 0 )
07441 
07442 #define RSDIFF_NUM(nnn) (rsbase == NULL || rsbase->nnn != rs->nnn)
07443 
07444 #define RSDIFF_CUTNUM(nnn) \
07445   (rsbase == NULL || rsbase->current_cutout_state.nnn != rs->current_cutout_state.nnn)
07446 
07447 #define RSP_STR(nnn)                           \
07448    if( rs->nnn[0] != '\0' && RSDIFF_STR(nnn) ) \
07449       sss = THD_zzprintf( sss , "  " #nnn " = %s\n" , rs->nnn )
07450 
07451 #define RSP_INT(nnn) \
07452    if( RSDIFF_NUM(nnn) ) sss = THD_zzprintf( sss , "  " #nnn " = %d\n" , rs->nnn )
07453 
07454 #define RSP_F2C  AV_format_fval  /* could also be MV_format_fval */
07455 
07456 #define RSP_FLOAT(nnn) \
07457    if( RSDIFF_NUM(nnn) ) sss = THD_zzprintf( sss , "  " #nnn " = %s\n" , RSP_F2C(rs->nnn) )
07458 
07459 char * REND_save_state( RENDER_state * rs , RENDER_state * rsbase )
07460 {
07461    char * sss ;
07462    int ii ;
07463 
07464    if( rs == NULL ) return NULL ;
07465 
07466    sss = (char *) malloc( sizeof(char) * 32 ) ;
07467    strcpy(sss,"\n***RENDER\n") ;
07468 
07469    /* write dataset names */
07470 
07471    RSP_STR(dset_name) ;
07472    RSP_STR(func_dset_name) ;
07473 
07474    /* write dataset ID codes [12 Apr 2000] */
07475 
07476    if( rsbase == NULL || !EQUIV_IDCODES(rsbase->dset_idc,rs->dset_idc) )
07477       if( !ISZERO_IDCODE(rs->dset_idc) )
07478          sss = THD_zzprintf( sss , "  dset_idc = %s\n" , rs->dset_idc.str ) ;
07479 
07480    if( rsbase == NULL || !EQUIV_IDCODES(rsbase->func_dset_idc,rs->func_dset_idc) )
07481       if( !ISZERO_IDCODE(rs->func_dset_idc) )
07482          sss = THD_zzprintf( sss , "  func_dset_idc = %s\n" , rs->func_dset_idc.str ) ;
07483 
07484    /* scalar values */
07485 
07486    RSP_INT(dset_ival) ;
07487    RSP_INT(func_color_ival) ; RSP_INT(func_thresh_ival) ;
07488 
07489    RSP_INT(clipbot) ; RSP_INT(cliptop) ;
07490 
07491    RSP_FLOAT(angle_roll) ; RSP_FLOAT(angle_pitch) ; RSP_FLOAT(angle_yaw) ;
07492 
07493    RSP_INT(xhair_flag) ;
07494    RSP_INT(xhair_ovc) ;  /* 08 Mar 2001 */
07495 
07496    RSP_INT(   func_use_autorange ) ; RSP_FLOAT( func_threshold     ) ;
07497    RSP_FLOAT( func_thresh_top    ) ;
07498    RSP_FLOAT( func_color_opacity ) ; RSP_INT(   func_see_overlay   ) ;
07499    RSP_INT(   func_cut_overlay   ) ; RSP_INT(   func_kill_clusters ) ;
07500    RSP_FLOAT( func_clusters_rmm  ) ; RSP_FLOAT( func_clusters_vmul ) ;
07501    RSP_FLOAT( func_range         ) ;
07502                                      RSP_INT(   func_see_ttatlas   ) ; /* 24 Jul 2001 */
07503 
07504    /* pbar values [all of them if number or mode changed] */
07505 
07506    if( rsbase == NULL ||
07507        rsbase->pbar_mode != rs->pbar_mode || rsbase->pbar_npane != rs->pbar_npane ){
07508 
07509       sss = THD_zzprintf( sss , " // new pbar values\n" ) ;
07510       sss = THD_zzprintf( sss , "  pbar_mode  = %d\n",rs->pbar_mode  ) ;
07511       sss = THD_zzprintf( sss , "  pbar_npane = %d\n",rs->pbar_npane ) ;
07512       for( ii=0 ; ii <= rs->pbar_npane ; ii++ )
07513          sss = THD_zzprintf( sss , "  pbar_pval[%d] = %s\n" ,
07514                              ii , RSP_F2C(rs->pbar_pval[ii]) ) ;
07515    } else {
07516       for( ii=0 ; ii <= rs->pbar_npane ; ii++ )
07517          if( rsbase->pbar_pval[ii] != rs->pbar_pval[ii] )
07518             sss = THD_zzprintf( sss , "  pbar_pval[%d] = %s\n" ,
07519                                 ii , RSP_F2C(rs->pbar_pval[ii]) ) ;
07520    }
07521 
07522    /* cutout stuff */
07523 
07524    if( RSDIFF_NUM(current_cutout_state.opacity_scale) )
07525       sss = THD_zzprintf(sss,"  opacity_scale = %s\n",
07526                          RSP_F2C(rs->current_cutout_state.opacity_scale) ) ;
07527 
07528    /* all cutout parameters if number or global logic changed */
07529 
07530    if( RSDIFF_NUM(current_cutout_state.num) || RSDIFF_NUM(current_cutout_state.logic) ){
07531 
07532       sss = THD_zzprintf( sss , " // new cutout values\n" ) ;
07533       sss = THD_zzprintf( sss , "  cutout_num   = %d\n" , rs->current_cutout_state.num  ) ;
07534       sss = THD_zzprintf( sss , "  cutout_logic = %s\n" ,
07535                           cutout_logic_labels[rs->current_cutout_state.logic]) ;
07536 
07537       for( ii=0 ; ii < rs->current_cutout_state.num ; ii++ ){
07538          sss = THD_zzprintf( sss , "  cutout_type[%d]   = %s\n" ,
07539                              ii ,
07540                              cutout_type_names[rs->current_cutout_state.type[ii]] ) ;
07541 
07542          sss = THD_zzprintf( sss , "  cutout_mustdo[%d] = %s\n" ,
07543                              ii ,
07544                              cutout_mustdo_names[rs->current_cutout_state.mustdo[ii]] ) ;
07545 
07546          sss = THD_zzprintf( sss , "  cutout_param[%d]  = %s\n" ,
07547                              ii , RSP_F2C(rs->current_cutout_state.param[ii]) ) ;
07548       }
07549 
07550    } else {
07551       for( ii=0 ; ii < rs->current_cutout_state.num ; ii++ ){
07552          if( RSDIFF_NUM(current_cutout_state.type[ii]) )
07553             sss = THD_zzprintf( sss , "  cutout_type[%d]   = %s\n" ,
07554                                 ii ,
07555                                 cutout_type_names[rs->current_cutout_state.type[ii]] ) ;
07556 
07557          if( RSDIFF_NUM(current_cutout_state.mustdo[ii]) )
07558             sss = THD_zzprintf( sss , "  cutout_mustdo[%d] = %s\n" ,
07559                                 ii ,
07560                                 cutout_mustdo_names[rs->current_cutout_state.mustdo[ii]] ) ;
07561 
07562          if( RSDIFF_NUM(current_cutout_state.param[ii]) )
07563             sss = THD_zzprintf( sss , "  cutout_param[%d]  = %s\n" ,
07564                                 ii , RSP_F2C(rs->current_cutout_state.param[ii]) ) ;
07565       }
07566    }
07567 
07568 #ifdef SCRIPT_GRAFS
07569    /*-- write graf stuff --*/
07570 
07571    if( rsbase == NULL || !graf_states_equal(&(rsbase->bright_graf_state),&(rs->bright_graf_state)) ){
07572       sss = THD_zzprintf( sss , " // new bright graf values\n" ) ;
07573       sss = THD_zzprintf( sss , "  bright_nhands = %d\n" , rs->bright_graf_state.nh ) ;
07574       sss = THD_zzprintf( sss , "  bright_spline = %d\n" , rs->bright_graf_state.spl) ;
07575       for( ii=0 ; ii < rs->bright_graf_state.nh ; ii++ ){
07576          sss = THD_zzprintf( sss , "  bright_handx[%d] = %d\n" ,
07577                              ii , rs->bright_graf_state.xh[ii]  ) ;
07578          sss = THD_zzprintf( sss , "  bright_handy[%d] = %d\n" ,
07579                              ii , rs->bright_graf_state.yh[ii]  ) ;
07580       }
07581    }
07582 
07583    if( rsbase == NULL || !graf_states_equal(&(rsbase->opacity_graf_state),&(rs->opacity_graf_state)) ){
07584       sss = THD_zzprintf( sss , " // new opacity graf values\n" ) ;
07585       sss = THD_zzprintf( sss , "  opacity_nhands = %d\n" , rs->opacity_graf_state.nh ) ;
07586       sss = THD_zzprintf( sss , "  opacity_spline = %d\n" , rs->opacity_graf_state.spl) ;
07587       for( ii=0 ; ii < rs->opacity_graf_state.nh ; ii++ ){
07588          sss = THD_zzprintf( sss , "  opacity_handx[%d] = %d\n" ,
07589                              ii , rs->opacity_graf_state.xh[ii]  ) ;
07590          sss = THD_zzprintf( sss , "  opacity_handy[%d] = %d\n" ,
07591                              ii , rs->opacity_graf_state.yh[ii]  ) ;
07592       }
07593    }
07594 #endif /* SCRIPT_GRAFS */
07595 
07596    sss = THD_zzprintf( sss , "\n" ) ;
07597    return sss ;
07598 }
07599 
07600 /*------------------------------------------------------------------------------
07601   Copy the internal rendering state to a structure
07602 --------------------------------------------------------------------------------*/
07603 
07604 #define TO_RS(nnn) (rs->nnn = nnn)
07605 
07606 void REND_widgets_to_state( RENDER_state * rs )
07607 {
07608    int ii ;
07609 
07610    if( rs == NULL ) return ;
07611 
07612    /* dataset stuff */
07613 
07614    if( dset != NULL ){
07615       strcpy( rs->dset_name , DSET_HEADNAME(dset) ) ;
07616       rs->dset_idc = dset->idcode ;
07617    } else {
07618       rs->dset_name[0] = '\0' ;
07619       ZERO_IDCODE(rs->dset_idc) ;
07620    }
07621 
07622    if( func_dset != NULL ){
07623       strcpy( rs->func_dset_name , DSET_HEADNAME(func_dset) ) ;
07624       rs->func_dset_idc = func_dset->idcode ;
07625    } else {
07626       rs->func_dset_name[0] = '\0' ;
07627       ZERO_IDCODE(rs->func_dset_idc) ;
07628    }
07629 
07630    /* other scalars */
07631 
07632    TO_RS(dset_ival) ; TO_RS(func_color_ival) ; TO_RS(func_thresh_ival) ;
07633 
07634    rs->clipbot = clipbot_av->ival ;
07635    rs->cliptop = cliptop_av->ival ;
07636 
07637    TO_RS(angle_roll) ; TO_RS(angle_pitch) ; TO_RS(angle_yaw) ;
07638    TO_RS(xhair_flag) ;
07639    TO_RS(xhair_ovc)  ;  /* 08 Mar 2001 */
07640 
07641    if( wfunc_frame != NULL ){
07642 
07643       TO_RS(func_use_autorange) ; TO_RS(func_threshold)     ;
07644       TO_RS(func_thresh_top)    ;
07645       TO_RS(func_color_opacity) ; TO_RS(func_see_overlay)   ;
07646       TO_RS(func_cut_overlay)   ; TO_RS(func_kill_clusters) ;
07647       TO_RS(func_clusters_rmm)  ; TO_RS(func_clusters_vmul) ;
07648       TO_RS(func_range)         ;
07649                                   TO_RS(func_see_ttatlas)   ; /* 24 Jul 2001 */
07650 
07651       /* pbar stuff */
07652 
07653       rs->pbar_mode  = wfunc_color_pbar->mode ;
07654       rs->pbar_npane = wfunc_color_pbar->num_panes ;
07655       for( ii=0 ; ii <= rs->pbar_npane ; ii++ )
07656          rs->pbar_pval[ii] = wfunc_color_pbar->pval[ii] ;
07657    }
07658 
07659    /* cutout stuff */
07660 
07661    REND_load_cutout_state() ; /* save current widget state into cutout state */
07662 
07663    TO_RS(current_cutout_state.opacity_scale) ;
07664 
07665    TO_RS(current_cutout_state.num)   ;
07666    TO_RS(current_cutout_state.logic) ;
07667 
07668    for( ii=0 ; ii < current_cutout_state.num ; ii++ ){
07669       TO_RS( current_cutout_state.type[ii]   ) ;
07670       TO_RS( current_cutout_state.mustdo[ii] ) ;
07671       TO_RS( current_cutout_state.param[ii]  ) ;
07672    }
07673 
07674 #ifdef SCRIPT_GRAFS
07675    graf_state_get( gry_graf , &(rs->bright_graf_state)  ) ;
07676    graf_state_get( opa_graf , &(rs->opacity_graf_state) ) ;
07677 #endif
07678 
07679    return ;
07680 }
07681 
07682 /*------------------------------------------------------------------------------
07683   Copy the structure values to the internal rendering state.
07684   Also must change the visible state of the interface widgets.
07685   In most cases, the widget internal values are set, then their callback
07686   routines are invoked to set the internal rendering state.
07687 --------------------------------------------------------------------------------*/
07688 
07689 #define RSOK(nnn,bb,tt) (rs->nnn != nnn && rs->nnn >= bb && rs->nnn <= tt)
07690 
07691 #define DBI(nnn) fprintf(stderr,#nnn ": rs=%d  wid=%d\n",rs->nnn,nnn)
07692 
07693 void REND_state_to_widgets( RENDER_state * rs )
07694 {
07695    int ii , flag ;
07696    static XtPointer xpt = (XtPointer) "Mr Tambourine Man" ;
07697 
07698    if( rs == NULL ) return ;
07699 
07700    script_dontdraw = 1 ;  /* 24 Nov 2000 */
07701 
07702 #ifdef SCRIPT_DSETS
07703    /* 12 Apr 2000: allow change of dataset! */
07704 
07705    if( script_dsetchange ){
07706       THD_3dim_dataset * qset ;
07707       MCW_choose_cbs cbs ;
07708       char serr[256] ;
07709 
07710       /*- underlay -*/
07711 
07712       if( !ISZERO_IDCODE(rs->dset_idc) ){
07713 
07714          if( dset == NULL || !EQUIV_IDCODES(rs->dset_idc,dset->idcode) ){
07715 fprintf(stderr,"++ Changing underlay dataset to %s\n",rs->dset_idc.str) ;
07716             qset = PLUTO_find_dset( &(rs->dset_idc) ) ;
07717             if( !ISVALID_DSET(qset) ){
07718                sprintf(serr, " \n"
07719                              "** Can't find desired\n"
07720                              "** underlay dataset:\n"
07721                              "** %s\n" , rs->dset_idc.str ) ;
07722                (void) MCW_popup_message( script_cbut , serr ,
07723                                          MCW_USER_KILL | MCW_TIMER_KILL   ) ;
07724                PLUTO_beep() ;
07725 fprintf(stderr,"** Couldn't find new underlay dataset!\n") ;
07726             } else {
07727                ndsl = 1 ;
07728                dsl = (PLUGIN_dataset_link *)
07729                        XtRealloc( (char *)dsl, sizeof(PLUGIN_dataset_link)*ndsl );
07730                make_PLUGIN_dataset_link( qset , dsl ) ;
07731                cbs.ival = 0 ;
07732                REND_finalize_dset_CB( NULL , NULL , &cbs ) ;
07733             }
07734          }
07735       }
07736 
07737       /*- overlay -*/
07738 
07739       if( !ISZERO_IDCODE(rs->func_dset_idc) && dset != NULL ){
07740 
07741          if( func_dset == NULL ||
07742              !EQUIV_IDCODES(rs->func_dset_idc,func_dset->idcode) ){
07743 fprintf(stderr,"++ Changing overlay dataset to %s\n",rs->func_dset_idc.str) ;
07744             qset = PLUTO_find_dset( &(rs->func_dset_idc) ) ;
07745             if( !ISVALID_DSET(qset) ){
07746                sprintf(serr, " \n"
07747                              "** Can't find desired\n"
07748                              "** overlay dataset:\n"
07749                              "**  %s\n" , rs->func_dset_idc.str ) ;
07750                (void) MCW_popup_message( script_cbut , serr ,
07751                                          MCW_USER_KILL | MCW_TIMER_KILL   ) ;
07752                PLUTO_beep() ;
07753 fprintf(stderr,"** Couldn't find new overlay dataset!\n") ;
07754             } else if( DSET_NX(dset) != DSET_NX(qset) ||
07755                        DSET_NY(dset) != DSET_NY(qset) ||
07756                        DSET_NZ(dset) != DSET_NZ(qset) ){
07757                sprintf(serr," \n"
07758                             "** Desired overlay dataset:\n"
07759                             "**  %s\n"
07760                             "** doesn't match underlay\n"
07761                             "** dataset's dimensions!\n", rs->func_dset_idc.str );
07762                (void) MCW_popup_message( script_cbut , serr ,
07763                                          MCW_USER_KILL | MCW_TIMER_KILL   ) ;
07764                PLUTO_beep() ;
07765 fprintf(stderr,"** New overlay dataset doesn't match underlay dimensions!\n") ;
07766             } else {
07767                ndsl = 1 ;
07768                dsl = (PLUGIN_dataset_link *)
07769                        XtRealloc( (char *)dsl,sizeof(PLUGIN_dataset_link)*ndsl );
07770                make_PLUGIN_dataset_link( qset , dsl ) ;
07771                cbs.ival = 0 ;
07772 
07773                if( wfunc_frame == NULL || !XtIsManaged(wfunc_frame) )
07774                   REND_open_func_CB(NULL,NULL,NULL) ;
07775 
07776                REND_finalize_func_CB( NULL , NULL , &cbs ) ;
07777             }
07778          }
07779       }
07780    }
07781 #endif /* SCRIPT_DSETS */
07782 
07783    /* change the sub-values in the dataset (maybe?) */
07784 
07785    if( script_brindex ){
07786       if( dset != NULL && RSOK(dset_ival,0,DSET_NVALS(dset)-1) ){
07787          AV_assign_ival( choose_av , rs->dset_ival ) ;
07788          REND_choose_av_CB( choose_av , xpt ) ;
07789       }
07790 
07791       if( func_dset != NULL && RSOK(func_color_ival,0,DSET_NVALS(func_dset)-1) ){
07792          AV_assign_ival( wfunc_color_av , rs->func_color_ival ) ;
07793          REND_choose_av_CB( wfunc_color_av , xpt ) ;
07794       }
07795 
07796       if( func_dset != NULL && RSOK(func_thresh_ival,0,DSET_NVALS(func_dset)-1) ){
07797          AV_assign_ival( wfunc_thresh_av , rs->func_thresh_ival ) ;
07798          REND_choose_av_CB( wfunc_thresh_av , xpt ) ;
07799       }
07800    }
07801 
07802 #ifdef SCRIPT_GRAFS
07803    /* change grafs (maybe?) */
07804 
07805    if( script_graf ){
07806       graf_state gs ;
07807 
07808       graf_state_get( gry_graf , &gs ) ;
07809       if( ! graf_states_equal( &(rs->bright_graf_state) , &gs ) ){
07810          FREE_VOLUMES ;
07811          graf_state_put( gry_graf , &(rs->bright_graf_state) ) ;
07812       }
07813 
07814       graf_state_get( opa_graf , &gs ) ;
07815       if( ! graf_states_equal( &(rs->opacity_graf_state) , &gs ) ){
07816          FREE_VOLUMES ;
07817          graf_state_put( opa_graf , &(rs->opacity_graf_state) ) ;
07818       }
07819    }
07820 #endif /* SCRIPT_GRAFS */
07821 
07822    /* change clipping values */
07823 
07824    if( rs->clipbot != clipbot_av->ival ){
07825       AV_assign_ival( clipbot_av , rs->clipbot ) ;
07826       REND_clip_CB( clipbot_av , NULL ) ;
07827    }
07828 
07829    if( rs->cliptop != cliptop_av->ival ){
07830       AV_assign_ival( cliptop_av , rs->cliptop ) ;
07831       REND_clip_CB( cliptop_av , NULL ) ;
07832    }
07833 
07834    /* change angles */
07835 
07836    if( RSOK(angle_roll,-359.9,719.9) ){
07837       AV_assign_fval( roll_av , rs->angle_roll ) ;
07838       REND_angle_CB ( roll_av , xpt ) ;            /* will set angle_roll */
07839    }
07840    if( RSOK(angle_pitch,-359.9,719.9) ){
07841       AV_assign_fval( pitch_av , rs->angle_pitch ) ;
07842       REND_angle_CB ( pitch_av , xpt ) ;           /* will set angle_pitch */
07843    }
07844    if( RSOK(angle_yaw,-359.9,719.9) ){
07845       AV_assign_fval( yaw_av , rs->angle_yaw ) ;
07846       REND_angle_CB ( yaw_av , xpt ) ;             /* will set angle_yaw */
07847    }
07848 
07849    /* change xhair mode */
07850 
07851    if( RSOK(xhair_flag,0,1) ){
07852       xhair_flag = rs->xhair_flag ;
07853       MCW_set_bbox( xhair_bbox , xhair_flag ) ;
07854    }
07855 
07856    if( RSOK(xhair_ovc,0,dc->ovc->ncol_ov) ){  /* 08 Mar 2001 */
07857       xhair_ovc = rs->xhair_ovc ;
07858    }
07859 
07860    /* change function stuff, if the functional widgets exist */
07861 
07862    if( wfunc_frame != NULL ){
07863 
07864       { static float dval[9] = { 1.0 , 10.0 , 100.0 , 1000.0 , 10000.0 ,
07865                                  100000.0 , 1000000.0 , 10000000.0 , 100000000.0 } ;
07866 
07867         if( RSOK(func_thresh_top,1.0,dval[THR_TOP_EXPON]) ){
07868            for( ii=THR_TOP_EXPON ; ii > 0 ; ii-- )
07869               if( rs->func_thresh_top >= dval[ii] ) break ;
07870 
07871            AV_assign_ival( wfunc_thr_top_av , ii ) ;
07872            REND_thresh_top_CB( wfunc_thr_top_av , NULL ) ;
07873         }
07874       }
07875 
07876       if( RSOK(func_threshold,0.0,0.9999) ){
07877          XmScaleCallbackStruct cbs ;
07878          cbs.value = (int)( rs->func_threshold / THR_FACTOR + 0.01 ) ;
07879          REND_thr_scale_CB( NULL,NULL , &cbs ) ;
07880          XmScaleSetValue( wfunc_thr_scale , cbs.value ) ;  /* oops, forgot this! 12 Apr 2000 */
07881       }
07882 
07883       if( RSOK(func_color_opacity,0.0,1.201) ){  /* 11 Sep 2001: add ST+Dcue=12 */
07884          ii = (int)(rs->func_color_opacity * 10.0 + 0.01) ;
07885          AV_assign_ival( wfunc_opacity_av , ii ) ;
07886          REND_color_opacity_CB( wfunc_opacity_av , NULL ) ;
07887       }
07888 
07889       if( RSOK(func_see_overlay,0,1) ){
07890          MCW_set_bbox( wfunc_see_overlay_bbox , rs->func_see_overlay ) ;
07891          REND_see_overlay_CB(NULL,NULL,NULL) ;
07892       }
07893 
07894       if( RSOK(func_see_ttatlas,0,1) ){  /* 24 Jul 2001 */
07895          MCW_set_bbox( wfunc_see_ttatlas_bbox , rs->func_see_ttatlas ) ;
07896          REND_see_ttatlas_CB(NULL,NULL,NULL) ;
07897       }
07898 
07899       if( RSOK(func_cut_overlay,0,1) ){
07900          MCW_set_bbox( wfunc_cut_overlay_bbox , rs->func_cut_overlay ) ;
07901          REND_cut_overlay_CB(NULL,NULL,NULL) ;
07902       }
07903 
07904       if( RSOK(func_kill_clusters,0,1) ){
07905          MCW_set_bbox( wfunc_kill_clusters_bbox , rs->func_kill_clusters ) ;
07906          REND_kill_clusters_CB(NULL,NULL,NULL) ;
07907       }
07908 
07909       if( RSOK(func_clusters_rmm,0,99) ){
07910          AV_assign_fval( wfunc_clusters_rmm_av , rs->func_clusters_rmm ) ;
07911          REND_clusters_av_CB(wfunc_clusters_rmm_av,xpt) ;
07912       }
07913 
07914       if( RSOK(func_clusters_vmul,0,9999) ){
07915          AV_assign_fval( wfunc_clusters_vmul_av , rs->func_clusters_vmul ) ;
07916          REND_clusters_av_CB(wfunc_clusters_vmul_av,xpt) ;
07917       }
07918 
07919       if( RSOK(func_use_autorange,0,1) ){
07920          MCW_set_bbox( wfunc_range_bbox , rs->func_use_autorange ) ;
07921          REND_range_bbox_CB(NULL,NULL,NULL) ;
07922       }
07923 
07924       if( RSOK(func_range,0,9999999) ){
07925          AV_assign_fval( wfunc_range_av , rs->func_range ) ;
07926          REND_range_av_CB(wfunc_range_av,xpt) ;
07927       }
07928 
07929       /* pbar stuff */
07930 
07931       if( rs->pbar_mode != wfunc_color_pbar->mode ){
07932          MCW_set_bbox( wfunc_color_bbox , rs->pbar_mode ) ;
07933          REND_color_bbox_CB(NULL,NULL,NULL) ;
07934       }
07935 
07936       if( rs->pbar_npane != wfunc_color_pbar->num_panes ){
07937          AV_assign_ival( wfunc_colornum_av , rs->pbar_npane ) ;
07938          REND_colornum_av_CB( wfunc_colornum_av , NULL ) ;
07939       }
07940 
07941       for( flag=ii=0 ; ii <= rs->pbar_npane ; ii++ ){
07942          if( rs->pbar_pval[ii] != wfunc_color_pbar->pval[ii] ) flag++ ;
07943       }
07944       if( flag ){
07945          alter_MCW_pbar( wfunc_color_pbar , 0 , rs->pbar_pval ) ;
07946          INVALIDATE_OVERLAY ;
07947       }
07948    }
07949 
07950    /* load cutout stuff into widgets */
07951 
07952    REND_load_cutout_state() ; /* save current widget state into cutout state */
07953 
07954    if( RSOK(current_cutout_state.opacity_scale,0.0,1.0) ){
07955       AV_assign_fval( opacity_scale_av , rs->current_cutout_state.opacity_scale ) ;
07956       REND_opacity_scale_CB( opacity_scale_av , xpt ) ;
07957    }
07958 
07959    if( RSOK(current_cutout_state.num,0,MAX_CUTOUTS) ){
07960       AV_assign_ival( numcutout_av , rs->current_cutout_state.num ) ;
07961       REND_numcutout_CB( numcutout_av , xpt ) ;
07962    }
07963 
07964    if( RSOK(current_cutout_state.logic,0,1) ){
07965       AV_assign_ival( logiccutout_av , rs->current_cutout_state.logic ) ;
07966       FREE_VOLUMES ;
07967    }
07968 
07969    for( ii=0 ; ii < num_cutouts ; ii++ ){
07970 
07971       if( RSOK(current_cutout_state.type[ii],0,NUM_CUTOUT_TYPES-1) ){
07972          AV_assign_ival( cutouts[ii]->type_av , rs->current_cutout_state.type[ii] ) ;
07973          REND_cutout_type_CB( cutouts[ii]->type_av , xpt ) ;
07974       }
07975 
07976       if( RSOK(current_cutout_state.mustdo[ii],0,1) ){
07977          MCW_set_bbox( cutouts[ii]->mustdo_bbox , rs->current_cutout_state.mustdo[ii] ) ;
07978       }
07979 
07980       if( RSOK(current_cutout_state.param[ii],-999999,999999) ){
07981          AV_assign_fval( cutouts[ii]->param_av , rs->current_cutout_state.param[ii] ) ;
07982       }
07983    }
07984 
07985    REND_load_cutout_state() ; /* save current widget state into cutout state */
07986 
07987    script_dontdraw = 0 ;  /* 24 Nov 2000 */
07988 
07989    return ;
07990 }
07991 
07992 #endif /* USE_SCRIPTING */
07993 
07994 /*-------------------------------------------------------------------------
07995    When a registered environment variable is changed, this
07996    function will be called - 20 Jun 2000!
07997 ---------------------------------------------------------------------------*/
07998 
07999 void REND_environ_CB( char * ename )
08000 {
08001    char * ept ;
08002    float val ;
08003 
08004    /* sanity checks */
08005 
08006    if( ename == NULL ) return ;
08007    ept = getenv(ename) ;
08008    if( ept == NULL ) return ;
08009 
08010    /*---*/
08011 
08012    if( strcmp(ename,"AFNI_RENDER_ANGLE_DELTA") == 0 ){
08013       float val = strtod(ept,NULL) ;
08014       if( val > 0.0 && val < 100.0 ){
08015          angle_fstep = val ;
08016          if( shell != NULL )
08017             roll_av->fstep = pitch_av->fstep = yaw_av->fstep = val ;
08018       }
08019    }
08020 
08021    /*---*/
08022 
08023    else if( strcmp(ename,"AFNI_RENDER_CUTOUT_DELTA") == 0 ){
08024       float val = strtod(ept,NULL) ;
08025       if( val > 0.0 && val < 100.0 ){
08026          int ii ;
08027          cutout_fstep = val ;
08028          if( shell != NULL ){
08029             for( ii=0 ; ii < MAX_CUTOUTS ; ii++ )
08030                cutouts[ii]->param_av->fstep = val ;
08031          }
08032       }
08033    }
08034 
08035    /*---*/
08036 
08037    return ;
08038 }
08039 
08040 /*==========================================================================*/
08041 #ifdef ALLOW_INCROT   /* 26 Apr 2002 - RWCox */
08042 
08043 /*--------------------------------------------------------------------------*/
08044 /*! Compute the changes in the rotation angles if we add
08045     an incremental rotation about axis ax (0,1,2) of size th.
08046 ----------------------------------------------------------------------------*/
08047 
08048 static void REND_inc_angles( int ax, float th,
08049                              float *yaw, float *pitch, float *roll )
08050 {
08051    double a,b,c ;
08052    THD_dmat33 qq , rr , pp ;
08053 
08054    a = *yaw ; b = *pitch ; c = *roll ;           /* fetch input angles */
08055    qq = REND_rotmatrix( 1,a , 0,b , 2,c ) ;      /* compute matrix from angles */
08056 
08057    LOAD_ROT_MAT(rr,th,ax) ;                      /* incremental rotation */
08058 
08059    pp = DMAT_MUL(rr,qq) ;                        /* total rotation matrix */
08060    REND_rotmatrix_to_angles( pp , &a,&b,&c ) ;   /* get angles from this */
08061    *yaw = a ; *pitch = b ; *roll = c ;           /* store angles */
08062    return ;
08063 }
08064 
08065 /*--------------------------------------------------------------------------*/
08066 /*! Compute a rotation matrix. */
08067 
08068 static THD_dmat33 REND_rotmatrix( int ax1,double th1 ,
08069                                   int ax2,double th2 , int ax3,double th3  )
08070 {
08071    THD_dmat33 q , p ;
08072 
08073    LOAD_ROT_MAT( q , th1 , ax1 ) ;
08074    LOAD_ROT_MAT( p , th2 , ax2 ) ; q = DMAT_MUL( p , q ) ;
08075    LOAD_ROT_MAT( p , th3 , ax3 ) ; q = DMAT_MUL( p , q ) ;
08076 
08077    return q ;
08078 }
08079 
08080 /*-----------------------------------------------------------------------*/
08081 /*! Compute yaw=a, pitch=b, roll=c, given rotation matrix in form below:
08082 
08083                          [cc ca + sc sb sa     sc cb    -cc sa + sc sb ca]
08084                          [                                               ]
08085  Rz(c) * Rx(b) * Ry(a) = [-sc ca + cc sb sa    cc cb    sc sa + cc sb ca ]
08086                          [                                               ]
08087                          [      cb sa           -sb           cb ca      ]
08088 
08089   - pitch will be between PI/2 and 3*PI/2.
08090   - this function only works if ax1=1, ax2=0, ax3=2 (the defaults)
08091 -------------------------------------------------------------------------*/
08092 
08093 static void REND_rotmatrix_to_angles( THD_dmat33 q,
08094                                       double *yaw, double *pitch, double *roll )
08095 {
08096    double a,b,c ;
08097    double sb,cb , sa,ca , sc,cc ;
08098 
08099    sb = -q.mat[2][1] ; b = PI-asin(sb) ; cb = cos(b) ;
08100 
08101    if( fabs(cb) < 0.001 ){  /* singular case */
08102       a  = 0 ;
08103       cc = q.mat[0][0] ;
08104       sc = q.mat[0][2] ; if( sb < 0.0 ) sc = -sc ;
08105       c  = atan2( sc , cc ) ;
08106    } else {
08107       a = atan2( -q.mat[2][0] , -q.mat[2][2] ) ;
08108       c = atan2( -q.mat[0][1] , -q.mat[1][1] ) ;
08109    }
08110 
08111    if( a < 0 ) a += 2.0*PI ;
08112    if( c < 0 ) c += 2.0*PI ;
08113 
08114    *yaw = a ; *pitch = b ; *roll = c ; return ;
08115 }
08116 #endif /* ALLOW_INCROT */
08117 /*==========================================================================*/
 

Powered by Plone

This site conforms to the following standards: