source: trunk/packages/vizservers/nanovis/Command.cpp @ 1219

Last change on this file since 1219 was 1219, checked in by gah, 16 years ago

Add pan command to nanovis and pymolproxy

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