Skip to content
Snippets Groups Projects
partibrains.c 202 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifdef __cplusplus
    extern "C" {	// in case someone feeds this to the C++ compiler,...
    #endif
    
    
    slevy's avatar
     
    slevy committed
    static char local_id[] = "$Id$";
    
    slevy's avatar
    slevy committed
    static char copyright[] = "Copyright (c) 2002 NCSA, University of Illinois Urbana-Champaign";
    
    
    /*
     * Brains of partiview: carrying and displaying data, parsing commands.
     * Stuart Levy, slevy@ncsa.uiuc.edu
     * National Center for Supercomputing Applications,
     * University of Illinois 2001.
    
    slevy's avatar
    slevy committed
     * This file is part of partiview, released under the
     * Illinois Open Source License; see the file LICENSE.partiview for details.
    
    slevy's avatar
     
    slevy committed
    /*
     * $Log$
    
     * Revision 1.113  2005/06/13 18:12:07  slevy
     * Fix long-standing bug where polygons would get the wrong orientation
     * if some were fixed-oriented and others screen-facing.
     * Portability tweak from Toshi -- be even more pessimistic about stack size.
     *
    
     * Revision 1.112  2005/02/08 20:10:59  slevy
     * Force using oldopengl (no glInterleavedArrays()/glDrawElements()) on MacOS X --
     * it seems to get the data completely wrong (most X's = 0, etc.).
     * If someone ever figures out why, I'd be curious to know.
     *
    
     * Revision 1.111  2004/10/19 01:52:27  slevy
     * Give specks_ieee_server() the right type to be an sproc function.
     * Need config.h early.
     * Initialize "oldopengl".
     * More digits for "where".
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.110  2004/10/06 05:35:19  slevy
     * Add 3-D texturing.
     *
    
     * Revision 1.109  2004/07/26 16:44:50  slevy
     * specks_set_byvariable() now correctly fails on 0-length names.
     *
    
     * Revision 1.108  2004/07/26 04:33:01  slevy
     * Use vertex arrays for drawing points, if available.
     * Allow dyndata processors to switch themselves off with st->dyn.enabled = -1.
     *
    
     * Revision 1.107  2004/07/23 20:57:12  slevy
     * Move alloca boilerplate (ugh) earlier.
     * Use HAVE_SQRTF.
     *
    
     * Revision 1.106  2004/07/06 23:06:22  slevy
     * Make use of multiple timesteps even if we have a dyndata handler.
     *
    
     * Revision 1.105  2004/04/19 21:04:12  slevy
     * Un-CONST-ify most of what had been constified.  It's just too messy.
     *
    
     * Revision 1.104  2004/04/19 17:42:42  slevy
     * Use AC_FUNC_ALLOCA and the autoconf-standard alloca boilerplate
     * in each of the files that uses alloca.
     *
    
     * Revision 1.103  2004/04/12 19:09:54  slevy
     * Crank up default specular highlights.
     * CONSTify getfloats().
     *
    
     * Revision 1.102  2004/01/14 02:03:41  slevy
     * Add Chromatek color-coding of depth, contributed by Carl Hultquist
     * (chultquist@smuts.uct.ac.za, student of Anthony Fairall), as part of his
     * Computer Science Honours project.  Works with Chromatek glasses,
     * which make red things look nearby, blue things far away.
     * New commands:
     *    chromadepth {on|off}
     * 	replaces colors of points and polygons with depth-coded colors
     *    chromaparams ZSTART ZRANGE
     * 	sets Z-range (distance from camera plane) over which
     * 	colormapping applies.  Z=ZSTART maps to first entry,
     * 	Z=ZSTART+ZRANGE maps to last entry in colormap.
     *    chromacmap  FILE.CMAP
     * 	Specifies colormap.
     * See example files data/chromadepth.cmap and data/hipchroma.
     *
    
     * Revision 1.101  2004/01/09 13:32:06  slevy
     * Parse lum command correctly again...
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.100  2004/01/09 04:54:46  slevy
     * Add lum options:
     *    "all"  - revert to autoranging
     *    "abs [base]"  - lum = scalefactor * abs(value - base)
     *    "lin"  - default behavior (unsets any "abs")
     *
    
     * Revision 1.99  2003/12/10 19:38:05  slevy
     * Add "pb" datacommand to read partadv-style .pb files.  Finally, a general-purpose
     * binary particle format!
     *
    
     * Revision 1.98  2003/11/03 17:06:55  smarx
     * small additions/changes to make os x and windows buildable and functional. open issues on windows time motion widgets and terminating cleanly.
     *
    
     * Revision 1.97  2003/10/26 16:20:22  slevy
     * Merge Steve Marx's many improvements -- generic slider,
     * MacOS X port, "home" command/button, lots of bug fixes -- into main branch!
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.96  2003/10/25 00:42:52  slevy
     * Add "echo" data+control command.
     * Try to add pthread-based USE_IEEEIO.  Don't know if this works yet,
     * but it compiles.
     *
    
     * Revision 1.95  2003/09/30 08:44:37  slevy
     * Make waveobj accept objects made of line segments.
    
     * Revision 1.94.2.1  2003/05/15 14:58:57  smarx
     * rel_0_7_04 upgrades to fltk-1.1.3, build support for os x, os x middle mouse button keyboard simulation, os x workaround for partiview/fltk issues with proper redraw. this release is using a recent fltk-1.1.3 cvs upgrade - not the standard release - to resolve OpenGL bugs that will be in fltk-1.1.4. Note that this release of partiview requires fltk-1.1.x support which precludes use of the old file chooser
    
     * Revision 1.94  2003/02/15 06:55:57  slevy
     * Add "slvalid" flag to struct dyndata.  Don't just use currealtime as
     * the validity test.
     *
    
     * Revision 1.93  2002/10/04 00:50:21  slevy
     * Fix CAVE-text-alignment hack for non-CAVE case.
     *
    
     * Revision 1.92  2002/10/02 07:00:04  slevy
     * Change text orientation in THIEBAUX_VIRDIR (often multipipe CAVE)
     * mode.  Rather than having text be oriented per-graphics-window,
     * we choose the orientation of the master pipe.
     *
    
     * Revision 1.91  2002/07/20 15:53:03  slevy
     * Make wavefront .obj models work with (or without) texture coordinates
     * and/or vertex normals.
     *
    
     * Revision 1.90  2002/07/20 05:03:39  slevy
     * Support textures and per-vertex normals from "waveobj" files.
     *
    
     * Revision 1.89  2002/07/10 22:51:59  slevy
     * Allow ``only= field > value'' etc.
     *
    
     * Revision 1.88  2002/06/18 21:43:52  slevy
     * Report copyright when "version" requested.
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.87  2002/06/18 21:24:36  slevy
     * Add copyright string.
     * Add Illinois-open-source-license reference to LICENSE.partiview file.
     *
    
     * Revision 1.86  2002/06/05 01:13:31  slevy
     * Ha -- when reading tfm's, remember to initialize has_scl!
     *
    
     * Revision 1.85  2002/06/04 23:06:07  slevy
     * Use parti_idof(), not parti_object( NULL, &st, 0 ), to turn object into id.
     *
    
     * Revision 1.84  2002/04/22 17:58:49  slevy
     * Allow "w" option to "bound" command: compute bounding box in world
     * instead of object coordinates.
     *
    
     * Revision 1.83  2002/04/17 20:47:58  slevy
     * Add a not-quite-proprietary notice to all source files.
     * Once we pick a license this might change, but
     * in the mean time, at least the NCSA UIUC origin is noted.
     *
    
     * Revision 1.82  2002/04/16 18:40:26  slevy
     * Move tokenize() and rejoinargs() into findfile.c,
     * and out of this overstuffed piece of junk.
     *
    
     * Revision 1.81  2002/04/12 05:50:20  slevy
     * Fix (?) "only=" etc. commands, broken since I added the selection stuff last July!
     *
    
     * Revision 1.80  2002/03/31 22:40:32  slevy
     * "tfm" command -- only print full matrices if "tfm -v" given,
     * otherwise just x y z rx ry rz scale; print matrices in %g format for
     * full precision; accept 7th parameter as scale factor on input
     * just as we print it on output.
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.79  2002/03/14 18:14:58  slevy
     * Peel out a bit more CAVE code,
     * and refer specifically to Marcus Thiebaux's virdir
     * since there's now also a Matt Hall version.
     *
    
     * Revision 1.78  2002/03/14 04:54:09  slevy
     * Strip out a bunch of virdir-specific CAVE menu clutter,
     * now moved into partimenu.c.
     *
    
     * Revision 1.77  2002/03/11 22:31:23  slevy
     * Move virdir-specific parti_seto2w() and specks_display() to partiview.cc.
     * "rawdata -a" particle-dump includes position, color, brightness too.
     *
    
     * Revision 1.76  2002/02/02 04:13:07  slevy
     * Unless PARTIMENU explicitly set, just get rid of the blasted menus.
     *
    
     * Revision 1.75  2002/01/27 00:38:19  slevy
     * Add "setenv name value" data command.
     *
    
     * Revision 1.74  2002/01/23 03:56:34  slevy
     * Add "timealign", "skipblanktimes" commands.
     * Default change: no longer skip blank times!
     * Per-data time ranges now extend overall clock range,
     * don't replace it.
     * Reset material properties (shininess, specular, ambient)
     * when drawing a lighted mesh.
     *
    
     * Revision 1.73  2001/12/28 07:23:57  slevy
     * Move plugins (kira, warp, ieeeio) off to separate source files.
     * "where" command gives full-precision values, and reports jump-pos with scale.
     * Allow for model-specific render function (initially for Maya models).
     * env TXDEBUG.
     *
    
     * Revision 1.72  2001/11/09 05:27:53  slevy
     * In specks_set_timestep(), don't set clock's range if we only have
     * a single timestep ourselves!
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.71  2001/11/08 06:32:52  slevy
     * Extract async code into async.c.
     * Add pointsize metering, normally #ifdef USE_PTRACK'ed out.
     *
    
     * Revision 1.70  2001/11/06 06:20:30  slevy
     * Centralize test for nonempty timestep slot: specks_nonempty_timestep().
     * Fix tokenize() for case of "quoted" or 'quoted' arg strings.
     *
    
     * Revision 1.69  2001/10/19 17:48:51  slevy
     * Don't leak FILE in specks_read_waveobj().
     *
    
     * Revision 1.68  2001/08/29 17:54:00  slevy
     * Make rejoinargs() work robustly -- use a private static malloced area,
     * don't overwrite args in memory.
     *
    
     * Revision 1.67  2001/08/28 18:27:34  slevy
     * Remove lots of unused variables.  Move some used only in CAVE code
     * inside #ifdef brackets.
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.66  2001/08/28 02:05:22  slevy
     * Fix format string usage.
     *
    
     * Revision 1.65  2001/08/26 17:40:04  slevy
     * Bounds-check all references to st->meshes[][], st->annot[][], etc. --
     * all those maintained by specks_timespecksptr.  We no longer guarantee
     * that st->curtime is always in range 0..st->ntimes-1, so just yield NULL
     * for out-of-range references.  New CURDATATIME(fieldname) does it.
     *
    
     * Revision 1.64  2001/08/26 02:10:40  slevy
     * "color rgb ..." sets colors of otherwise-uncolored mesh objects.
     * Only call parti_parse_args() if non-CAVE.
     *
    
     * Revision 1.63  2001/08/24 01:02:38  slevy
     * Add polygonal meshes -- wavefront .obj models.
     *
    
     * Revision 1.62  2001/08/16 19:58:56  slevy
     * Pull non-specks-specific code out of partibrains.c
     * and into partiview.cc, using new parti_add_commands hook.
     *
    
     * Revision 1.61  2001/08/16 17:23:41  slevy
     * New parti_parse_args() for generic add-on commands.
     * "where" prints more information.
     *
    
     * Revision 1.60  2001/07/19 20:10:23  slevy
     * st->threshsel is now kept as a SEL_DEST.
     * Fix seldest2src(), not even wrong.
     * Use specks_reupdate() after changing thresh, so the reported
     * selcount should be right.
     * specks_rethresh(): keep track of whether anything changed,
     * and increment st->selseq if so.
     *
    
     * Revision 1.59  2001/07/18 19:24:57  slevy
     * parse_selexpr() returns bit-encoded value saying whether src or dest or
     * both were filled in.
     *
    
     * Revision 1.58  2001/07/17 17:28:08  slevy
     * Increase MAXPTSIZE to allow bigger dots!
     *
    
     * Revision 1.57  2001/07/16 17:58:37  slevy
     * Don't take spurious snapshot if "snapset" command gets -... args.
     * Revert to compatible texture behavior: texture -A is again the default,
     * use texture -O for "over"-style blending.
     *
    
     * Revision 1.56  2001/07/15 23:09:46  slevy
     * Um, let "wanted == 0" and SEL_USE indicate that we want to match all pcles.
     *
    
     * Revision 1.55  2001/07/15 22:55:14  slevy
     * Er, those 'leadc' parameters to seldest()/selsrc() are ints, not SelTokens.
     *
    
     * Revision 1.54  2001/07/12 21:42:25  slevy
     * Use new selcounts() function to report stats whenever we mention a SelOp.
     * ``sel <src>'' alone now works too, to just report match count.
     *
    
     * Revision 1.53  2001/07/10 17:18:05  slevy
     * threshsel is a src, not a dest-type SelOp.
     *
    
     * Revision 1.52  2001/07/09 23:46:56  slevy
     * A bit more ripening of selection system...
     * And, report match counts from "sel", "thresh", "emph".
     *
    
     * Revision 1.51  2001/07/07 15:35:49  slevy
     * Implement more (most?) of selection framework:
     *     selsrc(), seldest(), selname(), seltoken().
     * "thresh" now accepts "-s 'destexpr'".
     * Add new selthresh SelOp.
     *
    
     * Revision 1.50  2001/07/04 03:44:12  slevy
     * Add framework of set-selection stuff; not really usable yet.
     * Next: implement "see" in drawspecks().
     * Add "picked" callback which gets notified of all pick results.
     *
    
     * Revision 1.49  2001/06/30 18:14:22  slevy
     * Provide for storing another bit in rgba alpha field: EMPHBIT, for
     * emphasis tag.
     * Use new sfStrDrawTJ (with transform & justification) for text.
     * Yeow, handle polymax properly -- default == infinity!
     * Add "vcmap" for per-datafield colormaps.
     * Enable GL_SMOOTH mode to get texture colors to work right (huh? why do we need to?).
     * "tfm c"/"tfm w" choose cam vs. world (default) location for object tfms.
     *
    
     * Revision 1.48  2001/05/30 14:32:55  slevy
     * Add subcameras ("subcam" command).
     * popen() needs "r" not "rb" -- no such thing as binary mode.
     * kira_open() gets original filename if we can't find it, for error messaging.
     *
    
     * Revision 1.47  2001/05/15 12:18:57  slevy
     * New interface to dynamic-data routines.
     * Now, the only #ifdef KIRA/WARP needed in partibrains.c are
     * the data-command initialization routines.  All others,
     * including control-command parsing and specialized drawing,
     * is now via a function table.
     *
    
     * Revision 1.46  2001/05/14 15:51:34  slevy
     * Initialize new speckseq value whenever we make a new specklist.
     * Put colorseq/sizeseq/threshseq invalidation in kira_parti, not here,
     * since we needn't do it when warping.
     * By default, clock range is whatever it had been set to before.
     *
    
     * Revision 1.45  2001/05/12 07:22:24  slevy
     * Add get-time-range func for dynamic data.
     * Initialize all dynamic-data stuff explicitly.
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.44  2001/05/11 10:05:38  slevy
     * Add "warp" command if -DUSE_WARP.
     * Ellipsoids allow 3-component (Rx Ry Rz) orientation numbers too.
     * st->dyndata doesn't mean we should trash the anima[][] specklist.
     * Need to keep it intact for warping.
     *
    
     * Revision 1.43  2001/05/02 09:51:01  slevy
     * Add "ellipsoids" and "meshes" commands to toggle their display.
     * Finally parse snapshot arguments properly...?
     *
    
     * Revision 1.42  2001/04/26 08:52:46  slevy
     * Add hook for off-screen rendering: "-w width[xheight]" option for
     * snapshot/snapset.  Not actually implemented yet.
     * Add "clipbox hide".  This (a) doesn't display the big yellow box
     * and (b) doesn't enable OpenGL clipping -- just whatever object culling
     * the draw routine does anyway.
     * specks_draw_mesh() now pays attention to drawing style (solid/line/plane/point).
     * When drawing ellipsoids, disable blending altogether if bgcolor != 0.
     * Small, distant labels now disappear by default.  To get the old
     * draw-tiny-line behavior, use a negative "labelmin" value.
     *
    
     * Revision 1.41  2001/04/20 13:47:39  slevy
     * Allow *cment commands to alter multiple colormap entries: new editcmap().
     *
    
     * Revision 1.40  2001/04/10 19:18:33  slevy
     * Open sdb files (and while we're at it, other files too) in binary mode.
     *
    
     * Revision 1.39  2001/04/04 20:33:02  slevy
     * Use findfile() for "read" ctrl-command.
     *
    
     * Revision 1.38  2001/03/30 16:49:00  slevy
     * Change enum SurfStyle to avoid mentioning POINT, which Windows uses too.
     *
    
     * Revision 1.37  2001/03/30 14:00:42  slevy
     * Allow cment/boxcment/textcment as data commands too.
     * Add "ghosts" ctl command (not really implemented).
     * Add "winsize" ctl command.
     * Ellipsoids now accept -l levelno option, in which case
     * "hide levelno"/"show levelno" applies to them.  Default is -1,
     * which means "show if any level is shown", but hidden by "hide all".
     * Scrap ghost maintenance.  Do that elsewhere instead.
     * Make "maxcomment" work properly.
     *
    
     * Revision 1.36  2001/03/19 11:55:08  slevy
     * New version.c (derived from ../VERSION) contains current version string.
     * New "version" command in partibrains reports that and the partibrains.c CVS ver no.
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.35  2001/03/19 10:39:07  slevy
     * Handle speck comments properly.
     *
    
     * Revision 1.34  2001/03/15 18:19:06  slevy
     * Don't include comments in argc/argv -- it complicates things.
     * Have a separate "comment" pointer.  Pass it to specks_read_ellipsoid too.
     *
    
     * Revision 1.33  2001/03/15 15:37:06  slevy
     * Yeow -- handle VIRDIR prefix properly!
     * Complain of unrecognized data commands.
     *
    
     * Revision 1.32  2001/03/14 17:27:05  slevy
     * Make rejoinargs() work -- don't omit last arg.
     * "object" command alone reports our currently selected object.
     *
    
     * Revision 1.31  2001/03/13 22:45:08  slevy
     * Add "verbose" flag to parti_allobjs, so "gall -v ..."
     * reports object name before invoking each command.
     *
    
     * Revision 1.30  2001/03/13 08:23:39  slevy
     * Use parti_object's new "create-if-not-present" flag.
     * Data-language references can create, command-language ones can't.
     * Switch specks_read() to argc/argv style, using new "tokenize()" function.
     * Some commands still want the original string, so we also have rejoinargs().
     * Allow for adjustable comment length with "maxcomment" data command.
     * New "ellipsoid" and "mesh" objects.  Only quadmeshes implemented right now.
     * Data-language "tfm" command is now quiet.  Command-language tfm still verbose.
     * Check at run time for endian-config errors and refuse to run if wrong!
     *
    
     * Revision 1.29  2001/03/08 22:02:29  slevy
     * Disable the parti menu unless PARTIMENU envar set.
     * Allow alpha to adjust brightness of mesh objects.
     *
    
     * Revision 1.28  2001/03/05 03:04:41  slevy
     * Add mesh objects.  Or, quad meshes, anyway.
     *
    
     * Revision 1.27  2001/03/04 16:47:35  slevy
     * Make "add" and "eval" behave consistently.
     * polyorivar and texturevar now accept field names as well as numbers.
     *
    
    slevy's avatar
    slevy committed
     * Revision 1.26  2001/02/22 20:04:34  slevy
     * CONSTify.
     *
    
     * Revision 1.25  2001/02/19 22:01:16  slevy
     * Satisfy windows C compiler: pull enum FadeModel outside struct speck, etc.
     *
    
     * Revision 1.24  2001/02/19 20:50:33  slevy
     * Oops, "object" should always invoke parti_object() whether there's an
     * alias or not!
     *
    
     * Revision 1.23  2001/02/17 22:02:54  slevy
     * Enlarge polygons so that unit circle is inscribed, not circumscribed.
     * Then "txscale .5" always shows entire texture regardless of polysides.
     * Add new "ptsize" command -- makes more sense than "fast".  "fast" still works.
     *
    
     * Revision 1.22  2001/02/17 17:44:05  slevy
     * For polygons, rotate circle of vertices by 1/2 step.
     * Then, for "polysides 4" and "txscale .707",
     * the vertices coincide with the corners of the 0..1 texture.
     *
    
     * Revision 1.21  2001/02/17 05:39:45  slevy
     * Allow (in data language) "object gN=NAME".
     *
    
     * Revision 1.20  2001/02/15 05:41:12  slevy
     * new textcmap, textcment commands.  Regularize color-gamma-mapping.
     * Object aliases: "object gN=ALIAS", or in command mode, "gN=ALIAS".
     * Accept "ellipsoid" data tag; not yet implemented.
     *
    
     * Revision 1.19  2001/02/05 00:41:52  slevy
     * Accept "time" as synonym for "step".
     * Add "pickrange".
     * Mention jump, center in help msg.
    
    slevy's avatar
     
    slevy committed
     *
    
     * Revision 1.18  2001/02/03 23:43:10  slevy
    
    slevy's avatar
     
    slevy committed
     * Don't let "kira tree" hide "kira track" -- demand 3 chars!
     *
    
    slevy's avatar
     
    slevy committed
     * Revision 1.17  2001/02/03 16:49:42  slevy
     * Update cookedcmap when "cment" changes cmap.
     *
    
    slevy's avatar
     
    slevy committed
     * Revision 1.16  2001/02/03 15:29:03  slevy
     * Toss unused variable.
     *
    
    slevy's avatar
     
    slevy committed
     * Revision 1.15  2001/02/03 14:50:44  slevy
     * Add "setgamma" (abbr. "setgam" or "cgam") command to adjust colors.
     * Add "kira tree {off|on|cross|tick} [tickscale]" subcommand
     * for showing tree structure of interacting groups.
     *
    
    slevy's avatar
     
    slevy committed
     * Revision 1.14  2001/01/31 17:11:54  slevy
     * Ensure that, for starlab, clock is always in "continuous" mode.
     *
    
    slevy's avatar
     
    slevy committed
     * Revision 1.13  2001/01/31 17:07:12  slevy
     * Add RCS Id and Log strings.
     *
     */
    
    teuben's avatar
    teuben committed
    
    #define __USE_MISC	/* makes <math.h> define sqrtf() on GNU libc */
    
    
    #ifndef __GNUC__
    # if HAVE_ALLOCA_H
    #  include <alloca.h>
    # else
    #  ifdef _AIX
      #pragma alloca
    #  else
    #   ifndef alloca /* predefined by HP cc +Olibcalls */
    
    extern void *alloca(int);
    
    #   endif
    #  endif
    # endif
    #endif
    
    #ifdef HAVE_MALLOC_H
    #include <malloc.h>	/* for mallinfo(), amallinfo(), maybe alloca() too */
    #endif
    
    
    teuben's avatar
    teuben committed
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <ctype.h>
    
    
    #if !defined(HAVE_SQRTF)
    
    teuben's avatar
    teuben committed
    # define sqrtf(x)  sqrt(x)	/* if no sqrtf() */
    #endif
    
    #undef isspace		/* hack for irix 6.5 back-compat */
    #undef isdigit
    #undef isalnum
    
    #if unix
    # include <unistd.h>
    # include <sys/types.h>
    # include <netinet/in.h>  /* for htonl */
    
    slevy's avatar
     
    slevy committed
    # include <time.h>
    
    slevy's avatar
     
    slevy committed
    # ifndef WORDS_BIGENDIAN
    #  include "config.h"	/* for WORDS_BIGENDIAN */
    # endif
    
    slevy's avatar
    slevy committed
    # if USE_IEEEIO
    #  include <sys/prctl.h>
    #  ifndef PR_SADDR		/* if SGI, use sproc() for bg processing */
    #    define USE_PTHREAD  1	/* linux or other UNIX; use pthreads for bg */
    #    include <pthread.h>
    #  endif  /* end non-SGI */
    # endif   /* end USE_IEEEIO */
    
    
    teuben's avatar
    teuben committed
    #else /*WIN32*/
    # include "winjunk.h"
    
    slevy's avatar
     
    slevy committed
    # define WORDS_BIGENDIAN 0
    
    teuben's avatar
    teuben committed
    #endif
    
    teuben's avatar
    teuben committed
    #include <string.h>
    #include <errno.h>
    
    
    slevy's avatar
     
    slevy committed
    
    
    slevy's avatar
     
    slevy committed
    #if WORDS_BIGENDIAN
    
    teuben's avatar
    teuben committed
    #define RGBALPHA(rgb, alpha)	((rgb) | (alpha))
    #define RGBWHITE		0xFFFFFF00
    #define	PACKRGBA(r,g,b,a)	((r)<<24 | (g)<<16 | (b)<<8 | (a))
    
    #define RGBA_R(rgba)		(((rgba)>>24) & 0xFF)
    #define RGBA_G(rgba)		(((rgba)>>16) & 0xFF)
    #define RGBA_B(rgba)		(((rgba)>>8) & 0xFF)
    #define RGBA_A(rgba)		(((rgba)) & 0xFF)
    
    teuben's avatar
    teuben committed
    #else
    #define RGBALPHA(rgb, alpha)	((rgb) | ((alpha)<<24))
    #define RGBWHITE		0x00FFFFFF
    #define	PACKRGBA(r,g,b,a)	((a)<<24 | (b)<<16 | (g)<<8 | (r))
    
    #define RGBA_R(rgba)		(((rgba)) & 0xFF)
    #define RGBA_G(rgba)		(((rgba)>>8) & 0xFF)
    #define RGBA_B(rgba)		(((rgba)>>16) & 0xFF)
    #define RGBA_A(rgba)		(((rgba)>>24) & 0xFF)
    
    teuben's avatar
    teuben committed
    #endif
    
    
    #define	THRESHBIT		PACKRGBA(0,0,0,1)
    #define	EMPHBIT			PACKRGBA(0,0,0,2)
    #define	EXTRABITS		PACKRGBA(0,0,0,0xff)
    #define	RGBBITS			PACKRGBA(0xff,0xff,0xff,0)
    
    
    teuben's avatar
    teuben committed
    #include "geometry.h"
    
    
    #ifdef __APPLE__
    #include <OpenGL/gl.h>
    #else
    #include <GL/gl.h>    /* for GLuint */
    #endif
    
    teuben's avatar
    teuben committed
    
    #include "shmem.h"	/* NewN(), etc. */
    #include "futil.h"
    
    #include "specks.h"
    
    #include "textures.h"
    #include "findfile.h"
    #include "partiviewc.h"
    #include "sfont.h"
    
    #include <sys/types.h>
    #include <signal.h>
    
    
    teuben's avatar
    teuben committed
    #ifdef USE_KIRA
    #include "kira_parti.h"
    
    #endif
    
    #if CAVEMENU
    # include "cavemenu.h"
    # include "partimenu.h"
    # define IFCAVEMENU(x)  (x)
    #else
    # define IFCAVEMENU(x)  /* nothing */
    #endif
    
    #if THIEBAUX_VIRDIR
    # include "vd_util.h"
    
    teuben's avatar
    teuben committed
    #endif
    
      /* Star Renderer (.sdb) structure -- from stardef.h */
    
    typedef enum {ST_POINT, ST_BRIGHT_CLOUD ,ST_DARK_CLOUD, ST_BOTH_CLOUD, ST_OFF} stype;
    
    teuben's avatar
    teuben committed
    
    typedef struct {
            float  x, y, z;
            float  dx, dy, dz;
            float  magnitude, radius;
            float  opacity;
            int  num;
            unsigned short  color;
            unsigned char   group;
            unsigned char   type;
    } db_star;
    
    typedef  struct  hrec { float  t;  int  num;}  hrec_t;
    typedef  struct  mrec { float  mass, x, y, z, vx, vy, vz, rho, temp, sfr, gasmass;
                     int  id, token;}  mrec_t;
      /* end Star Renderer */
    
    
    #define VDOT( v1, v2 )  ( (v1)->x[0]*(v2)->x[0] + (v1)->x[1]*(v2)->x[1] + (v1)->x[2]*(v2)->x[2] )
    
    
    static int defcmap[] = {
      0x11eeee00,
      0x1106ee00, 0x120ea900, 0x1316ce00, 0x1520d500, 0x172ece00, 0x193fcb00,
      0x1c54b400, 0x206da400, 0x24889200, 0x2aa58400, 0x33c07600, 0x3ed96a00,
      0x4eed6100, 0x63fa5a00, 0x7efe5100, 0x99fb4c00, 0xafef4700, 0xc0dc4000,
      0xcbc33900, 0xd4a83000, 0xda8b2900, 0xdf702700, 0xe2572500, 0xe5411700,
      0xe82f1000, 0xea211500, 0xeb171400, 0xed0f1200, 0xee0aee00,
      0xffffff00,
    };
    
    int orientboxcolor = PACKRGBA( 0xff, 0xff, 0, 0xff );
    
    void specks_read_boxes( struct stuff *st, char *fname, int timestep );
    int  specks_add_box( struct stuff *st, struct AMRbox *box, int timestep );
    int  specks_purge( void *vstuff, int nbytes, void *aarena );
    int  specks_count( struct specklist *head );
    int  specks_gobox( struct stuff *st, int boxno, int argcrest, char *argvrest[] );
    
    slevy's avatar
     
    slevy committed
    int specks_cookcment( struct stuff *st, int cment );
    void specks_rgbremap( struct stuff *st );
    
    teuben's avatar
    teuben committed
    
    
    slevy's avatar
     
    slevy committed
    void specks_reupdate( struct stuff *st, struct specklist *sl );
    
    teuben's avatar
    teuben committed
    struct specklist **specks_find_annotation( struct stuff *, struct specklist **);
    void specks_set_current_annotation( struct stuff *st, char *annotation );
    void specks_add_annotation( struct stuff *st, char *annotation, int timestep );
    
    slevy's avatar
     
    slevy committed
    void specks_timerange( struct stuff *st, double *tminp, double *tmaxp );
    
    teuben's avatar
    teuben committed
    
    void strncpyt( char *dst, char *src, int dstsize ) {
      int len = strlen(src);
      if(len >= dstsize) len = dstsize-1;
      memcpy(dst, src, len);
      dst[len] = '\0';
    } 
    
    #ifdef sgi
    static float defgamma = 1.0;
    #else
    static float defgamma = 2.5;
    #endif
    
    struct stuff *
    specks_init( int argc, char *argv[] )
    {
      int i;
      struct stuff *st = NewN( struct stuff, 1 );
    
    
      i = PACKRGBA(1, 0, 0, 0);
      if(*(char *)&i != 1) {
        msg("specks_init(): trouble: is WORDS_BIGENDIAN mis-set?  Giving up.");
        exit(1);
      }
    
    
    teuben's avatar
    teuben committed
      memset(st, 0, sizeof(*st));
      st->spacescale = 1.0;
      st->fog = 0;
      st->psize = 1;
      st->alpha = .5;
      st->gamma = defgamma;
    
    slevy's avatar
     
    slevy committed
      st->rgbgamma[0] = st->rgbgamma[1] = st->rgbgamma[2] = 1.0;
      st->rgbright[0] = st->rgbright[1] = st->rgbright[2] = 1.0;
      specks_rgbremap( st );
    
    teuben's avatar
    teuben committed
      st->useme = 1;
      st->usepoly = 0;
      st->usepoint = 1;
      st->usetext = 1;
      st->usetextaxes = 1;
      st->usetextures = 1;
      st->useboxes = 1;
    
      st->usemeshes = 1;
    
      st->staticmeshes = NULL;
      st->mullions = 0;
    
      st->useellipsoids = 1;
    
    teuben's avatar
    teuben committed
      st->polysizevar = -1;
      st->polyarea = 0;
      st->polyorivar0 = -1;
    
      st->use_chromadepth = 0;
      st->chromaslidestart = 2.0;
      st->chromaslidelength = 20;
    
    teuben's avatar
    teuben committed
      st->texturevar = -1;
      st->txscale = .5;
      st->boxlabels = 0;
      st->boxlabelscale = 1.0;
      st->boxlevelmask = ~0;	/* all levels on */
      st->boxaxes = 0;		/* boxes don't show orientation markers */
      st->goboxscale = 1.0;
      st->textsize = .05;
      st->npolygon = 11;
      st->subsample = 1;
    
    slevy's avatar
     
    slevy committed
      st->everycomp = 1;
    
      st->maxcomment = sizeof(st->sl->specks->title) - 1;
    
      st->dyn.enabled = 0;
      st->dyn.data = NULL;
      st->dyn.getspecks = NULL;
      st->dyn.draw = NULL;
      st->dyn.trange = NULL;
      st->dyn.help = NULL;
      st->dyn.ctlcmd = NULL;
      st->dyn.free = NULL;
    
    teuben's avatar
    teuben committed
    
      st->menudemandfps = 4.0;
    
      st->pfaint = .05;	/* params for "fast" point-drawing */
      st->plarge = 10;
      st->polymin = .5;	/* don't draw polygons if smaller (pixels) */
    
      st->polymax = 1e8;	/* don't allow polygons to get bigger than this (pixels) */
      st->polyfademax = 0;
    
    teuben's avatar
    teuben committed
      st->textmin = 2;	/* replace labels with line-segments if smaller (pixels) */
      st->ntextures = 0;
      st->textures = NULL;
    
      st->fade = F_SPHERICAL;
      st->fadeknee1 = 10.0;
      st->fadeknee2 = 1.0;
      st->knee2steep = 1.0;
    
      st->gscale = 1.;
      st->gtrans.x[0] = st->gtrans.x[1] = st->gtrans.x[2] = 0;
      st->objTo2w = Tidentity;
    
    
      st->ncmap = st->boxncmap = st->textncmap = COUNT(defcmap);
      st->cmap = NewN(struct cment, COUNT(defcmap));
      st->boxcmap = NewN(struct cment, COUNT(defcmap));
      st->textcmap = NewN(struct cment, COUNT(defcmap));
    
    slevy's avatar
     
    slevy committed
      for(i = 0; i < COUNT(defcmap); i++) {
    
        st->cmap[i].raw = st->boxcmap[i].raw = st->textcmap[i].raw
    	= htonl(defcmap[i]);
        st->cmap[i].cooked = st->boxcmap[i].cooked = st->textcmap[i].cooked
    	= specks_cookcment( st, st->cmap[i].raw );
    
    slevy's avatar
     
    slevy committed
      }
    
      /* Ensure that textcmap[0] is white by default */
      st->textcmap[0].raw = PACKRGBA( 170, 170, 170, 0 );
      st->textcmap[0].cooked = specks_cookcment( st, st->textcmap[0].raw );
    
    teuben's avatar
    teuben committed
    
      st->sizedby = 0;
      st->coloredby = 1;
      st->sizeseq = st->colorseq = st->threshseq = 0;
      st->trueradius = 0;
      st->sdbvars = shmstrdup( "mcr" );
    
    
      st->useemph = 0;
      selinit( &st->emphsel );
      st->emphfactor = 10;
    
    
      selinit( &st->threshsel );
      selinit( &st->seesel );
    
    
    teuben's avatar
    teuben committed
      st->ntimes = 0;
      st->ndata = 0;
      st->curtime = 0;
      st->curdata = 0;
      st->datatime = 0;
    
    slevy's avatar
     
    slevy committed
      st->usertrange = 0;
      st->utmin = -HUGE;
      st->utmax = HUGE;
      st->utwrap = 0.1;
    
    teuben's avatar
    teuben committed
      st->sl = NULL;
    
      st->boxes = NULL;
      st->boxlevels = 0;
      st->boxlinewidth = 0.75;
    
    
    slevy's avatar
     
    slevy committed
      st->depthsort = 0;
    
    
    slevy's avatar
     
    slevy committed
      st->clk = NewN(SClock, 1);
      clock_init(st->clk);
      clock_set_running(st->clk, 1);
    
    teuben's avatar
    teuben committed
    
      memset(st->anima, 0, sizeof(st->anima));
      memset(st->annot, 0, sizeof(st->annot));
      memset(st->datafile, 0, sizeof(st->datafile));
      memset(st->fname, 0, sizeof(st->fname));
    
      memset(st->meshes, 0, sizeof(st->meshes));
    
    teuben's avatar
    teuben committed
    
    #if CAVE
      shmrecycler( specks_purge, st );
    #endif
    
      for(i = 1; i < argc; i++)
        specks_read( &st, argv[i] );
    
    
      IFCAVEMENU( partimenu_init( st ) );
    
    teuben's avatar
    teuben committed
    
      return st;
    }
    
    void specks_rethresh( struct stuff *st, struct specklist *sl, int by )
    {
      int i;
      int curdata = st->curdata;
      int nel = sl->nspecks;
      float threshmin = st->thresh[0], threshmax = st->thresh[1];
      struct speck *p = sl->specks;
    
      SelMask *sel = sl->sel;
    
      SelOp threshseldest;
    
      int changed = 0;
    
    teuben's avatar
    teuben committed
    
      sl->threshseq = st->threshseq;
    
      if(sl->text != NULL)	/* specklists with labels shouldn't be thresholded */
        return;
    
      if(curdata >= st->ndata)
        curdata = 0;
    
      min = (SMALLSPECKSIZE(by)>=sl->bytesperspeck) ? 0 : st->usethresh&P_THRESHMIN;
      max = (SMALLSPECKSIZE(by)>=sl->bytesperspeck) ? 0 : st->usethresh&P_THRESHMAX;
    
    teuben's avatar
    teuben committed
    
    
      for(i = 0, p = sl->specks; i < nel; i++, p = NextSpeck( p, sl, 1 )) {
    
        SelMask was = sel[i];
    
        if((min&&p->val[by]<threshmin) || (max&&p->val[by]>threshmax)) {
    
    	SELUNSET( sel[i], &threshseldest );
    
    	SELSET( sel[i], &threshseldest );
    
        changed |= was ^ sel[i];
      }
      if(changed) {
        sl->selseq++;
        if(st->selseq < sl->selseq) st->selseq = sl->selseq;
    
    teuben's avatar
    teuben committed
      }
    }
    
    
    slevy's avatar
     
    slevy committed
    int specks_cookcment( struct stuff *st, int cment )
    {
        unsigned char crgba[4];
        memcpy(crgba, &cment, 4);		/* XXX 64-bit bug? */
        return (cment & ~RGBWHITE) |
    	   PACKRGBA(
    		st->rgbmap[0][crgba[0]],
    		st->rgbmap[1][crgba[1]],
    		st->rgbmap[2][crgba[2]],
    		0 );
    }
    
    void specks_rgbremap( struct stuff *st )
    {
      int i, k;
      for(i = 0; i < 256; i++) {
        float t = (float)i / 256;
        float v = 255.99f * pow(t, 1/st->rgbgamma[0]);
        k = (int) (st->rgbright[0] * v);
    
    slevy's avatar
     
    slevy committed
        st->rgbmap[0][i] = (k <= 0) ? 0 : (k > 255) ? 255 : k;
        if(st->rgbgamma[0] != st->rgbgamma[1])
            v = 255.99f * pow(t, 1/st->rgbgamma[1]);
        k = (int) (st->rgbright[1] * v);
        st->rgbmap[1][i] = (k <= 0) ? 0 : (k > 255) ? 255 : k;
        if(st->rgbgamma[1] != st->rgbgamma[2])
            v = 255.99f * pow(t, 1/st->rgbgamma[2]);
        k = (int) (st->rgbright[2] * v);
        st->rgbmap[2][i] = (k <= 0) ? 0 : (k > 255) ? 255 : k;
      }
      /* remake colormap too */
      for(i = 0; i < st->ncmap; i++)
    
        st->cmap[i].cooked = specks_cookcment( st, st->cmap[i].raw );
    
    
      /* and chromadepth colormaps */
      if (st->chromacm != NULL) {
        for (i = 0; i < st->nchromacm; i++)
    	st->chromacm[i].cooked = specks_cookcment(st, st->chromacm[i].raw);
      }
    
    slevy's avatar
     
    slevy committed
      st->colorseq++;
    }
    
    
    
    teuben's avatar
    teuben committed
    void specks_recolor( struct stuff *st, struct specklist *sl, int by )
    {
      struct valdesc *vd;
      int i;
      int curdata = st->curdata;
      int nel = sl->nspecks;
      struct speck *sp = sl->specks;
      float cmin, cmax, normal;
      int ncmap = st->ncmap;
    
      struct cment *cmap = st->cmap;
    
    teuben's avatar
    teuben committed
      int index;
      int rgb565;
    
    slevy's avatar
     
    slevy committed
      unsigned char (*rgbmap)[256];
    
    teuben's avatar
    teuben committed
    
      sl->coloredby = by;
      sl->colorseq = st->colorseq;
    
      if(sl->text != NULL)	/* specklists with labels shouldn't be recolored */
        return;
    
      if(curdata >= st->ndata)
        curdata = 0;
    
      if(by == CONSTVAL) {
        /* Hack -- color by given RGB value */
        char crgba[4];
    
    slevy's avatar
     
    slevy committed
        int r, g, b, rgba;
    
    teuben's avatar
    teuben committed
        vd = &st->vdesc[curdata][CONSTVAL];
    
    slevy's avatar
     
    slevy committed
        r = (vd->cmin<=0) ? 0 : vd->cmin>=1 ? 255 : (int)(255.99f * vd->cmin);
        g = (vd->cmax<=0) ? 0 : vd->cmax>=1 ? 255 : (int)(255.99f * vd->cmax);
        b = (vd->mean<=0) ? 0 : vd->mean>=1 ? 255 : (int)(255.99f * vd->mean);
        crgba[0] = st->rgbmap[0][r];
    
        crgba[1] = st->rgbmap[1][g];
        crgba[2] = st->rgbmap[2][b];
    
    teuben's avatar
    teuben committed
        crgba[3] = 0;
    
    slevy's avatar
     
    slevy committed
        rgba = *(int *)&crgba[0];	/* XXX 64-bit bug? */
    
    teuben's avatar
    teuben committed
        for(i = 0; i < nel; i++, sp = NextSpeck(sp, sl, 1)) {
    
    	sp->rgba = rgba | (sp->rgba & EXTRABITS);
    
    teuben's avatar
    teuben committed
        }
        return; 
      }
    
      if(by >= MAXVAL || by < 0 || SMALLSPECKSIZE(by) > sl->bytesperspeck)
    	by = 0;
    	
      vd = &st->vdesc[curdata][by];
    
    
      if(vd->vncmap > 0) {
        ncmap = vd->vncmap;
        cmap = vd->vcmap;
      }
    
    
    teuben's avatar
    teuben committed
    
      cmin = vd->cmin, cmax = vd->cmax;
      if(cmin == cmax && cmin == 0 || (vd->call && !vd->cexact)) {
        vd->cmin = cmin = vd->min;
        vd->cmax = cmax = vd->max;
      }
    
      normal = (cmax != cmin && ncmap>2) ? (ncmap-2)/(cmax - cmin) : 0;
      rgb565 = !strcmp(vd->name, "rgb565") || !strcmp(vd->name, "colors565");
    
      /* cexact field means:
       *   0 (default): scale data range to cmap index 1..ncmap-2;
       *		    use 0 and ncmap-1 for low- and high- out-of-range values.
       *
       *   1 ("exact"): use data value as literal colormap index, 0..ncmap-1.
       */
    
    slevy's avatar
     
    slevy committed
      rgbmap = &st->rgbmap[0];
    
    teuben's avatar
    teuben committed
      for(i = 0; i < nel; i++, sp = NextSpeck(sp, sl, 1)) {
        if(rgb565) {
    	index = sp->val[by];
    	sp->rgba = PACKRGBA(
    
    slevy's avatar
     
    slevy committed
    			rgbmap[0][(index&0xF800)>>(11-(8-5))],
    			rgbmap[1][(index&0x07E0)>>(5-(8-6))],
    			rgbmap[2][(index&0x1F)<<(8-5)],
    			0 )
    
    		  | (sp->rgba & EXTRABITS);
    
    teuben's avatar
    teuben committed
        } else {
    	index = vd->cexact  ?   sp->val[by] + cmin
    			    :  (sp->val[by] - cmin) * normal + 1;
    
    	if(index < 0) index = 0;
    	else if(index >= ncmap) index = ncmap-1;
    
    
    	sp->rgba = cmap[index].cooked | (sp->rgba & EXTRABITS);
    
    teuben's avatar
    teuben committed
        }
      }
    }
    
    void specks_resize( struct stuff *st, struct specklist *sl, int by )
    {
      int i;
      int nel = sl->nspecks;
      struct speck *sp = sl->specks;
      int curdata = st->curdata;
      struct valdesc *vd;
    
    slevy's avatar
    slevy committed
      float lmin, lmax, normal, lbase;
      int labs;
    
    teuben's avatar
    teuben committed
    
      sl->sizedby = by;
      sl->sizeseq = st->sizeseq;
    
      if(sl->text != NULL) /* specklists with labels shouldn't be resized */
        return;
    
      if(curdata < 0 || curdata >= st->ndata)
        curdata = 0;
    
      if(by == CONSTVAL) {
        vd = &st->vdesc[curdata][CONSTVAL];
    
        for(i = 0; i < nel; i++, sp = NextSpeck(sp, sl, 1)) {
    
    teuben's avatar
    teuben committed
    	sp->size = vd->lmin;
    
    	if(SELECTED(sl->sel[i], &st->emphsel)) {
    	    sp->size *= st->emphfactor;