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

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