source: trunk/vizservers/nanovis/Command.cpp @ 913

Last change on this file since 913 was 913, checked in by gah, 15 years ago

created R2 and newmat11 libraries

File size: 89.4 KB
Line 
1
2/*
3 * ----------------------------------------------------------------------
4 * Command.cpp
5 *
6 *      This modules creates the Tcl interface to the nanovis server.
7 *      The communication protocol of the server is the Tcl language.
8 *      Commands given to the server by clients are executed in a
9 *      safe interpreter and the resulting image rendered offscreen
10 *      is returned as BMP-formatted image data.
11 *
12 * ======================================================================
13 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
14 *           Michael McLennan <mmclennan@purdue.edu>
15 *           Purdue Rendering and Perceptualization Lab (PURPL)
16 *
17 *  Copyright (c) 2004-2006  Purdue Research Foundation
18 *
19 *  See the file "license.terms" for information on usage and
20 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
21 * ======================================================================
22 */
23
24/*
25 * TODO:  In no particular order...
26 *        o Convert to Tcl_CmdObj interface. (done)
27 *        o Use Tcl command option parser to reduce size of procedures, remove
28 *          lots of extra error checking code.
29 *        o Convert GetVolumeIndices to GetVolumes.  Goal is to remove
30 *          all references of Nanovis::volume[] from this file.  Don't
31 *          want to know how volumes are stored. Same for heightmaps.
32 *        o Rationalize volume id scheme. Right now it's the index in
33 *          the vector. 1) Use a list instead of a vector. 2) carry
34 *          an id field that's a number that gets incremented each new volume.
35 *        o Create R2, matrix, etc. libraries.
36 */
37
38#define ISO_TEST                1
39#define PLANE_CMDS              0
40#define __TEST_CODE__           0
41// FOR testing new functions
42#define _LOCAL_ZINC_TEST_       0
43
44#include <tcl.h>
45#include "Trace.h"
46#include "Command.h"
47#include "nanovis.h"
48#include "CmdProc.h"
49
50#include "RpField1D.h"
51#include "RpFieldRect3D.h"
52#include "RpFieldPrism3D.h"
53#include "RpEncode.h"
54
55#include "transfer-function/TransferFunctionMain.h"
56#include "transfer-function/ControlPoint.h"
57#include "transfer-function/TransferFunctionGLUTWindow.h"
58#include "transfer-function/ColorGradientGLUTWindow.h"
59#include "transfer-function/ColorPaletteWindow.h"
60#include "transfer-function/MainWindow.h"
61
62#include "Nv.h"
63#include "PointSetRenderer.h"
64#include "PointSet.h"
65#include "ZincBlendeVolume.h"
66#include "NvLoadFile.h"
67#include "NvColorTableRenderer.h"
68#include "NvEventLog.h"
69#include "NvZincBlendeReconstructor.h"
70#include "VolumeInterpolator.h"
71#include "HeightMap.h"
72#include "Grid.h"
73#include "NvCamera.h"
74#include <RenderContext.h>
75#include <NvLIC.h>
76
77#if _LOCAL_ZINC_TEST_
78#include "Test.h"
79#endif
80
81// EXTERN DECLARATIONS
82// in Nv.cpp
83
84extern Grid* NanoVis::grid;
85
86// in nanovis.cpp
87extern vector<PointSet*> g_pointSet;
88
89extern PlaneRenderer* plane_render;
90extern Texture2D* plane[10];
91
92extern Rappture::Outcome load_volume_stream(int index, std::iostream& fin);
93extern Rappture::Outcome load_volume_stream_odx(int index, const char *buf,
94        int nBytes);
95extern Rappture::Outcome load_volume_stream2(int index, std::iostream& fin);
96extern void load_volume(int index, int width, int height, int depth,
97        int n_component, float* data, double vmin, double vmax,
98        double nzero_min);
99extern void load_vector_stream(int index, std::istream& fin);
100
101// Tcl interpreter for incoming messages
102static Tcl_Interp *interp;
103static Tcl_DString cmdbuffer;
104
105// default transfer function
106static const char def_transfunc[] = "transfunc define default {\n\
107  0.0  1 1 1\n\
108  0.2  1 1 0\n\
109  0.4  0 1 0\n\
110  0.6  0 1 1\n\
111  0.8  0 0 1\n\
112  1.0  1 0 1\n\
113} {\n\
114  0.00  1.0\n\
115  0.05  0.0\n\
116  0.15  0.0\n\
117  0.20  1.0\n\
118  0.25  0.0\n\
119  0.35  0.0\n\
120  0.40  1.0\n\
121  0.45  0.0\n\
122  0.55  0.0\n\
123  0.60  1.0\n\
124  0.65  0.0\n\
125  0.75  0.0\n\
126  0.80  1.0\n\
127  0.85  0.0\n\
128  0.95  0.0\n\
129  1.00  1.0\n\
130}";
131
132static Tcl_ObjCmdProc AxisCmd;
133static Tcl_ObjCmdProc CameraCmd;
134static Tcl_ObjCmdProc CutplaneCmd;
135static Tcl_ObjCmdProc GridCmd;
136static Tcl_ObjCmdProc LegendCmd;
137#if PLANE_CMDS
138static Tcl_ObjCmdProc PlaneEnableCmd;
139static Tcl_ObjCmdProc PlaneLinkCmd;
140static Tcl_ObjCmdProc PlaneNewCmd;
141#endif
142static Tcl_ObjCmdProc ScreenCmd;
143static Tcl_ObjCmdProc ScreenShotCmd;
144static Tcl_ObjCmdProc TransfuncCmd;
145static Tcl_ObjCmdProc UniRect2dCmd;
146static Tcl_ObjCmdProc UpCmd;
147static Tcl_ObjCmdProc VolumeCmd;
148static Tcl_ObjCmdProc FlowCmd;
149
150static int GetVolumeIndices(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
151        vector<unsigned int>* vectorPtr);
152static int GetVolumes(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
153        vector<Volume *>* vectorPtr);
154static int GetVolumeFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
155        Volume **volPtrPtr);
156static int GetVolumeIndex(Tcl_Interp *interp, Tcl_Obj *objPtr,
157        unsigned int *indexPtr);
158static int GetHeightMap(Tcl_Interp *interp, Tcl_Obj *objPtr, HeightMap **hmPtrPtr);
159static int GetIndices(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
160        vector<unsigned int>* vectorPtr);
161static int GetAxisFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr);
162static int GetAxisDirFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr,
163        int *dirPtr);
164static int GetColor(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
165        float *rgbPtr);
166static int GetDataStream(Tcl_Interp *interp, Rappture::Buffer &buf,
167        int nBytes);
168static HeightMap *CreateHeightMap(ClientData clientData, Tcl_Interp *interp,
169        int objc, Tcl_Obj *CONST *objv);
170
171static int
172GetFloatFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, float *valuePtr)
173{
174    double value;
175
176    if (Tcl_GetDoubleFromObj(interp, objPtr, &value) != TCL_OK) {
177        return TCL_ERROR;
178    }
179    *valuePtr = (float)value;
180    return TCL_OK;
181}
182
183static int
184GetCullMode(Tcl_Interp *interp, Tcl_Obj *objPtr,
185        graphics::RenderContext::CullMode *modePtr)
186{
187    char *string = Tcl_GetString(objPtr);
188    if (strcmp(string, "none") == 0) {
189        *modePtr = graphics::RenderContext::NO_CULL;
190    } else if (strcmp(string, "front") == 0) {
191        *modePtr = graphics::RenderContext::FRONT;
192    } else if (strcmp(string, "back") == 0) {
193        *modePtr = graphics::RenderContext::BACK;
194    } else {
195        Tcl_AppendResult(interp, "invalid cull mode \"", string,
196                "\": should be front, back, or none\"", (char *)NULL);
197        return TCL_ERROR;
198    }
199    return TCL_OK;
200}
201
202static int
203GetShadingModel(Tcl_Interp *interp, Tcl_Obj *objPtr,
204                graphics::RenderContext::ShadingModel *modelPtr)
205{
206    char *string = Tcl_GetString(objPtr);
207    if (strcmp(string,"flat") == 0) {
208        *modelPtr = graphics::RenderContext::FLAT;
209    } else if (strcmp(string,"smooth") == 0) {
210        *modelPtr = graphics::RenderContext::SMOOTH;
211    } else {
212        Tcl_AppendResult(interp, "bad shading model \"", string,
213                         "\": should be flat or smooth", (char *)NULL);
214        return TCL_ERROR;
215    }
216    return TCL_OK;
217}
218
219static int
220GetPolygonMode(Tcl_Interp *interp, Tcl_Obj *objPtr,
221               graphics::RenderContext::PolygonMode *modePtr)
222{
223    char *string = Tcl_GetString(objPtr);
224    if (strcmp(string,"wireframe") == 0) {
225        *modePtr = graphics::RenderContext::LINE;
226    } else if (strcmp(string,"fill") == 0) {
227        *modePtr = graphics::RenderContext::FILL;
228    } else {
229        Tcl_AppendResult(interp, "invalid polygon mode \"", string,
230        "\": should be wireframe or fill\"", (char *)NULL);
231        return TCL_ERROR;
232    }
233    return TCL_OK;
234}
235
236
237static int
238GetVolumeLimits(Tcl_Interp *interp, float *minPtr, float *maxPtr)
239{
240    int i;
241
242    /* Find the first volume. */
243    for (i = 0; i < NanoVis::n_volumes; i++) {
244        if (NanoVis::volume[i] != NULL) {
245            break;
246        }
247    }
248    if (i == NanoVis::n_volumes) {
249        Tcl_AppendResult(interp, "no volumes found", (char *)NULL);
250        return TCL_ERROR;
251    }
252    Volume *volPtr;
253    volPtr = NanoVis::volume[i];
254    float min, max;
255    min = volPtr->range_min();
256    max = volPtr->range_max();
257    for (i++; i < NanoVis::n_volumes; i++) {
258        if (NanoVis::volume[i] == NULL) {
259            continue;
260        }
261        volPtr = NanoVis::volume[i];
262        if (min > volPtr->range_min()) {
263            min = volPtr->range_min();
264        }
265        if (max < volPtr->range_max()) {
266            max = volPtr->range_max();
267        }
268    }
269    *minPtr = min;
270    *maxPtr = max;
271    return TCL_OK;
272}
273
274/*
275 * ----------------------------------------------------------------------
276 * CLIENT COMMAND:
277 *   camera aim <x0> <y0> <z0>
278 *   camera angle <xAngle> <yAngle> <zAngle>
279 *   camera zoom <factor>
280 *
281 * Clients send these commands to manipulate the camera.  The "angle"
282 * option controls the angle of the camera around the focal point.
283 * The "zoom" option sets the zoom factor, moving the camera in
284 * and out.
285 * ----------------------------------------------------------------------
286 */
287static int
288CameraCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
289{
290    if (objc < 2) {
291        Tcl_AppendResult(interp, "wrong # args: should be \"",
292                Tcl_GetString(objv[0]), " option arg arg...\"", (char*)NULL);
293        return TCL_ERROR;
294    }
295
296    char *string = Tcl_GetString(objv[1]);
297    char c = string[0];
298    if ((c == 'a') && (strcmp(string, "angle") == 0)) {
299        if (objc != 5) {
300            Tcl_AppendResult(interp, "wrong # args: should be \"",
301                Tcl_GetString(objv[0]), " angle xangle yangle zangle\"",
302                (char*)NULL);
303            return TCL_ERROR;
304        }
305        double xangle, yangle, zangle;
306        if ((Tcl_GetDoubleFromObj(interp, objv[2], &xangle) != TCL_OK) ||
307            (Tcl_GetDoubleFromObj(interp, objv[3], &yangle) != TCL_OK) ||
308            (Tcl_GetDoubleFromObj(interp, objv[4], &zangle) != TCL_OK)) {
309            return TCL_ERROR;
310        }
311        NanoVis::cam->rotate(xangle, yangle, zangle);
312    } else if ((c == 'a') && (strcmp(string, "aim") == 0)) {
313        if (objc != 5) {
314            Tcl_AppendResult(interp, "wrong # args: should be \"",
315                Tcl_GetString(objv[0]), " aim x y z\"", (char*)NULL);
316            return TCL_ERROR;
317        }
318        double x0, y0, z0;
319        if ((Tcl_GetDoubleFromObj(interp, objv[2], &x0) != TCL_OK) ||
320            (Tcl_GetDoubleFromObj(interp, objv[3], &y0) != TCL_OK) ||
321            (Tcl_GetDoubleFromObj(interp, objv[4], &z0) != TCL_OK)) {
322            return TCL_ERROR;
323        }
324        NanoVis::cam->aim(x0, y0, z0);
325    } else if ((c == 'z') && (strcmp(string, "zoom") == 0)) {
326        if (objc != 3) {
327            Tcl_AppendResult(interp, "wrong # args: should be \"",
328                Tcl_GetString(objv[0]), " zoom factor\"", (char*)NULL);
329            return TCL_ERROR;
330        }
331       
332        double zoom;
333        if (Tcl_GetDoubleFromObj(interp, objv[2], &zoom) != TCL_OK) {
334            return TCL_ERROR;
335        }
336        NanoVis::zoom(zoom);
337    } else {
338        Tcl_AppendResult(interp, "bad camera option \"", string,
339                     "\": should be aim, angle, or zoom", (char*)NULL);
340        return TCL_ERROR;
341    }
342
343    /*
344    Trace("Camera pos(%f %f %f), rot(%f %f %f), aim(%f %f %f)\n",
345            NanoVis::cam->location.x, NanoVis::cam->location.y, NanoVis::cam->location.z,
346            NanoVis::cam->angle.x, NanoVis::cam->angle.y, NanoVis::cam->angle.z,
347            NanoVis::cam->target.x, NanoVis::cam->target.y, NanoVis::cam->target.z);
348
349    NanoVis::cam->aim(0, 0, 100);
350    NanoVis::cam->rotate(-51.868206, 88.637497, 0.000000);
351    NanoVis::cam->move(-0.000000, -0.000000, -0.819200);
352    */
353
354    return TCL_OK;
355}
356
357static int
358ScreenShotCmd(ClientData cdata, Tcl_Interp *interp, int objc,
359              Tcl_Obj *CONST *objv)
360{
361#ifdef XINETD
362    NanoVis::resize_offscreen_buffer(1024, 1024);
363    NanoVis::cam->set_screen_size(30, 90, 1024 - 60, 1024 - 120);
364    NanoVis::offscreen_buffer_capture();  //enable offscreen render
365    NanoVis::display();
366
367    // INSOO
368    // TBD
369    /*
370    Volume* vol = NanoVis::volume[0];
371    TransferFunction* tf;
372    tf = NanoVis::vol_renderer->get_volume_shading(vol);
373    if (tf != NULL)
374    {
375        float data[512];
376
377        for (int i=0; i < 256; i++) {
378            data[i] = data[i+256] = (float)(i/255.0);
379        }
380        Texture2D* plane = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
381        NanoVis::color_table_renderer->render(1024, 1024, plane, tf, vol->range_min(),
382                vol->range_max());
383        delete plane;
384   
385    }
386    */
387#endif
388
389    return TCL_OK;
390}
391
392/*
393 * ----------------------------------------------------------------------
394 * CLIENT COMMAND:
395 *   cutplane state on|off <axis> ?<volume>...?
396 *   cutplane position <relvalue> <axis> ?<volume>...?
397 *
398 * Clients send these commands to manipulate the cutplanes in one or
399 * more data volumes.  The "state" command turns a cutplane on or
400 * off.  The "position" command changes the position to a relative
401 * value in the range 0-1.  The <axis> can be x, y, or z.  These
402 * options are applied to the volumes represented by one or more
403 * <volume> indices.  If no volumes are specified, then all volumes
404 * are updated.
405 * ----------------------------------------------------------------------
406 */
407static int
408CutplaneCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
409{
410    if (objc < 2) {
411        Tcl_AppendResult(interp, "wrong # args: should be \"",
412                Tcl_GetString(objv[0]), " option ?arg arg...?\"", (char*)NULL);
413        return TCL_ERROR;
414    }
415
416    char *string = Tcl_GetString(objv[1]);
417    char c = string[0];
418    if ((c == 's') && (strcmp(string, "state") == 0)) {
419        if (objc < 4) {
420            Tcl_AppendResult(interp, "wrong # args: should be \"",
421                Tcl_GetString(objv[0]), " state on|off axis ?volume ...? \"",
422                (char*)NULL);
423            return TCL_ERROR;
424        }
425
426        int state;
427        if (Tcl_GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
428            return TCL_ERROR;
429        }
430
431        int axis;
432        if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
433            return TCL_ERROR;
434        }
435
436        vector<Volume *> ivol;
437        if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
438            return TCL_ERROR;
439        }
440        if (state) {
441            vector<Volume *>::iterator iter;
442            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
443                (*iter)->enable_cutplane(axis);
444            }
445        } else {
446            vector<Volume *>::iterator iter;
447            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
448                (*iter)->disable_cutplane(axis);
449            }
450        }
451    } else if ((c == 'p') && (strcmp(string, "position") == 0)) {
452        if (objc < 4) {
453            Tcl_AppendResult(interp, "wrong # args: should be \"",
454                Tcl_GetString(objv[0]), " position relval axis ?volume ...? \"",
455                (char*)NULL);
456            return TCL_ERROR;
457        }
458
459        float relval;
460        if (GetFloatFromObj(interp, objv[2], &relval) != TCL_OK) {
461            return TCL_ERROR;
462        }
463
464        // keep this just inside the volume so it doesn't disappear
465        if (relval < 0.01f) {
466            relval = 0.01f;
467        } else if (relval > 0.99f) {
468            relval = 0.99f;
469        }
470
471        int axis;
472        if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
473            return TCL_ERROR;
474        }
475
476        vector<Volume *> ivol;
477        if (GetVolumes(interp, objc-4, objv+4, &ivol) != TCL_OK) {
478            return TCL_ERROR;
479        }
480        vector<Volume *>::iterator iter;
481        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
482            (*iter)->move_cutplane(axis, relval);
483        }
484    } else {
485        Tcl_AppendResult(interp, "bad option \"", string,
486                         "\": should be position or state", (char*)NULL);
487        return TCL_ERROR;
488    }
489    return TCL_OK;
490}
491
492/*
493 * ----------------------------------------------------------------------
494 * CLIENT COMMAND:
495 *   legend <volumeIndex> <width> <height>
496 *
497 * Clients use this to generate a legend image for the specified
498 * transfer function.  The legend image is a color gradient from 0
499 * to one, drawn in the given transfer function.  The resulting image
500 * is returned in the size <width> x <height>.
501 * ----------------------------------------------------------------------
502 */
503static int
504LegendCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
505{
506    if (objc != 4) {
507        Tcl_AppendResult(interp, "wrong # args: should be \"",
508                Tcl_GetString(objv[0]), " transfunc width height\"", (char*)NULL);
509        return TCL_ERROR;
510    }
511
512    Volume *volPtr;
513    if (GetVolumeFromObj(interp, objv[1], &volPtr) != TCL_OK) {
514        return TCL_ERROR;
515    }
516    TransferFunction *tf;
517    tf = NanoVis::vol_renderer->get_volume_shading(volPtr);
518    if (tf == NULL) {
519        Tcl_AppendResult(interp, "no transfer function defined for volume \"",
520                Tcl_GetString(objv[1]), "\"", (char*)NULL);
521        return TCL_ERROR;
522    }
523    char *label;
524    label = Tcl_GetString(objv[1]);
525
526    int w, h;
527    if ((Tcl_GetIntFromObj(interp, objv[2], &w) != TCL_OK) ||
528        (Tcl_GetIntFromObj(interp, objv[3], &h) != TCL_OK)) {
529        return TCL_ERROR;
530    }
531    float vmin, vmax;
532    if (GetVolumeLimits(interp, &vmin, &vmax) != TCL_OK) {
533        return TCL_ERROR;
534    }
535    NanoVis::render_legend(tf, vmin, vmax, w, h, label);
536    return TCL_OK;
537}
538
539/*
540 * ----------------------------------------------------------------------
541 * CLIENT COMMAND:
542 *   screen <width> <height>
543 *
544 * Clients send this command to set the size of the rendering area.
545 * Future images are generated at the specified width/height.
546 * ----------------------------------------------------------------------
547 */
548static int
549ScreenCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
550{
551    if (objc != 3) {
552        Tcl_AppendResult(interp, "wrong # args: should be \"",
553                Tcl_GetString(objv[0]), " width height\"", (char*)NULL);
554        return TCL_ERROR;
555    }
556
557    int w, h;
558    if ((Tcl_GetIntFromObj(interp, objv[1], &w) != TCL_OK) ||
559        (Tcl_GetIntFromObj(interp, objv[2], &h) != TCL_OK)) {
560        return TCL_ERROR;
561    }
562    NanoVis::resize_offscreen_buffer(w, h);
563    return TCL_OK;
564}
565
566/*
567 * ----------------------------------------------------------------------
568 * CLIENT COMMAND:
569 *   transfunc define <name> <colormap> <alphamap>
570 *     where <colormap> = { <v> <r> <g> <b> ... }
571 *           <alphamap> = { <v> <w> ... }
572 *
573 * Clients send these commands to manipulate the transfer functions.
574 * ----------------------------------------------------------------------
575 */
576static int
577TransfuncCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
578{
579    if (objc < 2) {
580        Tcl_AppendResult(interp, "wrong # args: should be \"",
581                Tcl_GetString(objv[0]), " option arg arg...\"", (char*)NULL);
582        return TCL_ERROR;
583    }
584
585    char *string = Tcl_GetString(objv[1]);
586    char c = string[0];
587    if ((c == 'd') && (strcmp(string, "define") == 0)) {
588        if (objc != 5) {
589            Tcl_AppendResult(interp, "wrong # args: should be \"",
590                Tcl_GetString(objv[0]), " define name colormap alphamap\"",
591                (char*)NULL);
592            return TCL_ERROR;
593        }
594
595        // decode the data and store in a series of fields
596        Rappture::Field1D rFunc, gFunc, bFunc, wFunc;
597        int cmapc, wmapc, i;
598        Tcl_Obj **cmapv;
599        Tcl_Obj **wmapv;
600
601        wmapv = cmapv = NULL;
602        if (Tcl_ListObjGetElements(interp, objv[3], &cmapc, &cmapv) != TCL_OK) {
603            return TCL_ERROR;
604        }
605        if ((cmapc % 4) != 0) {
606            Tcl_AppendResult(interp, "bad colormap in transfunc: should be ",
607                "{ v r g b ... }", (char*)NULL);
608            return TCL_ERROR;
609        }
610        if (Tcl_ListObjGetElements(interp, objv[4], &wmapc, &wmapv) != TCL_OK) {
611            return TCL_ERROR;
612        }
613        if ((wmapc % 2) != 0) {
614            Tcl_AppendResult(interp, "wrong # elements in alphamap: should be ",
615                        " { v w ... }", (char*)NULL);
616            return TCL_ERROR;
617        }
618        for (i = 0; i < cmapc; i += 4) {
619            int j;
620            double vals[4];
621
622            for (j=0; j < 4; j++) {
623                if (Tcl_GetDoubleFromObj(interp, cmapv[i+j], &vals[j]) != TCL_OK) {
624                    return TCL_ERROR;
625                }
626                if ((vals[j] < 0.0) || (vals[j] > 1.0)) {
627                    Tcl_AppendResult(interp, "bad value \"", cmapv[i+j],
628                        "\": should be in the range 0-1", (char*)NULL);
629                    return TCL_ERROR;
630                }
631            }
632            rFunc.define(vals[0], vals[1]);
633            gFunc.define(vals[0], vals[2]);
634            bFunc.define(vals[0], vals[3]);
635        }
636        for (i=0; i < wmapc; i += 2) {
637            double vals[2];
638            int j;
639
640            for (j=0; j < 2; j++) {
641                if (Tcl_GetDoubleFromObj(interp, wmapv[i+j], &vals[j]) != TCL_OK) {
642                    return TCL_ERROR;
643                }
644                if ((vals[j] < 0.0) || (vals[j] > 1.0)) {
645                    Tcl_AppendResult(interp, "bad value \"", wmapv[i+j],
646                        "\": should be in the range 0-1", (char*)NULL);
647                    return TCL_ERROR;
648                }
649            }
650            wFunc.define(vals[0], vals[1]);
651        }
652        // sample the given function into discrete slots
653        const int nslots = 256;
654        float data[4*nslots];
655        for (i=0; i < nslots; i++) {
656            double xval = double(i)/(nslots-1);
657            data[4*i]   = rFunc.value(xval);
658            data[4*i+1] = gFunc.value(xval);
659            data[4*i+2] = bFunc.value(xval);
660            data[4*i+3] = wFunc.value(xval);
661        }
662
663        // find or create this transfer function
664        TransferFunction *tf;
665        tf = NanoVis::get_transfunc(Tcl_GetString(objv[2]));
666        if (tf != NULL) {
667            tf->update(data);
668        } else {
669            tf = NanoVis::set_transfunc(Tcl_GetString(objv[2]), nslots, data);
670        }
671    } else {
672        Tcl_AppendResult(interp, "bad option \"", string,
673                "\": should be define", (char*)NULL);
674        return TCL_ERROR;
675    }
676    return TCL_OK;
677}
678
679/*
680 * ----------------------------------------------------------------------
681 * CLIENT COMMAND:
682 *   up axis
683 *
684 * Clients use this to set the "up" direction for all volumes.  Volumes
685 * are oriented such that this direction points upward.
686 * ----------------------------------------------------------------------
687 */
688static int
689UpCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
690{
691    if (objc != 2) {
692        Tcl_AppendResult(interp, "wrong # args: should be \"",
693                Tcl_GetString(objv[0]), " x|y|z|-x|-y|-z\"", (char*)NULL);
694        return TCL_ERROR;
695    }
696
697    int sign;
698    int axis;
699    if (GetAxisDirFromObj(interp, objv[1], &axis, &sign) != TCL_OK) {
700        return TCL_ERROR;
701    }
702    NanoVis::updir = (axis+1)*sign;
703    return TCL_OK;
704}
705
706/*
707 * ----------------------------------------------------------------------
708 * CLIENT COMMAND:
709 *   volume axis label x|y|z <value> ?<volumeId> ...?
710 *   volume data state on|off ?<volumeId> ...?
711 *   volume outline state on|off ?<volumeId> ...?
712 *   volume outline color on|off ?<volumeId> ...?
713 *   volume shading transfunc <name> ?<volumeId> ...?
714 *   volume shading diffuse <value> ?<volumeId> ...?
715 *   volume shading specular <value> ?<volumeId> ...?
716 *   volume shading opacity <value> ?<volumeId> ...?
717 *   volume state on|off ?<volumeId> ...?
718 *
719 * Clients send these commands to manipulate the volumes.
720 * ----------------------------------------------------------------------
721 */
722static int
723VolumeCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
724{
725    if (objc < 2) {
726        Tcl_AppendResult(interp, "wrong # args: should be \"",
727                Tcl_GetString(objv[0]), " option arg arg...\"", (char*)NULL);
728        return TCL_ERROR;
729    }
730
731    char *string = Tcl_GetString(objv[1]);
732    char c = string[0];
733    if ((c == 'a') && (strcmp(string, "axis") == 0)) {
734        if (objc < 3) {
735            Tcl_AppendResult(interp, "wrong # args: should be \"",
736                Tcl_GetString(objv[0]), " axis option ?arg arg...?\"",
737                (char*)NULL);
738            return TCL_ERROR;
739        }
740        char *string = Tcl_GetString(objv[2]);
741        c = string[0];
742        if ((c == 'l') && (strcmp(string, "label") == 0)) {
743            if (objc < 5) {
744                Tcl_AppendResult(interp, "wrong # args: should be \"",
745                        Tcl_GetString(objv[0]),
746                        " axis label x|y|z string ?volume ...?\"", (char*)NULL);
747                return TCL_ERROR;
748            }
749            int axis;
750            if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
751                return TCL_ERROR;
752            }
753            vector<Volume *> ivol;
754            if (GetVolumes(interp, objc - 5, objv + 5, &ivol) != TCL_OK) {
755                return TCL_ERROR;
756            }
757            vector<Volume *>::iterator iter;
758            char *label;
759            label = Tcl_GetString(objv[4]);
760            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
761                (*iter)->set_label(axis, label);
762            }
763        } else {
764            Tcl_AppendResult(interp, "bad option \"", string,
765                "\": should be label", (char*)NULL);
766            return TCL_ERROR;
767        }
768    } else if ((c == 'd') && (strcmp(string, "data") == 0)) {
769        if (objc < 3) {
770            Tcl_AppendResult(interp, "wrong # args: should be \"",
771                Tcl_GetString(objv[0]), " data option ?arg arg...?\"",
772                (char*)NULL);
773            return TCL_ERROR;
774        }
775        char *string = Tcl_GetString(objv[2]);
776        c = string[0];
777        if ((c == 's') && (strcmp(string, "state") == 0)) {
778            if (objc < 4) {
779                Tcl_AppendResult(interp, "wrong # args: should be \"",
780                        Tcl_GetString(objv[0])," data state on|off ?volume...?\"",
781                        (char*)NULL);
782                return TCL_ERROR;
783            }
784            int state;
785            if (Tcl_GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
786                return TCL_ERROR;
787            }
788            vector<Volume *> ivol;
789            if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
790                return TCL_ERROR;
791            }
792            if (state) {
793                vector<Volume *>::iterator iter;
794                for (iter = ivol.begin(); iter != ivol.end(); iter++) {
795                    (*iter)->enable_data();
796                }
797            } else {
798                vector<Volume *>::iterator iter;
799                for (iter = ivol.begin(); iter != ivol.end(); iter++) {
800                    (*iter)->disable_data();
801                }
802            }
803        } else if (c == 'f' && strcmp(string, "follows") == 0) {
804            if (objc < 4) {
805                Tcl_AppendResult(interp, "wrong # args: should be \"",
806                        Tcl_GetString(objv[0]), " data follows size", (char*)NULL);
807                return TCL_ERROR;
808            }
809            printf("Data Loading\n");
810            fflush(stdout);
811
812            int nbytes;
813            if (Tcl_GetIntFromObj(interp, objv[3], &nbytes) != TCL_OK) {
814                return TCL_ERROR;
815            }
816           
817            Rappture::Buffer buf;
818            if (GetDataStream(interp, buf, nbytes) != TCL_OK) {
819                return TCL_ERROR;
820            }
821            int n = NanoVis::n_volumes;
822            char header[6];
823            memcpy(header, buf.bytes(), sizeof(char) * 5);
824            header[5] = '\0';
825
826#if _LOCAL_ZINC_TEST_
827            //FILE* fp = fopen("/home/nanohub/vrinside/nv/data/HOON/QDWL_100_100_50_strain_8000i.nd_zatom_12_1", "rb");
828            FILE* fp;
829
830            fp = fopen("/home/nanohub/vrinside/nv/data/HOON/GaAs_AlGaAs_2QD_B4.nd_zc_1_wf", "rb");
831            if (fp == NULL) {
832                printf("cannot open the file\n");
833                fflush(stdout);
834                return TCL_ERROR;
835            }
836            unsigned char* b = (unsigned char*)malloc(buf.size());
837            fread(b, buf.size(), 1, fp);
838            fclose(fp);
839#endif  /*_LOCAL_ZINC_TEST_*/
840            printf("Checking header[%s]\n", header);
841            fflush(stdout);
842            if (strcmp(header, "<HDR>") == 0) {
843                Volume* vol = NULL;
844
845                printf("ZincBlende stream is in\n");
846                fflush(stdout);
847                //std::stringstream fdata(std::ios_base::out|std::ios_base::in|std::ios_base::binary);
848                //fdata.write(buf.bytes(),buf.size());
849                //vol = NvZincBlendeReconstructor::getInstance()->loadFromStream(fdata);
850               
851#if _LOCAL_ZINC_TEST_
852                vol = NvZincBlendeReconstructor::getInstance()->loadFromMemory(b);
853#else
854                vol = NvZincBlendeReconstructor::getInstance()->loadFromMemory((void*) buf.bytes());
855#endif  /*_LOCAL_ZINC_TEST_*/
856
857                printf("finish loading\n");
858                fflush(stdout);
859                if (vol) {
860                    while (NanoVis::n_volumes <= n) {
861                        NanoVis::volume.push_back((Volume*) NULL);
862                        NanoVis::n_volumes++;
863                    }
864
865                    if (NanoVis::volume[n] != NULL) {
866                        delete NanoVis::volume[n];
867                        NanoVis::volume[n] = NULL;
868                    }
869
870                    float dx0 = -0.5;
871                    float dy0 = -0.5*vol->height/vol->width;
872                    float dz0 = -0.5*vol->depth/vol->width;
873                    vol->move(Vector3(dx0, dy0, dz0));
874
875                    NanoVis::volume[n] = vol;
876                }
877#if __TEST_CODE__
878            } else if (strcmp(header, "<FET>") == 0) {
879                printf("FET loading...\n");
880                fflush(stdout);
881                std::stringstream fdata;
882                fdata.write(buf.bytes(),buf.size());
883                err = load_volume_stream3(n, fdata);
884
885                if (err) {
886                    Tcl_AppendResult(interp, err.remark().c_str(), (char*)NULL);
887                    return TCL_ERROR;
888                }
889#endif  /*__TEST_CODE__*/
890            } else if (strcmp(header, "<ODX>") == 0) {
891                Rappture::Outcome err;
892
893                printf("Loading DX using OpenDX library...\n");
894                fflush(stdout);
895                //err = load_volume_stream_odx(n, buf.bytes()+5, buf.size()-5);
896                //err = load_volume_stream2(n, fdata);
897                if (err) {
898                    Tcl_AppendResult(interp, err.remark().c_str(), (char*)NULL);
899                    return TCL_ERROR;
900                }
901            } else {
902                Rappture::Outcome err;
903
904                printf("OpenDX loading...\n");
905                fflush(stdout);
906                std::stringstream fdata;
907                fdata.write(buf.bytes(),buf.size());
908               
909#if ISO_TEST
910                err = load_volume_stream2(n, fdata);
911#else
912                err = load_volume_stream(n, fdata);
913#endif
914                if (err) {
915                    Tcl_AppendResult(interp, err.remark().c_str(), (char*)NULL);
916                    return TCL_ERROR;
917                }
918            }
919
920            //
921            // BE CAREFUL:  Set the number of slices to something
922            //   slightly different for each volume.  If we have
923            //   identical volumes at exactly the same position
924            //   with exactly the same number of slices, the second
925            //   volume will overwrite the first, so the first won't
926            //   appear at all.
927            //
928            if (NanoVis::volume[n] != NULL) {
929                NanoVis::volume[n]->set_n_slice(256-n);
930                NanoVis::volume[n]->disable_cutplane(0);
931                NanoVis::volume[n]->disable_cutplane(1);
932                NanoVis::volume[n]->disable_cutplane(2);
933
934                NanoVis::vol_renderer->add_volume(NanoVis::volume[n],NanoVis::get_transfunc("default"));
935            }
936
937            {
938                Volume *volPtr;
939                char info[1024];
940                float vmin, vmax;
941
942                if (GetVolumeLimits(interp, &vmin, &vmax) != TCL_OK) {
943                    return TCL_ERROR;
944                }
945                volPtr = NanoVis::volume[n];
946                sprintf(info, "nv>data id %d min %g max %g vmin %g vmax %g\n",
947                        n, volPtr->range_min(), volPtr->range_max(),vmin, vmax);
948                write(0, info, strlen(info));
949            }
950        } else {
951            Tcl_AppendResult(interp, "bad data option \"", string,
952                "\": should be follows or state", (char*)NULL);
953            return TCL_ERROR;
954        }
955    } else if (c == 'o' && strcmp(string, "outline") == 0) {
956        if (objc < 3) {
957            Tcl_AppendResult(interp, "wrong # args: should be \"",
958                Tcl_GetString(objv[0]), " outline option ?arg arg...?\"",
959                (char*)NULL);
960            return TCL_ERROR;
961        }
962        char *string = Tcl_GetString(objv[2]);
963        c = string[0];
964        if ((c == 's') && (strcmp(string, "state") == 0)) {
965            if (objc < 3) {
966                Tcl_AppendResult(interp, "wrong # args: should be \"",
967                        Tcl_GetString(objv[0]),
968                        " outline state on|off ?volume ...? \"", (char*)NULL);
969                return TCL_ERROR;
970            }
971
972            int state;
973            if (Tcl_GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
974                return TCL_ERROR;
975            }
976            vector<Volume *> ivol;
977            if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
978                return TCL_ERROR;
979            }
980            if (state) {
981                vector<Volume *>::iterator iter;
982                for (iter = ivol.begin(); iter != ivol.end(); iter++) {
983                    (*iter)->enable_outline();
984                }
985            } else {
986                vector<Volume *>::iterator iter;
987                for (iter = ivol.begin(); iter != ivol.end(); iter++) {
988                    (*iter)->disable_outline();
989                }
990            }
991        } else if ((c == 'v') && (strcmp(string, "visible") == 0)) {
992            int ivisible;
993
994            if (Tcl_GetBooleanFromObj(interp, objv[3], &ivisible) != TCL_OK) {
995                return TCL_ERROR;
996            }           
997            if (!ivisible) {
998                for (int i = 0; i < NanoVis::n_volumes; ++i) {
999                    if (NanoVis::volume[i]) {
1000                        NanoVis::volume[i]->disable_outline();
1001                    }
1002                }
1003            } else {
1004                for (int i = 0; i < NanoVis::n_volumes; ++i) {
1005                    if (NanoVis::volume[i]) {
1006                        NanoVis::volume[i]->enable_outline();
1007                    }
1008                }
1009            }
1010        } else if ((c == 'c') && (strcmp(string, "color") == 0)) {
1011            if (objc < 6) {
1012                Tcl_AppendResult(interp, "wrong # args: should be \"",
1013                        Tcl_GetString(objv[0]),
1014                        " outline color R G B ?volume ...? \"", (char*)NULL);
1015                return TCL_ERROR;
1016            }
1017            float rgb[3];
1018            if (GetColor(interp, objc - 3, objv + 3, rgb) != TCL_OK) {
1019                return TCL_ERROR;
1020            }
1021            vector<Volume *> ivol;
1022            if (GetVolumes(interp, objc - 6, objv + 6, &ivol) != TCL_OK) {
1023                return TCL_ERROR;
1024            }
1025            vector<Volume *>::iterator iter;
1026            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1027                (*iter)->set_outline_color(rgb);
1028            }
1029        }
1030        else {
1031            Tcl_AppendResult(interp, "bad outline option \"", string,
1032                "\": should be color, visible, or state", (char*)NULL);
1033            return TCL_ERROR;
1034        }
1035    } else if ((c == 's') && (strcmp(string, "shading") == 0)) {
1036        if (objc < 3) {
1037            Tcl_AppendResult(interp, "wrong # args: should be \"",
1038                Tcl_GetString(objv[0]), " shading option ?arg arg...?\"",
1039                (char*)NULL);
1040            return TCL_ERROR;
1041        }
1042        char *string = Tcl_GetString(objv[2]);
1043        c = string[0];
1044        if ((c == 't') && (strcmp(string, "transfunc") == 0)) {
1045            if (objc < 4) {
1046                Tcl_AppendResult(interp, "wrong # args: should be \"",
1047                        Tcl_GetString(objv[0]),
1048                        " shading transfunc name ?volume ...?\"", (char*)NULL);
1049                return TCL_ERROR;
1050            }
1051            TransferFunction *tf;
1052            char *name = Tcl_GetString(objv[3]);
1053            tf = NanoVis::get_transfunc(name);
1054            if (tf == NULL) {
1055                Tcl_AppendResult(interp, "transfer function \"", name,
1056                    "\" is not defined", (char*)NULL);
1057                return TCL_ERROR;
1058            }
1059            vector<Volume *> ivol;
1060            if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1061                return TCL_ERROR;
1062            }
1063            vector<Volume *>::iterator iter;
1064            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1065                NanoVis::vol_renderer->shade_volume(*iter, tf);
1066               
1067                // TBD..
1068                // POINTSET
1069                /*
1070                if ((*iter)->pointsetIndex != -1) {
1071                    g_pointSet[(*iter)->pointsetIndex]->updateColor(tf->getData(), 256);
1072                }
1073                */
1074            }
1075        } else if ((c == 'd') && (strcmp(string, "diffuse") == 0)) {
1076            if (objc < 4) {
1077                Tcl_AppendResult(interp, "wrong # args: should be \"",
1078                        Tcl_GetString(objv[0]),
1079                        " shading diffuse value ?volume ...?\"", (char*)NULL);
1080                return TCL_ERROR;
1081            }
1082
1083            float diffuse;
1084            if (GetFloatFromObj(interp, objv[3], &diffuse) != TCL_OK) {
1085                return TCL_ERROR;
1086            }
1087            vector<Volume *> ivol;
1088            if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1089                return TCL_ERROR;
1090            }
1091            vector<Volume *>::iterator iter;
1092            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1093                (*iter)->set_diffuse(diffuse);
1094            }
1095        } else if ((c == 'o') && (strcmp(string, "opacity") == 0)) {
1096            if (objc < 4) {
1097                Tcl_AppendResult(interp, "wrong # args: should be \"",
1098                        Tcl_GetString(objv[0]),
1099                        " shading opacity value ?volume ...?\"", (char*)NULL);
1100                return TCL_ERROR;
1101            }
1102            float opacity;
1103            if (GetFloatFromObj(interp, objv[3], &opacity) != TCL_OK) {
1104                return TCL_ERROR;
1105            }
1106            vector<Volume *> ivol;
1107            if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1108                return TCL_ERROR;
1109            }
1110            vector<Volume *>::iterator iter;
1111            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1112                (*iter)->set_opacity_scale(opacity);
1113            }
1114        } else if ((c == 's') && (strcmp(string, "specular") == 0)) {
1115            if (objc < 4) {
1116                Tcl_AppendResult(interp, "wrong # args: should be \"",
1117                        Tcl_GetString(objv[0]),
1118                        " shading specular value ?volume ...?\"", (char*)NULL);
1119                return TCL_ERROR;
1120            }
1121            float specular;
1122            if (GetFloatFromObj(interp, objv[3], &specular) != TCL_OK) {
1123                return TCL_ERROR;
1124            }
1125            vector<Volume *> ivol;
1126            if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1127                return TCL_ERROR;
1128            }
1129            vector<Volume *>::iterator iter;
1130            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1131                (*iter)->set_specular(specular);
1132            }
1133        } else if ((c == 'i') && (strcmp(string, "isosurface") == 0)) {
1134            if (objc < 4) {
1135                Tcl_AppendResult(interp, "wrong # args: should be \"",
1136                        Tcl_GetString(objv[0]),
1137                        " shading isosurface on|off ?volume ...?\"", (char*)NULL);
1138                return TCL_ERROR;
1139            }
1140            int iso_surface;
1141            if (Tcl_GetBooleanFromObj(interp, objv[3], &iso_surface) != TCL_OK) {
1142                return TCL_ERROR;
1143            }
1144            vector<Volume *> ivol;
1145            if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1146                return TCL_ERROR;
1147            }
1148            vector<Volume *>::iterator iter;
1149            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1150                (*iter)->set_isosurface(iso_surface);
1151            }
1152        } else {
1153            Tcl_AppendResult(interp, "bad shading option \"", string,
1154                "\": should be diffuse, opacity, specular, transfunc, or ",
1155                "isosurface", (char*)NULL);
1156            return TCL_ERROR;
1157        }
1158    } else if ((c == 's') && (strcmp(string, "state") == 0)) {
1159        if (objc < 3) {
1160            Tcl_AppendResult(interp, "wrong # args: should be \"",
1161                Tcl_GetString(objv[0]), " state on|off ?volume...?\"",
1162                (char*)NULL);
1163            return TCL_ERROR;
1164        }
1165        int state;
1166        if (Tcl_GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1167            return TCL_ERROR;
1168        }
1169        vector<Volume *> ivol;
1170        if (GetVolumes(interp, objc - 3, objv + 3, &ivol) != TCL_OK) {
1171            return TCL_ERROR;
1172        }
1173        if (state) {
1174            vector<Volume *>::iterator iter;
1175            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1176                (*iter)->enable();
1177            }
1178        } else {
1179            vector<Volume *>::iterator iter;
1180            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1181                (*iter)->disable();
1182            }
1183        }
1184    } else if (strcmp(string, "animation") == 0) {
1185        if (objc < 3) {
1186            Tcl_AppendResult(interp, "wrong # args: should be \"",
1187                Tcl_GetString(objv[0]), " animation option ?args...?\"",
1188                (char*)NULL);
1189            return TCL_ERROR;
1190        }
1191        char *string = Tcl_GetString(objv[2]);
1192        char c = string[0];
1193        if ((c == 'v') && (strcmp(string,"volumes") == 0)) {
1194            vector<unsigned int> ivol;
1195            if (GetVolumeIndices(interp, objc - 3, objv + 3, &ivol) != TCL_OK) {
1196                return TCL_ERROR;
1197            }
1198            Trace("parsing volume index\n");
1199            vector<unsigned int>::iterator iter;
1200            for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1201                Trace("index: %d\n", *iter);
1202                NanoVis::vol_renderer->addAnimatedVolume(NanoVis::volume[*iter],
1203                        *iter);
1204            }
1205        } else if ((c == 'c') && (strcmp(string,"capture") == 0)) {
1206            int total;
1207
1208            if (Tcl_GetIntFromObj(interp, objv[3], &total) != TCL_OK) {
1209                return TCL_ERROR;
1210            }
1211            VolumeInterpolator* interpolator;
1212            interpolator = NanoVis::vol_renderer->getVolumeInterpolator();
1213            interpolator->start();
1214            if (interpolator->is_started()) {
1215                char *fileName = (objc < 5) ? NULL : Tcl_GetString(objv[4]);
1216                for (int frame_num = 0; frame_num < total; ++frame_num) {
1217                    float fraction;
1218
1219                    fraction = ((float)frame_num) / (total - 1);
1220                    Trace("fraction : %f\n", fraction);
1221                    //interpolator->update(((float)frame_num) / (total - 1));
1222                    interpolator->update(fraction);
1223
1224                    NanoVis::offscreen_buffer_capture();  //enable offscreen render
1225
1226                    NanoVis::display();
1227                    NanoVis::read_screen();
1228
1229                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1230           
1231                    NanoVis::bmp_write_to_file(frame_num, fileName);
1232                }
1233            }
1234        } else if ((c == 's') && (strcmp(string, "start") == 0)) {
1235            NanoVis::vol_renderer->startVolumeAnimation();
1236        } else if ((c == 's') && (strcmp(string, "stop") == 0)) {
1237            NanoVis::vol_renderer->stopVolumeAnimation();
1238        } else if ((c == 'c') && (strcmp(string, "clear") == 0)) {
1239            NanoVis::vol_renderer->clearAnimatedVolumeInfo();
1240        } else {
1241            Tcl_AppendResult(interp, "bad animation option \"", string,
1242                "\": should be volumes, start, stop,  or clear", (char*)NULL);
1243            return TCL_ERROR;
1244        }
1245    } else if ((c == 't') && (strcmp(string, "test2") == 0)) {
1246        NanoVis::volume[1]->disable_data();
1247        NanoVis::volume[1]->disable();
1248    } else {
1249        Tcl_AppendResult(interp, "bad option \"", string, "\": should be ",
1250                "data, outline, shading, or state", (char*)NULL);
1251        return TCL_ERROR;
1252    }
1253    return TCL_OK;
1254}
1255
1256static int
1257FlowCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
1258{
1259    Rappture::Outcome err;
1260
1261    if (objc < 2) {
1262        Tcl_AppendResult(interp, "wrong # args: should be \"",
1263                Tcl_GetString(objv[0]), " option ?arg arg?", (char *)NULL);
1264        return TCL_ERROR;
1265    }
1266    char *string = Tcl_GetString(objv[1]);
1267    char c = string[0];
1268    if ((c == 'v') && (strcmp(string, "vectorid") == 0)) {
1269        if (objc != 3) {
1270            Tcl_AppendResult(interp, "wrong # args: should be \"",
1271                Tcl_GetString(objv[0]), " vectorid volume", (char *)NULL);
1272            return TCL_ERROR;
1273        }
1274        Volume *volPtr;
1275
1276        if (GetVolumeFromObj(interp, objv[2], &volPtr) != TCL_OK) {
1277            return TCL_ERROR;
1278        }
1279        if (NanoVis::particleRenderer != NULL) {
1280            NanoVis::particleRenderer->setVectorField(volPtr->id, 1.0f,
1281                volPtr->height / (float)volPtr->width,
1282                volPtr->depth  / (float)volPtr->width,
1283                volPtr->range_max());
1284            NanoVis::initParticle();
1285        }
1286        if (NanoVis::licRenderer != NULL) {
1287            NanoVis::licRenderer->setVectorField(volPtr->id,
1288                1.0f / volPtr->aspect_ratio_width,
1289                1.0f / volPtr->aspect_ratio_height,
1290                1.0f / volPtr->aspect_ratio_depth,
1291                volPtr->range_max());
1292            NanoVis::licRenderer->set_offset(NanoVis::lic_slice_z);
1293        }
1294    } else if (c == 'l' && strcmp(string, "lic") == 0) {
1295        if (objc != 3) {
1296            Tcl_AppendResult(interp, "wrong # args: should be \"",
1297                Tcl_GetString(objv[0]), " lic on|off\"", (char*)NULL);
1298            return TCL_ERROR;
1299        }
1300        int ibool;
1301        if (Tcl_GetBooleanFromObj(interp, objv[2], &ibool) != TCL_OK) {
1302            return TCL_ERROR;
1303        }
1304        NanoVis::lic_on = (bool)ibool;
1305    } else if ((c == 'p') && (strcmp(string, "particle") == 0)) {
1306        if (objc < 3) {
1307            Tcl_AppendResult(interp, "wrong # args: should be \"",
1308                Tcl_GetString(objv[0]), " particle visible|slice|slicepos arg \"",
1309                (char*)NULL);
1310            return TCL_ERROR;
1311        }
1312        char *string = Tcl_GetString(objv[2]);
1313        c = string[0];
1314        if ((c == 'v') && (strcmp(string, "visible") == 0)) {
1315            if (objc != 4) {
1316                Tcl_AppendResult(interp, "wrong # args: should be \"",
1317                        Tcl_GetString(objv[0]), " particle visible on|off\"",
1318                        (char*)NULL);
1319                return TCL_ERROR;
1320            }
1321            int state;
1322            if (Tcl_GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
1323                return TCL_ERROR;
1324            }
1325            NanoVis::particle_on = state;
1326        } else if ((c == 's') && (strcmp(string, "slice") == 0)) {
1327            if (objc != 4) {
1328                Tcl_AppendResult(interp, "wrong # args: should be \"",
1329                        Tcl_GetString(objv[0]),
1330                        " particle slice volume\"", (char*)NULL);
1331                return TCL_ERROR;
1332            }
1333            int axis;
1334            if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
1335                return TCL_ERROR;
1336            }
1337            NanoVis::lic_axis = axis;
1338        } else if ((c == 's') && (strcmp(string, "slicepos") == 0)) {
1339            if (objc != 4) {
1340                Tcl_AppendResult(interp, "wrong # args: should be \"",
1341                        Tcl_GetString(objv[0]), " particle slicepos value\"",
1342                        (char*)NULL);
1343                return TCL_ERROR;
1344            }
1345            float pos;
1346            if (GetFloatFromObj(interp, objv[2], &pos) != TCL_OK) {
1347                return TCL_ERROR;
1348            }
1349            if (pos < 0.0f) {
1350                pos = 0.0f;
1351            } else if (pos > 1.0f) {
1352                pos = 1.0f;
1353            }
1354            switch (NanoVis::lic_axis) {
1355            case 0 :
1356                NanoVis::lic_slice_x = pos;
1357                break;
1358            case 1 :
1359                NanoVis::lic_slice_y = pos;
1360                break;
1361            case 2 :
1362                NanoVis::lic_slice_z = pos;
1363                break;
1364            }
1365        } else {
1366            Tcl_AppendResult(interp, "unknown option \"",string,"\": should be \"",
1367                Tcl_GetString(objv[0]), " visible, slice, or slicepos\"",
1368                (char *)NULL);
1369            return TCL_ERROR;
1370        }
1371    } else if ((c == 'r') && (strcmp(string, "reset") == 0)) {
1372        NanoVis::initParticle();
1373    } else if ((c == 'c') && (strcmp(string, "capture") == 0)) {
1374        if (objc > 4 || objc < 3) {
1375            Tcl_AppendResult(interp, "wrong # args: should be \"",
1376                Tcl_GetString(objv[0]), " capture numframes [directory]\"",
1377                (char*)NULL);
1378            return TCL_ERROR;
1379        }
1380        int total_frame_count;
1381
1382        if (Tcl_GetIntFromObj(interp, objv[2], &total_frame_count) != TCL_OK) {
1383            return TCL_ERROR;
1384        }
1385        if (NanoVis::licRenderer) {
1386            NanoVis::licRenderer->activate();
1387        }
1388        if (NanoVis::particleRenderer) {
1389            NanoVis::particleRenderer->activate();
1390        }
1391        // Karl
1392        //
1393        Trace("FLOW started\n");
1394        char *fileName;
1395        fileName = (objc < 4) ? NULL : Tcl_GetString(objv[3]);
1396        for (int frame_count = 0; frame_count < total_frame_count;
1397             frame_count++) {
1398           
1399            // Generate the latest frame and send it back to the client
1400            if (NanoVis::licRenderer &&
1401                NanoVis::licRenderer->isActivated()) {
1402                NanoVis::licRenderer->convolve();               
1403            }
1404            if (NanoVis::particleRenderer &&
1405                NanoVis::particleRenderer->isActivated()) {
1406                NanoVis::particleRenderer->advect();
1407            }
1408            NanoVis::offscreen_buffer_capture();  //enable offscreen render
1409            NanoVis::display();
1410           
1411            //          printf("Read Screen for Writing to file...\n");
1412           
1413            NanoVis::read_screen();
1414            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1415
1416            NanoVis::bmp_write_to_file(frame_count, fileName);
1417        }
1418        Trace("FLOW end\n");
1419        // put your code...
1420        if (NanoVis::licRenderer) {
1421            NanoVis::licRenderer->deactivate();
1422        }
1423        if (NanoVis::particleRenderer) {
1424            NanoVis::particleRenderer->deactivate();
1425        }
1426        NanoVis::initParticle();
1427    } else if ((c == 'd') && (strcmp(string, "data") == 0)) {
1428        if (objc < 3) {
1429            Tcl_AppendResult(interp, "wrong # args: should be \"",
1430                Tcl_GetString(objv[0]), " data follows ?args?", (char *)NULL);
1431            return TCL_ERROR;
1432        }
1433        char *string = Tcl_GetString(objv[2]);;
1434        c = string[0];
1435        if ((c == 'f') && (strcmp(string,"follows") == 0)) {
1436            if (objc != 4) {
1437                Tcl_AppendResult(interp, "wrong # args: should be \"",
1438                        Tcl_GetString(objv[0]), " data follows length",
1439                        (char *)NULL);
1440                return TCL_ERROR;
1441            }
1442            int nbytes;
1443            if (Tcl_GetIntFromObj(interp, objv[3], &nbytes) != TCL_OK) {
1444                return TCL_ERROR;
1445            }
1446            Rappture::Buffer buf;
1447            if (GetDataStream(interp, buf, nbytes) != TCL_OK) {
1448                return TCL_ERROR;
1449            }
1450            int n = NanoVis::n_volumes;
1451            std::stringstream fdata;
1452            fdata.write(buf.bytes(),buf.size());
1453            load_vector_stream(n, fdata);
1454            Volume *volPtr = NanoVis::volume[n];
1455
1456            //
1457            // BE CAREFUL:  Set the number of slices to something
1458            //   slightly different for each volume.  If we have
1459            //   identical volumes at exactly the same position
1460            //   with exactly the same number of slices, the second
1461            //   volume will overwrite the first, so the first won't
1462            //   appear at all.
1463            //
1464            if (volPtr != NULL) {
1465                volPtr->set_n_slice(256-n);
1466                volPtr->disable_cutplane(0);
1467                volPtr->disable_cutplane(1);
1468                volPtr->disable_cutplane(2);
1469
1470                NanoVis::vol_renderer->add_volume(volPtr,
1471                        NanoVis::get_transfunc("default"));
1472            }
1473        }
1474    } else {
1475        return TCL_ERROR;
1476    }
1477    return TCL_OK;
1478}
1479
1480
1481static int
1482HeightMapDataFollowsOp(ClientData cdata, Tcl_Interp *interp, int objc,
1483                       Tcl_Obj *CONST *objv)
1484{
1485    Rappture::Buffer buf;
1486    int nBytes;
1487   
1488    if (Tcl_GetIntFromObj(interp, objv[3], &nBytes) != TCL_OK) {
1489        return TCL_ERROR;
1490    }
1491    if (GetDataStream(interp, buf, nBytes) != TCL_OK) {
1492        return TCL_ERROR;
1493    }
1494    buf.append("\0", 1);
1495    int result;
1496    result = Tcl_Eval(interp, buf.bytes());
1497    if (result != TCL_OK) {
1498        fprintf(stderr, "error in command: %s\n",
1499                Tcl_GetStringResult(interp));
1500        fflush(stderr);
1501    }
1502    return result;
1503}
1504
1505static int
1506HeightMapDataVisibleOp(ClientData cdata, Tcl_Interp *interp, int objc,
1507                       Tcl_Obj *CONST *objv)
1508{
1509    int ivisible;
1510    if (Tcl_GetBooleanFromObj(interp, objv[3], &ivisible) != TCL_OK) {
1511        return TCL_ERROR;
1512    }
1513    vector<unsigned int> indices;
1514    if (GetIndices(interp, objc - 4, objv + 4, &indices) != TCL_OK) {
1515        return TCL_ERROR;
1516    }
1517    bool visible;
1518    visible = (bool)ivisible;
1519    for (unsigned int i = 0; i < indices.size(); ++i) {
1520        if ((indices[i] < NanoVis::heightMap.size()) &&
1521            (NanoVis::heightMap[indices[i]] != NULL)) {
1522            NanoVis::heightMap[indices[i]]->setVisible(visible);
1523        }
1524    }
1525    return TCL_OK;
1526}
1527
1528static Rappture::CmdSpec heightMapDataOps[] =
1529{
1530    {"follows",      1, HeightMapDataFollowsOp, 4, 4, "length",},
1531    {"visible",      1, HeightMapDataVisibleOp, 4, 0, "bool ?indices?",},
1532};
1533static int nHeightMapDataOps = NumCmdSpecs(heightMapDataOps);
1534
1535static int
1536HeightMapDataOp(ClientData cdata, Tcl_Interp *interp, int objc,
1537                 Tcl_Obj *CONST *objv)
1538{
1539    Tcl_ObjCmdProc *proc;
1540
1541    proc = Rappture::GetOpFromObj(interp, nHeightMapDataOps, heightMapDataOps,
1542                Rappture::CMDSPEC_ARG2, objc, objv, 0);
1543    if (proc == NULL) {
1544        return TCL_ERROR;
1545    }
1546    return (*proc) (cdata, interp, objc, objv);
1547}
1548
1549
1550static int
1551HeightMapLineContourColorOp(ClientData cdata, Tcl_Interp *interp, int objc,
1552                              Tcl_Obj *CONST *objv)
1553{
1554    float rgb[3];
1555    if (GetColor(interp, objc - 3, objv + 3, rgb) != TCL_OK) {
1556        return TCL_ERROR;
1557    }           
1558    vector<unsigned int> indices;
1559    if (GetIndices(interp, objc-6, objv + 6, &indices) != TCL_OK) {
1560        return TCL_ERROR;
1561    }
1562    for (unsigned int i = 0; i < indices.size(); ++i) {
1563        if ((indices[i] < NanoVis::heightMap.size()) &&
1564            (NanoVis::heightMap[indices[i]] != NULL)) {
1565            NanoVis::heightMap[indices[i]]->setLineContourColor(rgb);
1566        }
1567    }
1568    return TCL_OK;
1569}
1570
1571static int
1572HeightMapLineContourVisibleOp(ClientData cdata, Tcl_Interp *interp, int objc,
1573                              Tcl_Obj *CONST *objv)
1574{
1575    int ivisible;
1576    bool visible;
1577    if (Tcl_GetBooleanFromObj(interp, objv[3], &ivisible) != TCL_OK) {
1578        return TCL_ERROR;
1579    }
1580    visible = (bool)ivisible;
1581    vector<unsigned int> indices;
1582    if (GetIndices(interp, objc-4, objv+4, &indices) != TCL_OK) {
1583        return TCL_ERROR;
1584    }
1585    for (unsigned int i = 0; i < indices.size(); ++i) {
1586        if ((indices[i] < NanoVis::heightMap.size()) &&
1587            (NanoVis::heightMap[indices[i]] != NULL)) {
1588            NanoVis::heightMap[indices[i]]->setLineContourVisible(visible);
1589        }
1590    }
1591    return TCL_OK;
1592}
1593
1594static Rappture::CmdSpec heightMapLineContourOps[] =
1595{
1596    {"color",   1, HeightMapLineContourColorOp,   4, 4, "length",},
1597    {"visible", 1, HeightMapLineContourVisibleOp, 4, 0, "bool ?indices?",},
1598};
1599static int nHeightMapLineContourOps = NumCmdSpecs(heightMapLineContourOps);
1600
1601static int
1602HeightMapLineContourOp(ClientData cdata, Tcl_Interp *interp, int objc,
1603                        Tcl_Obj *CONST *objv)
1604{
1605    Tcl_ObjCmdProc *proc;
1606
1607    proc = Rappture::GetOpFromObj(interp, nHeightMapLineContourOps,
1608        heightMapLineContourOps, Rappture::CMDSPEC_ARG2, objc, objv, 0);
1609    if (proc == NULL) {
1610        return TCL_ERROR;
1611    }
1612    return (*proc) (cdata, interp, objc, objv);
1613}
1614
1615static int
1616HeightMapCullOp(ClientData cdata, Tcl_Interp *interp, int objc,
1617                   Tcl_Obj *CONST *objv)
1618{
1619    graphics::RenderContext::CullMode mode;
1620    if (GetCullMode(interp, objv[2], &mode) != TCL_OK) {
1621        return TCL_ERROR;
1622    }
1623    NanoVis::renderContext->setCullMode(mode);
1624    return TCL_OK;
1625}
1626
1627static int
1628HeightMapCreateOp(ClientData cdata, Tcl_Interp *interp, int objc,
1629                  Tcl_Obj *CONST *objv)
1630{
1631    HeightMap *hMap;
1632   
1633    /* heightmap create xmin ymin xmax ymax xnum ynum values */
1634    hMap = CreateHeightMap(cdata, interp, objc - 2, objv + 2);
1635    if (hMap == NULL) {
1636        return TCL_ERROR;
1637    }
1638    NanoVis::heightMap.push_back(hMap);
1639    Tcl_SetIntObj(Tcl_GetObjResult(interp), NanoVis::heightMap.size() - 1);;
1640    return TCL_OK;
1641}
1642
1643static int
1644HeightMapLegendOp(ClientData cdata, Tcl_Interp *interp, int objc,
1645                  Tcl_Obj *CONST *objv)
1646{
1647    HeightMap *hMap;
1648    if (GetHeightMap(interp, objv[2], &hMap) != TCL_OK) {
1649        return TCL_ERROR;
1650    }
1651    TransferFunction *tf;
1652    tf = hMap->getColorMap();
1653    if (tf == NULL) {
1654        Tcl_AppendResult(interp, "no transfer function defined for heightmap \"",
1655                Tcl_GetString(objv[2]), "\"", (char*)NULL);
1656        return TCL_ERROR;
1657    }
1658    int w, h;
1659    if ((Tcl_GetIntFromObj(interp, objv[3], &w) != TCL_OK) ||
1660        (Tcl_GetIntFromObj(interp, objv[4], &h) != TCL_OK)) {
1661        return TCL_ERROR;
1662    }
1663    NanoVis::render_legend(tf, hMap->range_min(), hMap->range_max(),
1664                           w, h, "label");
1665    return TCL_OK;
1666}
1667
1668static int
1669HeightMapPolygonOp(ClientData cdata, Tcl_Interp *interp, int objc,
1670                   Tcl_Obj *CONST *objv)
1671{
1672    graphics::RenderContext::PolygonMode mode;
1673    if (GetPolygonMode(interp, objv[2], &mode) != TCL_OK) {
1674        return TCL_ERROR;
1675    }
1676    NanoVis::renderContext->setPolygonMode(mode);
1677    return TCL_OK;
1678}
1679
1680static int
1681HeightMapShadeOp(ClientData cdata, Tcl_Interp *interp, int objc,
1682                   Tcl_Obj *CONST *objv)
1683{
1684    graphics::RenderContext::ShadingModel model;
1685    if (GetShadingModel(interp, objv[2], &model) != TCL_OK) {
1686        return TCL_ERROR;
1687    }
1688    NanoVis::renderContext->setShadingModel(model);
1689    return TCL_OK;
1690}
1691
1692static int
1693HeightMapTestOp(ClientData cdata, Tcl_Interp *interp, int objc,
1694        Tcl_Obj *CONST *objv)
1695{
1696    srand((unsigned)time(NULL));
1697
1698    int size = 20 * 200;
1699    double sigma = 5.0;
1700    double mean = exp(0.0) / (sigma * sqrt(2.0));
1701    float* data = (float*) malloc(sizeof(float) * size);
1702   
1703    float x;
1704    for (int i = 0; i < size; ++i) {
1705        x = - 10 + i%20;
1706        data[i] = exp(- (x * x)/(2 * sigma * sigma)) /
1707            (sigma * sqrt(2.0)) / mean * 2 + 1000;
1708    }
1709   
1710    HeightMap* heightMap = new HeightMap();
1711    float minx = 0.0f;
1712    float maxx = 1.0f;
1713    float miny = 0.5f;
1714    float maxy = 3.5f;
1715    heightMap->setHeight(minx, miny, maxx, maxy, 20, 200, data);
1716    heightMap->setColorMap(NanoVis::get_transfunc("default"));
1717    heightMap->setVisible(true);
1718    heightMap->setLineContourVisible(true);
1719    NanoVis::heightMap.push_back(heightMap);
1720
1721
1722    Vector3 min(minx, (float) heightMap->range_min(), miny);
1723    Vector3 max(maxx, (float) heightMap->range_max(), maxy);
1724   
1725    NanoVis::grid->setMinMax(min, max);
1726    NanoVis::grid->setVisible(true);
1727   
1728    return TCL_OK;
1729}
1730
1731static int
1732HeightMapTransFuncOp(ClientData cdata, Tcl_Interp *interp, int objc,
1733                     Tcl_Obj *CONST *objv)
1734{
1735    char *name;
1736    name = Tcl_GetString(objv[2]);
1737    TransferFunction *tf;
1738    tf = NanoVis::get_transfunc(name);
1739    if (tf == NULL) {
1740        Tcl_AppendResult(interp, "transfer function \"", name,
1741                         "\" is not defined", (char*)NULL);
1742        return TCL_ERROR;
1743    }
1744    vector<unsigned int> indices;
1745    if (GetIndices(interp, objc - 3, objv + 3, &indices) != TCL_OK) {
1746        return TCL_ERROR;
1747    }
1748    for (unsigned int i = 0; i < indices.size(); ++i) {
1749        if ((indices[i] < NanoVis::heightMap.size()) &&
1750            (NanoVis::heightMap[indices[i]] != NULL)) {
1751            NanoVis::heightMap[indices[i]]->setColorMap(tf);
1752        }
1753    }
1754    return TCL_OK;
1755}
1756
1757static Rappture::CmdSpec heightMapOps[] =
1758{
1759    {"create",       2, HeightMapCreateOp,      9, 9,
1760        "xmin ymin xmax ymax xnum ynum values",},
1761    {"cull",         2, HeightMapCullOp,        3, 3, "mode",},
1762    {"data",         1, HeightMapDataOp,        3, 0, "oper ?args?",},
1763    {"legend",       2, HeightMapLegendOp,      5, 5, "index width height",},
1764    {"linecontour",  2, HeightMapLineContourOp, 2, 0, "oper ?args?",},
1765    {"polygon",      1, HeightMapPolygonOp,     3, 3, "mode",},
1766    {"shade",        1, HeightMapShadeOp,       3, 3, "model",},
1767    {"test",         2, HeightMapTestOp,        2, 2, "",},
1768    {"transfunc",    2, HeightMapTransFuncOp,   3, 0, "name ?indices?",},
1769};
1770static int nHeightMapOps = NumCmdSpecs(heightMapOps);
1771
1772static int
1773HeightMapCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
1774{
1775    Tcl_ObjCmdProc *proc;
1776
1777    proc = Rappture::GetOpFromObj(interp, nHeightMapOps, heightMapOps,
1778        Rappture::CMDSPEC_ARG1, objc, objv, 0);
1779    if (proc == NULL) {
1780        return TCL_ERROR;
1781    }
1782    return (*proc) (cdata, interp, objc, objv);
1783}
1784
1785static int
1786GridCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
1787{
1788    if (objc < 2) {
1789        Tcl_AppendResult(interp, "wrong # args: should be \"",
1790                Tcl_GetString(objv[0]), " option ?args?", (char *)NULL);
1791        return TCL_ERROR;
1792    }
1793    char *string = Tcl_GetString(objv[1]);
1794    char c = string[0];
1795    if ((c == 'v') && (strcmp(string,"visible") == 0)) {
1796        int ivisible;
1797
1798        if (Tcl_GetBooleanFromObj(interp, objv[2], &ivisible) != TCL_OK) {
1799            return TCL_ERROR;
1800        }
1801        NanoVis::grid->setVisible((bool)ivisible);
1802    } else if ((c == 'l') && (strcmp(string, "linecount") == 0)) {
1803        int x, y, z;
1804
1805        if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) ||
1806            (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK) ||
1807            (Tcl_GetIntFromObj(interp, objv[4], &z) != TCL_OK)) {
1808            return TCL_ERROR;
1809        }
1810        if (NanoVis::grid) {
1811            NanoVis::grid->setGridLineCount(x, y, z);
1812        }
1813    } else if ((c == 'a') && (strcmp(string, "axiscolor") == 0)) {
1814        float r, g, b, a;
1815        if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
1816            (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
1817            (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
1818            return TCL_ERROR;
1819        }
1820        a = 1.0f;
1821        if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
1822            return TCL_ERROR;
1823        }           
1824        if (NanoVis::grid) {
1825            NanoVis::grid->setAxisColor(r, g, b, a);
1826        }
1827    } else if ((c == 'l') && (strcmp(string, "linecolor") == 0)) {
1828        float r, g, b, a;
1829        if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
1830            (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
1831            (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
1832            return TCL_ERROR;
1833        }
1834        a = 1.0f;
1835        if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
1836            return TCL_ERROR;
1837        }           
1838        if (NanoVis::grid) {
1839            NanoVis::grid->setGridLineColor(r, g, b, a);
1840        }
1841    } else if ((c == 'm') && (strcmp(string, "minmax") == 0)) {
1842        double x1, y1, z1, x2, y2, z2;
1843        if ((Tcl_GetDoubleFromObj(interp, objv[2], &x1) != TCL_OK) ||
1844            (Tcl_GetDoubleFromObj(interp, objv[3], &y1) != TCL_OK) ||
1845            (Tcl_GetDoubleFromObj(interp, objv[4], &z1) != TCL_OK) ||
1846            (Tcl_GetDoubleFromObj(interp, objv[5], &x2) != TCL_OK) ||
1847            (Tcl_GetDoubleFromObj(interp, objv[6], &y2) != TCL_OK) ||
1848            (Tcl_GetDoubleFromObj(interp, objv[7], &z2) != TCL_OK)) {
1849            return TCL_ERROR;
1850        }
1851        if (NanoVis::grid) {
1852            NanoVis::grid->setMinMax(Vector3(x1, y1, z1), Vector3(x2, y2, z2));
1853        }
1854    } else if ((c == 'a') && (strcmp(string, "axisname") == 0)) {
1855        int axisId;
1856        if (GetAxisFromObj(interp, objv[2], &axisId) != TCL_OK) {
1857            return TCL_ERROR;
1858        }
1859        if (NanoVis::grid) {
1860            NanoVis::grid->setAxisName(axisId, Tcl_GetString(objv[3]));
1861        }
1862    } else {
1863        Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[1]),
1864                         "\": should be data, outline, shading, or state",
1865                         (char*)NULL);
1866        return TCL_ERROR;
1867    }
1868    return TCL_OK;
1869}
1870
1871static int
1872AxisCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
1873{
1874    if (objc < 2) {
1875        Tcl_AppendResult(interp, "wrong # args: should be \"",
1876                Tcl_GetString(objv[0]), " option arg arg...\"", (char*)NULL);
1877        return TCL_ERROR;
1878    }
1879    char *string = Tcl_GetString(objv[1]);
1880    char c = string[0];
1881    if ((c == 'v') && (strcmp(string, "visible") == 0)) {
1882        int ivisible;
1883
1884        if (Tcl_GetBooleanFromObj(interp, objv[2], &ivisible) != TCL_OK) {
1885            return TCL_ERROR;
1886        }
1887        NanoVis::axis_on = (bool)ivisible;
1888    } else {
1889        Tcl_AppendResult(interp, "bad axis option \"", string,
1890                         "\": should be visible", (char*)NULL);
1891        return TCL_ERROR;
1892    }
1893    return TCL_OK;
1894}
1895
1896/*
1897 * ----------------------------------------------------------------------
1898 * FUNCTION: GetHeightMap
1899 *
1900 * Used internally to decode a series of volume index values and
1901 * store then in the specified vector.  If there are no volume index
1902 * arguments, this means "all volumes" to most commands, so all
1903 * active volume indices are stored in the vector.
1904 *
1905 * Updates pushes index values into the vector.  Returns TCL_OK or
1906 * TCL_ERROR to indicate an error.
1907 * ----------------------------------------------------------------------
1908 */
1909static int
1910GetHeightMap(Tcl_Interp *interp, Tcl_Obj *objPtr, HeightMap **hmPtrPtr)
1911{
1912    int mapIndex;
1913    if (Tcl_GetIntFromObj(interp, objPtr, &mapIndex) != TCL_OK) {
1914        return TCL_ERROR;
1915    }
1916    if ((mapIndex < 0) || (mapIndex >= (int)NanoVis::heightMap.size()) ||
1917        (NanoVis::heightMap[mapIndex] == NULL)) {
1918        Tcl_AppendResult(interp, "invalid heightmap index \"",
1919                Tcl_GetString(objPtr), "\"", (char *)NULL);
1920        return TCL_ERROR;
1921    }
1922    *hmPtrPtr = NanoVis::heightMap[mapIndex];
1923    return TCL_OK;
1924}
1925
1926/*
1927 * ----------------------------------------------------------------------
1928 * FUNCTION: GetVolumeIndex
1929 *
1930 * Used internally to decode a series of volume index values and
1931 * store then in the specified vector.  If there are no volume index
1932 * arguments, this means "all volumes" to most commands, so all
1933 * active volume indices are stored in the vector.
1934 *
1935 * Updates pushes index values into the vector.  Returns TCL_OK or
1936 * TCL_ERROR to indicate an error.
1937 * ----------------------------------------------------------------------
1938 */
1939static int
1940GetVolumeIndex(Tcl_Interp *interp, Tcl_Obj *objPtr, unsigned int *indexPtr)
1941{
1942    int index;
1943    if (Tcl_GetIntFromObj(interp, objPtr, &index) != TCL_OK) {
1944        return TCL_ERROR;
1945    }
1946    if (index < 0) {
1947        Tcl_AppendResult(interp, "can't have negative index \"",
1948                Tcl_GetString(objPtr), "\"", (char*)NULL);
1949        return TCL_ERROR;
1950    }
1951    if (index >= (int)NanoVis::volume.size()) {
1952        Tcl_AppendResult(interp, "index \"", Tcl_GetString(objPtr),
1953                         "\" is out of range", (char*)NULL);
1954        return TCL_ERROR;
1955    }
1956    *indexPtr = (unsigned int)index;
1957    return TCL_OK;
1958}
1959
1960/*
1961 * ----------------------------------------------------------------------
1962 * FUNCTION: GetVolumeFromObj
1963 *
1964 * Used internally to decode a series of volume index values and
1965 * store then in the specified vector.  If there are no volume index
1966 * arguments, this means "all volumes" to most commands, so all
1967 * active volume indices are stored in the vector.
1968 *
1969 * Updates pushes index values into the vector.  Returns TCL_OK or
1970 * TCL_ERROR to indicate an error.
1971 * ----------------------------------------------------------------------
1972 */
1973static int
1974GetVolumeFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Volume **volPtrPtr)
1975{
1976    unsigned int index;
1977    if (GetVolumeIndex(interp, objPtr, &index) != TCL_OK) {
1978        return TCL_ERROR;
1979    }
1980    Volume *vol;
1981    vol = NanoVis::volume[index];
1982    if (vol == NULL) {
1983        Tcl_AppendResult(interp, "no volume defined for index \"",
1984                Tcl_GetString(objPtr), "\"", (char*)NULL);
1985        return TCL_ERROR;
1986    }
1987    *volPtrPtr = vol;
1988    return TCL_OK;
1989}
1990
1991/*
1992 * ----------------------------------------------------------------------
1993 * FUNCTION: GetVolumeIndices()
1994 *
1995 * Used internally to decode a series of volume index values and
1996 * store then in the specified vector.  If there are no volume index
1997 * arguments, this means "all volumes" to most commands, so all
1998 * active volume indices are stored in the vector.
1999 *
2000 * Updates pushes index values into the vector.  Returns TCL_OK or
2001 * TCL_ERROR to indicate an error.
2002 * ----------------------------------------------------------------------
2003 */
2004static int
2005GetVolumeIndices(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
2006    vector<unsigned int>* vectorPtr)
2007{
2008    if (objc == 0) {
2009        for (unsigned int n = 0; n < NanoVis::volume.size(); n++) {
2010            if (NanoVis::volume[n] != NULL) {
2011                vectorPtr->push_back(n);
2012            }
2013        }
2014    } else {
2015        for (int n = 0; n < objc; n++) {
2016            unsigned int index;
2017
2018            if (GetVolumeIndex(interp, objv[n], &index) != TCL_OK) {
2019                return TCL_ERROR;
2020            }
2021            if (index < NanoVis::volume.size() && NanoVis::volume[index] != NULL) {
2022                vectorPtr->push_back(index);
2023            }
2024        }
2025    }
2026    return TCL_OK;
2027}
2028
2029static int
2030GetIndices(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
2031    vector<unsigned int>* vectorPtr)
2032{
2033    for (int n = 0; n < objc; n++) {
2034        int index;
2035
2036        if (Tcl_GetIntFromObj(interp, objv[n], &index) != TCL_OK) {
2037            return TCL_ERROR;
2038        }
2039        if (index < 0) {
2040            Tcl_AppendResult(interp, "can't have negative index \"",
2041                Tcl_GetString(objv[n]), "\"", (char *)NULL);
2042            return TCL_ERROR;
2043        }
2044        vectorPtr->push_back((unsigned int)index);
2045    }
2046    return TCL_OK;
2047}
2048
2049
2050/*
2051 * ----------------------------------------------------------------------
2052 * FUNCTION: GetVolumes()
2053 *
2054 * Used internally to decode a series of volume index values and
2055 * store then in the specified vector.  If there are no volume index
2056 * arguments, this means "all volumes" to most commands, so all
2057 * active volume indices are stored in the vector.
2058 *
2059 * Updates pushes index values into the vector.  Returns TCL_OK or
2060 * TCL_ERROR to indicate an error.
2061 * ----------------------------------------------------------------------
2062 */
2063static int
2064GetVolumes(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv,
2065    vector<Volume *>* vectorPtr)
2066{
2067    if (objc == 0) {
2068        for (unsigned int n = 0; n < NanoVis::volume.size(); n++) {
2069            if (NanoVis::volume[n] != NULL) {
2070                vectorPtr->push_back(NanoVis::volume[n]);
2071            }
2072        }
2073    } else {
2074        for (int n = 0; n < objc; n++) {
2075            Volume *volPtr;
2076
2077            if (GetVolumeFromObj(interp, objv[n], &volPtr) != TCL_OK) {
2078                return TCL_ERROR;
2079            }
2080            if (volPtr != NULL) {
2081                vectorPtr->push_back(volPtr);
2082            }
2083        }
2084    }
2085    return TCL_OK;
2086}
2087
2088
2089/*
2090 * ----------------------------------------------------------------------
2091 * FUNCTION: GetAxis()
2092 *
2093 * Used internally to decode an axis value from a string ("x", "y",
2094 * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
2095 * along with a value in valPtr.  Otherwise, it returns TCL_ERROR
2096 * and an error message in the interpreter.
2097 * ----------------------------------------------------------------------
2098 */
2099static int
2100GetAxis(Tcl_Interp *interp, const char *string, int *indexPtr)
2101{
2102    if (string[1] == '\0') {
2103        char c;
2104
2105        c = tolower((unsigned char)string[0]);
2106        if (c == 'x') {
2107            *indexPtr = 0;
2108            return TCL_OK;
2109        } else if (c == 'y') {
2110            *indexPtr = 1;
2111            return TCL_OK;
2112        } else if (c == 'z') {
2113            *indexPtr = 2;
2114            return TCL_OK;
2115        }
2116        /*FALLTHRU*/
2117    }
2118    Tcl_AppendResult(interp, "bad axis \"", string,
2119        "\": should be x, y, or z", (char*)NULL);
2120    return TCL_ERROR;
2121}
2122
2123
2124/*
2125 * ----------------------------------------------------------------------
2126 * FUNCTION: GetAxisFromObj()
2127 *
2128 * Used internally to decode an axis value from a string ("x", "y",
2129 * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
2130 * along with a value in indexPtr.  Otherwise, it returns TCL_ERROR
2131 * and an error message in the interpreter.
2132 * ----------------------------------------------------------------------
2133 */
2134static int
2135GetAxisFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr)
2136{
2137    return GetAxis(interp, Tcl_GetString(objPtr), indexPtr);
2138}
2139
2140/*
2141 * ----------------------------------------------------------------------
2142 * FUNCTION: GetAxisDirFromObj()
2143 *
2144 * Used internally to decode an axis value from a string ("x", "y",
2145 * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
2146 * along with a value in indexPtr.  Otherwise, it returns TCL_ERROR
2147 * and an error message in the interpreter.
2148 * ----------------------------------------------------------------------
2149 */
2150static int
2151GetAxisDirFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *indexPtr, int *dirPtr)
2152{
2153    char *string = Tcl_GetString(objPtr);
2154
2155    int sign = 1;
2156    if (*string == '-') {
2157        sign = -1;
2158        string++;
2159    }
2160    if (GetAxis(interp, string, indexPtr) != TCL_OK) {
2161        return TCL_ERROR;
2162    }
2163    if (dirPtr != NULL) {
2164        *dirPtr = sign;
2165    }
2166    return TCL_OK;
2167}
2168
2169/*
2170 * ----------------------------------------------------------------------
2171 * FUNCTION: GetColor()
2172 *
2173 * Used internally to decode a color value from a string ("R G B")
2174 * as a list of three numbers 0-1.  Returns TCL_OK if successful,
2175 * along with RGB values in rgbPtr.  Otherwise, it returns TCL_ERROR
2176 * and an error message in the interpreter.
2177 * ----------------------------------------------------------------------
2178 */
2179static int
2180GetColor(Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv, float *rgbPtr)
2181{
2182    if (objc < 3) {
2183        Tcl_AppendResult(interp, "missing color values\": ",
2184                "should list of R G B values 0.0 - 1.0", (char*)NULL);
2185        return TCL_ERROR;
2186    }
2187    if ((GetFloatFromObj(interp, objv[0], rgbPtr + 0) != TCL_OK) ||
2188        (GetFloatFromObj(interp, objv[1], rgbPtr + 1) != TCL_OK) ||
2189        (GetFloatFromObj(interp, objv[2], rgbPtr + 2) != TCL_OK)) {
2190        return TCL_ERROR;
2191    }
2192    return TCL_OK;
2193}
2194
2195
2196#if PLANE_CMDS
2197static int
2198PlaneNewCmd(ClientData cdata, Tcl_Interp *interp, int objc,
2199            Tcl_Obj *CONST *objv)
2200{
2201    fprintf(stderr, "load plane for 2D visualization command\n");
2202    int index, w, h;
2203    if (objc != 4) {
2204        Tcl_AppendResult(interp, "wrong # args: should be \"",
2205                Tcl_GetString(objv[0]), " plane_index w h \"", (char*)NULL);
2206        return TCL_ERROR;
2207    }
2208    if (Tcl_GetIntFromObj(interp, objv[1], &index) != TCL_OK) {
2209        return TCL_ERROR;
2210    }
2211    if (Tcl_GetIntFromObj(interp, objv[2], &w) != TCL_OK) {
2212        return TCL_ERROR;
2213    }
2214    if (Tcl_GetIntFromObj(interp, objv[3], &h) != TCL_OK) {
2215        return TCL_ERROR;
2216    }
2217   
2218    //Now read w*h*4 bytes. The server expects the plane to be a stream of floats
2219    char* tmp = new char[int(w*h*sizeof(float))];
2220    if (tmp == NULL) {
2221        Tcl_AppendResult(interp, "can't allocate stream data", (char *)NULL);
2222        return TCL_ERROR;
2223    }
2224    bzero(tmp, w*h*4);
2225    int status = read(0, tmp, w*h*sizeof(float));
2226    if (status <= 0) {
2227        exit(0);                // Bail out on read error?  Should log the
2228                                // error and return a non-zero exit status.
2229    }
2230    plane[index] = new Texture2D(w, h, GL_FLOAT, GL_LINEAR, 1, (float*)tmp);
2231    delete[] tmp;
2232    return TCL_OK;
2233}
2234
2235
2236static int
2237PlaneLinkCmd(ClientData cdata, Tcl_Interp *interp, int objc,
2238             Tcl_Obj *CONST *objv)
2239{
2240    fprintf(stderr, "link the plane to the 2D renderer command\n");
2241   
2242    int plane_index, tf_index;
2243   
2244    if (objc != 3) {
2245        Tcl_AppendResult(interp, "wrong # args: should be \"",
2246                Tcl_GetString(objv[0]), " plane_index tf_index \"", (char*)NULL);
2247        return TCL_ERROR;
2248    }
2249    if (Tcl_GetIntFromObj(interp, objv[1], &plane_index) != TCL_OK) {
2250        return TCL_ERROR;
2251    }
2252    if (Tcl_GetIntFromObj(interp, objv[2], &tf_index) != TCL_OK) {
2253        return TCL_ERROR;
2254    }
2255    //plane_render->add_plane(plane[plane_index], tf[tf_index]);
2256    return TCL_OK;
2257}
2258
2259//Enable a 2D plane for render
2260//The plane_index is the index mantained in the 2D plane renderer
2261static int
2262PlaneEnableCmd(ClientData cdata, Tcl_Interp *interp, int objc,
2263        Tcl_Obj *CONST *objv)
2264{
2265    fprintf(stderr,"enable a plane so the 2D renderer can render it command\n");
2266   
2267    if (objc != 3) {
2268        Tcl_AppendResult(interp, "wrong # args: should be \"",
2269                Tcl_GetString(objv[0]), " plane_index mode \"", (char*)NULL);
2270        return TCL_ERROR;
2271    }
2272    int plane_index;
2273    if (Tcl_GetIntFromObj(interp, objv[1], &plane_index) != TCL_OK) {
2274        return TCL_ERROR;
2275    }
2276    int mode;
2277    if (Tcl_GetIntFromObj(interp, objv[2], &mode) != TCL_OK) {
2278        return TCL_ERROR;
2279    }
2280    if (mode == 0) {
2281        plane_index = -1;
2282    }
2283    plane_render->set_active_plane(plane_index);
2284    return TCL_OK;
2285}
2286#endif  /*PLANE_CMDS*/
2287
2288void
2289initTcl()
2290{
2291    interp = Tcl_CreateInterp();
2292    Tcl_MakeSafe(interp);
2293
2294    Tcl_DStringInit(&cmdbuffer);
2295
2296    // manipulate the viewpoint
2297    Tcl_CreateObjCommand(interp, "camera", CameraCmd,
2298        NULL, (Tcl_CmdDeleteProc*)NULL);
2299
2300    // turn on/off cut planes in x/y/z directions
2301    Tcl_CreateObjCommand(interp, "cutplane", CutplaneCmd,
2302        NULL, (Tcl_CmdDeleteProc*)NULL);
2303
2304    // request the legend for a plot (transfer function)
2305    Tcl_CreateObjCommand(interp, "legend", LegendCmd,
2306        NULL, (Tcl_CmdDeleteProc*)NULL);
2307
2308    // change the size of the screen (size of picture generated)
2309    Tcl_CreateObjCommand(interp, "screen", ScreenCmd,
2310        NULL, (Tcl_CmdDeleteProc*)NULL);
2311
2312    // manipulate transfer functions
2313    Tcl_CreateObjCommand(interp, "transfunc", TransfuncCmd,
2314        NULL, (Tcl_CmdDeleteProc*)NULL);
2315
2316    // set the "up" direction for volumes
2317    Tcl_CreateObjCommand(interp, "up", UpCmd,
2318        NULL, (Tcl_CmdDeleteProc*)NULL);
2319
2320    // manipulate volume data
2321    Tcl_CreateObjCommand(interp, "volume", VolumeCmd,
2322        NULL, (Tcl_CmdDeleteProc*)NULL);
2323
2324    Tcl_CreateObjCommand(interp, "flow", FlowCmd,
2325        NULL, (Tcl_CmdDeleteProc*)NULL);
2326
2327    Tcl_CreateObjCommand(interp, "axis", AxisCmd,
2328        NULL, (Tcl_CmdDeleteProc*)NULL);
2329
2330    Tcl_CreateObjCommand(interp, "grid", GridCmd,
2331        NULL, (Tcl_CmdDeleteProc*)NULL);
2332
2333    Tcl_CreateObjCommand(interp, "heightmap", HeightMapCmd,
2334        NULL, (Tcl_CmdDeleteProc*)NULL);
2335
2336    // get screenshot
2337    Tcl_CreateObjCommand(interp, "screenshot", ScreenShotCmd,
2338        NULL, (Tcl_CmdDeleteProc*)NULL);
2339
2340    Tcl_CreateObjCommand(interp, "unirect2d", UniRect2dCmd,
2341        NULL, (Tcl_CmdDeleteProc*)NULL);
2342
2343    Tcl_CreateObjCommand(interp, "axis", AxisCmd,
2344        NULL, (Tcl_CmdDeleteProc*)NULL);
2345
2346    Tcl_CreateObjCommand(interp, "grid", GridCmd,
2347        NULL, (Tcl_CmdDeleteProc*)NULL);
2348
2349    Tcl_CreateObjCommand(interp, "heightmap", HeightMapCmd,
2350        NULL, (Tcl_CmdDeleteProc*)NULL);
2351
2352    // get screenshot
2353    Tcl_CreateObjCommand(interp, "screenshot", ScreenShotCmd,
2354        NULL, (Tcl_CmdDeleteProc*)NULL);
2355
2356    Tcl_CreateObjCommand(interp, "unirect2d", UniRect2dCmd,
2357        NULL, (Tcl_CmdDeleteProc*)NULL);
2358
2359#if __TEST_CODE__
2360    Tcl_CreateObjCommand(interp, "test", TestCmd,
2361        NULL, (Tcl_CmdDeleteProc*)NULL);
2362
2363
2364//    Tcl_CreateObjCommand(interp, "flow", FlowCmd,
2365 //       NULL, (Tcl_CmdDeleteProc*)NULL);
2366#endif
2367
2368    // create a default transfer function
2369    if (Tcl_Eval(interp, def_transfunc) != TCL_OK) {
2370        fprintf(stdin, "WARNING: bad default transfer function\n");
2371        fprintf(stdin, Tcl_GetStringResult(interp));
2372    }
2373}
2374
2375
2376void
2377xinetd_listen()
2378{
2379    int flags = fcntl(0, F_GETFL, 0);
2380    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2381
2382    int status = TCL_OK;
2383    int npass = 0;
2384
2385    //
2386    //  Read and execute as many commands as we can from stdin...
2387    //
2388    while (status == TCL_OK) {
2389        //
2390        //  Read the next command from the buffer.  First time through
2391        //  we block here and wait if necessary until a command comes in.
2392        //
2393        //  BE CAREFUL:  Read only one command, up to a newline.
2394        //  The "volume data follows" command needs to be able to read
2395        //  the data immediately following the command, and we shouldn't
2396        //  consume it here.
2397        //
2398        while (1) {
2399            char c = getchar();
2400            if (c <= 0) {
2401                if (npass == 0) {
2402                    exit(0);  // EOF -- we're done!
2403                } else {
2404                    break;
2405                }
2406            }
2407            Tcl_DStringAppend(&cmdbuffer, &c, 1);
2408
2409            if (c=='\n' && Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer))) {
2410                break;
2411            }
2412        }
2413
2414        // no command? then we're done for now
2415        if (Tcl_DStringLength(&cmdbuffer) == 0) {
2416            break;
2417        }
2418
2419        // back to original flags during command evaluation...
2420        fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2421        status = Tcl_Eval(interp, Tcl_DStringValue(&cmdbuffer));
2422        Tcl_DStringSetLength(&cmdbuffer, 0);
2423
2424        // non-blocking for next read -- we might not get anything
2425        fcntl(0, F_SETFL, flags | O_NONBLOCK);
2426        npass++;
2427    }
2428    fcntl(0, F_SETFL, flags);
2429
2430    if (status != TCL_OK) {
2431        std::ostringstream errmsg;
2432        errmsg << "ERROR: " << Tcl_GetStringResult(interp) << std::endl;
2433        write(0, errmsg.str().c_str(), errmsg.str().size());
2434        return;
2435    }
2436
2437    //
2438    // This is now in "FlowCmd()":
2439    //  Generate the latest frame and send it back to the client
2440    //
2441    /*
2442    if (NanoVis::licRenderer && NanoVis::licRenderer->isActivated())
2443    {
2444        NanoVis::licRenderer->convolve();
2445    }
2446
2447    if (NanoVis::particleRenderer && NanoVis::particleRenderer->isActivated())
2448    {
2449        NanoVis::particleRenderer->advect();
2450    }
2451    */
2452
2453    NanoVis::update();
2454
2455    NanoVis::offscreen_buffer_capture();  //enable offscreen render
2456
2457    NanoVis::display();
2458   
2459    // INSOO
2460#ifdef XINETD
2461   NanoVis::read_screen();
2462   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2463#else
2464   NanoVis::display_offscreen_buffer(); //display the final rendering on screen
2465   NanoVis::read_screen();
2466   glutSwapBuffers();
2467#endif   
2468
2469#if DO_RLE
2470    do_rle();
2471    int sizes[2] = {  offsets_size*sizeof(offsets[0]), rle_size };
2472    fprintf(stderr, "Writing %d,%d\n", sizes[0], sizes[1]); fflush(stderr);
2473    write(0, &sizes, sizeof(sizes));
2474    write(0, offsets, offsets_size*sizeof(offsets[0]));
2475    write(0, rle, rle_size);    //unsigned byte
2476#else
2477    NanoVis::bmp_write("nv>image -bytes");
2478#endif
2479}
2480
2481
2482/*
2483 * -----------------------------------------------------------------------
2484 *
2485 * GetDataStream --
2486 *
2487 *      Read the requested number of bytes from standard input into the given
2488 *      buffer.  The buffer is then decompressed and decoded.
2489 *
2490 * -----------------------------------------------------------------------
2491 */
2492static int
2493GetDataStream(Tcl_Interp *interp, Rappture::Buffer &buf, int nBytes)
2494{
2495    char buffer[8096];
2496
2497    clearerr(stdin);
2498    while (nBytes > 0) {
2499        unsigned int chunk;
2500        int nRead;
2501
2502        chunk = (sizeof(buffer) < (unsigned int) nBytes) ?
2503            sizeof(buffer) : nBytes;
2504        nRead = fread(buffer, sizeof(char), chunk, stdin);
2505        if (ferror(stdin)) {
2506            Tcl_AppendResult(interp, "while reading data stream: ",
2507                Tcl_PosixError(interp), (char*)NULL);
2508            return TCL_ERROR;
2509        }
2510        if (feof(stdin)) {
2511            Tcl_AppendResult(interp, "premature EOF while reading data stream",
2512                (char*)NULL);
2513            return TCL_ERROR;
2514        }
2515        buf.append(buffer, nRead);
2516        nBytes -= nRead;
2517    }
2518    {
2519        Rappture::Outcome err;
2520
2521        err = Rappture::encoding::decode(buf, RPENC_Z|RPENC_B64|RPENC_HDR);
2522        if (err) {
2523            printf("ERROR -- DECODING\n");
2524            fflush(stdout);
2525            Tcl_AppendResult(interp, err.remark().c_str(), (char*)NULL);
2526            return TCL_ERROR;
2527        }
2528    }
2529    return TCL_OK;
2530}
2531
2532/*
2533 * -----------------------------------------------------------------------
2534 *
2535 * CreateHeightMap --
2536 *
2537 *      Creates a heightmap from the given the data. The format of the data
2538 *      should be as follows:
2539 *
2540 *              xMin, xMax, xNum, yMin, yMax, yNum, heights...
2541 *
2542 *      xNum and yNum must be integer values, all others are real numbers.
2543 *      The number of heights must be xNum * yNum;
2544 *
2545 * -----------------------------------------------------------------------
2546 */
2547static HeightMap *
2548CreateHeightMap(ClientData clientData, Tcl_Interp *interp, int objc,
2549                Tcl_Obj *CONST *objv)
2550{
2551    float xMin, yMin, xMax, yMax;
2552    int xNum, yNum;
2553
2554    if (objc != 7) {
2555        Tcl_AppendResult(interp,
2556        "wrong # of values: should be xMin yMin xMax yMax xNum yNum heights",
2557                (char *)NULL);
2558        return NULL;
2559    }
2560    if ((GetFloatFromObj(interp, objv[0], &xMin) != TCL_OK) ||
2561        (GetFloatFromObj(interp, objv[1], &yMin) != TCL_OK) ||
2562        (GetFloatFromObj(interp, objv[2], &xMax) != TCL_OK) ||
2563        (GetFloatFromObj(interp, objv[3], &yMax) != TCL_OK) ||
2564        (Tcl_GetIntFromObj(interp, objv[4], &xNum) != TCL_OK) ||
2565        (Tcl_GetIntFromObj(interp, objv[5], &yNum) != TCL_OK)) {
2566        return NULL;
2567    }
2568    int nValues;
2569    Tcl_Obj **elem;
2570    if (Tcl_ListObjGetElements(interp, objv[6], &nValues, &elem) != TCL_OK) {
2571        return NULL;
2572    }
2573    if ((xNum <= 0) || (yNum <= 0)) {
2574        Tcl_AppendResult(interp, "bad number of x or y values", (char *)NULL);
2575        return NULL;
2576    }
2577    if (nValues != (xNum * yNum)) {
2578        Tcl_AppendResult(interp, "wrong # of heights", (char *)NULL);
2579        return NULL;
2580    }
2581
2582    float *heights;
2583    heights = new float[nValues];
2584    if (heights == NULL) {
2585        Tcl_AppendResult(interp, "can't allocate array of heights",
2586                (char *)NULL);
2587        return NULL;
2588    }
2589
2590    int i;
2591    for (i = 0; i < nValues; i++) {
2592        if (GetFloatFromObj(interp, elem[i], heights + i) != TCL_OK) {
2593            delete [] heights;
2594            return NULL;
2595        }
2596    }
2597    HeightMap* hMap;
2598    hMap = new HeightMap();
2599    hMap->setHeight(xMin, yMin, xMax, yMax, xNum, yNum, heights);
2600    hMap->setColorMap(NanoVis::get_transfunc("default"));
2601    hMap->setVisible(true);
2602    hMap->setLineContourVisible(true);
2603    delete [] heights;
2604    return hMap;
2605}
2606
2607/*
2608 * This command should be Tcl procedure instead of a C command.  The reason
2609 * for this that 1) we are using a safe interpreter so we would need a master
2610 * interpreter to load the Tcl environment properly (including our "unirect2d"
2611 * procedure). And 2) the way nanovis is currently deployed, doesn't make it
2612 * easy to add new directories for procedures, since it's loaded into /tmp.
2613 *
2614 * Ideally, the "unirect2d" proc would do a rundimentary parsing of the data
2615 * to verify the structure and then pass it to the appropiate Tcl command
2616 * (heightmap, volume, etc). Our C command always creates a heightmap. 
2617 */
2618static int
2619UniRect2dCmd(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST *objv)
2620{   
2621    int xNum, yNum, zNum;
2622    float xMin, yMin, xMax, yMax;
2623    float *zValues;
2624
2625    if ((objc & 0x01) == 0) {
2626        Tcl_AppendResult(interp, Tcl_GetString(objv[0]), ": ",
2627                "wrong number of arguments: should be key-value pairs",
2628                (char *)NULL);
2629        return TCL_ERROR;
2630    }
2631    zValues = NULL;
2632    xNum = yNum = zNum = 0;
2633    xMin = yMin = xMax = yMax = 0.0f;
2634    int i;
2635    for (i = 1; i < objc; i += 2) {
2636        char *string;
2637
2638        string = Tcl_GetString(objv[i]);
2639        if (strcmp(string, "xmin") == 0) {
2640            if (GetFloatFromObj(interp, objv[i+1], &xMin) != TCL_OK) {
2641                return TCL_ERROR;
2642            }
2643        } else if (strcmp(string, "xmax") == 0) {
2644            if (GetFloatFromObj(interp, objv[i+1], &xMax) != TCL_OK) {
2645                return TCL_ERROR;
2646            }
2647        } else if (strcmp(string, "xnum") == 0) {
2648            if (Tcl_GetIntFromObj(interp, objv[i+1], &xNum) != TCL_OK) {
2649                return TCL_ERROR;
2650            }
2651            if (xNum <= 0) {
2652                Tcl_AppendResult(interp, "bad xnum value: must be > 0",
2653                                 (char *)NULL);
2654                return TCL_ERROR;
2655            }
2656        } else if (strcmp(string, "ymin") == 0) {
2657            if (GetFloatFromObj(interp, objv[i+1], &yMin) != TCL_OK) {
2658                return TCL_ERROR;
2659            }
2660        } else if (strcmp(string, "ymax") == 0) {
2661            if (GetFloatFromObj(interp, objv[i+1], &yMax) != TCL_OK) {
2662                return TCL_ERROR;
2663            }
2664        } else if (strcmp(string, "ynum") == 0) {
2665            if (Tcl_GetIntFromObj(interp, objv[i+1], &yNum) != TCL_OK) {
2666                return TCL_ERROR;
2667            }
2668            if (yNum <= 0) {
2669                Tcl_AppendResult(interp, "bad ynum value: must be > 0",
2670                                 (char *)NULL);
2671                return TCL_ERROR;
2672            }
2673        } else if (strcmp(string, "zvalues") == 0) {
2674            Tcl_Obj **zObj;
2675
2676            if (Tcl_ListObjGetElements(interp, objv[i+1], &zNum, &zObj)!= TCL_OK) {
2677                return TCL_ERROR;
2678            }
2679            int j;
2680            zValues = new float[zNum];
2681            for (j = 0; j < zNum; j++) {
2682                if (GetFloatFromObj(interp, zObj[j], zValues + j) != TCL_OK) {
2683                    return TCL_ERROR;
2684                }
2685            }
2686        } else {
2687            Tcl_AppendResult(interp, "unknown key \"", string,
2688                "\": should be xmin, xmax, xnum, ymin, ymax, ynum, or zvalues",
2689                (char *)NULL);
2690            return TCL_ERROR;
2691        }
2692    }
2693    if (zValues == NULL) {
2694        Tcl_AppendResult(interp, "missing \"zvalues\" key", (char *)NULL);
2695        return TCL_ERROR;
2696    }
2697    if (zNum != (xNum * yNum)) {
2698        Tcl_AppendResult(interp, "wrong number of z values must be xnum*ynum",
2699                (char *)NULL);
2700        return TCL_ERROR;
2701    }
2702    HeightMap* hMap;
2703    hMap = new HeightMap();
2704    hMap->setHeight(xMin, yMin, xMax, yMax, xNum, yNum, zValues);
2705    hMap->setColorMap(NanoVis::get_transfunc("default"));
2706    hMap->setVisible(true);
2707    hMap->setLineContourVisible(true);
2708    NanoVis::heightMap.push_back(hMap);
2709    delete [] zValues;
2710    return TCL_OK;
2711}
Note: See TracBrowser for help on using the repository browser.