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

Last change on this file since 928 was 928, checked in by gah, 17 years ago

collect limits for axes

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