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

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