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

Last change on this file since 1380 was 1380, checked in by gah, 13 years ago
File size: 87.2 KB
Line 
1
2/*
3 * ----------------------------------------------------------------------
4 * Command.cpp
5 *
6 *      This modules creates the Tcl interface to the nanovis server.  The
7 *      communication protocol of the server is the Tcl language.  Commands
8 *      given to the server by clients are executed in a safe interpreter and
9 *      the resulting image rendered offscreen is returned as BMP-formatted
10 *      image data.
11 *
12 * ======================================================================
13 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
14 *           Michael McLennan <mmclennan@purdue.edu>
15 *           Purdue Rendering and Perceptualization Lab (PURPL)
16 *
17 *  Copyright (c) 2004-2006  Purdue Research Foundation
18 *
19 *  See the file "license.terms" for information on usage and
20 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
21 * ======================================================================
22 */
23
24/*
25 * TODO:  In no particular order...
26 *        x Convert to Tcl_CmdObj interface. (done)
27 *        o Use Tcl command option parser to reduce size of procedures, remove
28 *          lots of extra error checking code. (almost there)
29 *        o Convert GetVolumeIndices to GetVolumes.  Goal is to remove
30 *          all references of Nanovis::volume[] from this file.  Don't
31 *          want to know how volumes are stored. Same for heightmaps.
32 *        o Rationalize volume id scheme. Right now it's the index in
33 *          the vector. 1) Use a list instead of a vector. 2) carry
34 *          an id field that's a number that gets incremented each new volume.
35 *        x Create R2, matrix, etc. libraries. (done)
36 *        o Add bookkeeping for volumes, heightmaps, flows, etc. to track
37 *          1) id #  2) simulation # 3) include/exclude.  The include/exclude
38 *          is to indicate whether the item should contribute to the overall
39 *          limits of the axes.
40 */
41
42#include <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 ISO_TEST                1
75#define PLANE_CMD               0
76#define __TEST_CODE__           0
77// FOR testing new functions
78#define _LOCAL_ZINC_TEST_       0
79
80#if _LOCAL_ZINC_TEST_
81#include "Test.h"
82#endif
83
84// EXTERN DECLARATIONS
85// in Nv.cpp
86
87// in nanovis.cpp
88extern vector<PointSet*> g_pointSet;
89extern int debug_flag;
90
91extern PlaneRenderer* plane_render;
92extern Texture2D* plane[10];
93
94bool load_volume_stream(Rappture::Outcome &status, int index,
95                        std::iostream& fin);
96bool load_volume_stream_odx(Rappture::Outcome &status, int index,
97        const char *buf, int nBytes);
98extern bool load_volume_stream2(Rappture::Outcome &status, int index,
99        std::iostream& fin);
100extern void load_volume(int index, int width, int height, int depth,
101            int n_component, float* data, double vmin, double vmax,
102            double nzero_min);
103extern bool load_vector_stream(Rappture::Outcome &result, int index,
104        std::istream& fin);
105extern bool load_vector_stream2(Rappture::Outcome &result, int index,
106        size_t length, char *bytes);
107extern bool MakeVectorFieldFromUnirect3d(Rappture::Outcome &result,
108        Rappture::Unirect3d &data);
109
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;
143static Tcl_ObjCmdProc FlowCmd;
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    {
690        Rappture::Outcome err;
691        unsigned int flags;
692
693        flags = RPENC_Z|RPENC_B64|RPENC_HDR;
694        if (!Rappture::encoding::decode(err, buf, flags)) {
695            printf("ERROR -- DECODING\n");
696            fflush(stdout);
697            Tcl_AppendResult(interp, err.remark(), (char*)NULL);
698            return TCL_ERROR;
699        }
700    }
701    return TCL_OK;
702}
703
704
705static int
706CameraAimOp(ClientData cdata, Tcl_Interp *interp, int objc,
707            Tcl_Obj *const *objv)
708{
709    float x, y, z;
710    if ((GetFloatFromObj(interp, objv[2], &x) != TCL_OK) ||
711        (GetFloatFromObj(interp, objv[3], &y) != TCL_OK) ||
712        (GetFloatFromObj(interp, objv[4], &z) != TCL_OK)) {
713        return TCL_ERROR;
714    }
715    NanoVis::cam->xAim(x);
716    NanoVis::cam->yAim(y);
717    NanoVis::cam->zAim(z);
718    return TCL_OK;
719}
720
721static int
722CameraAngleOp(ClientData cdata, Tcl_Interp *interp, int objc,
723              Tcl_Obj *const *objv)
724{
725    float theta, phi, psi;
726    if ((GetFloatFromObj(interp, objv[2], &phi) != TCL_OK) ||
727        (GetFloatFromObj(interp, objv[3], &theta) != TCL_OK) ||
728        (GetFloatFromObj(interp, objv[4], &psi) != TCL_OK)) {
729        return TCL_ERROR;
730    }
731    NanoVis::cam->rotate(phi, theta, psi);
732    return TCL_OK;
733}
734
735
736static int
737CameraPanOp(ClientData cdata, Tcl_Interp *interp, int objc,
738             Tcl_Obj *const *objv)
739{
740    float x, y;
741    if ((GetFloatFromObj(interp, objv[2], &x) != TCL_OK) ||
742        (GetFloatFromObj(interp, objv[3], &y) != TCL_OK)) {
743        return TCL_ERROR;
744    }
745    NanoVis::pan(x, y);
746    return TCL_OK;
747}
748
749static int
750CameraZoomOp(ClientData cdata, Tcl_Interp *interp, int objc,
751             Tcl_Obj *const *objv)
752{
753    float zoom;
754    if (GetFloatFromObj(interp, objv[2], &zoom) != TCL_OK) {
755        return TCL_ERROR;
756    }
757    NanoVis::cam->z(-2.5f / zoom);
758    return TCL_OK;
759}
760
761static Rappture::CmdSpec cameraOps[] = {
762    {"aim",     2, CameraAimOp,      5, 5, "x y z",},
763    {"angle",   2, CameraAngleOp,    5, 5, "xAngle yAngle zAngle",},
764    {"pan",     1, CameraPanOp,      4, 4, "x y",},
765    {"zoom",    1, CameraZoomOp,     3, 3, "factor",},
766};
767static int nCameraOps = NumCmdSpecs(cameraOps);
768
769/*
770 * ----------------------------------------------------------------------
771 * CLIENT COMMAND:
772 *   camera aim <x0> <y0> <z0>
773 *   camera angle <xAngle> <yAngle> <zAngle>
774 *   camera zoom <factor>
775 *
776 * Clients send these commands to manipulate the camera.  The "angle"
777 * option controls the angle of the camera around the focal point.
778 * The "zoom" option sets the zoom factor, moving the camera in
779 * and out.
780 * ----------------------------------------------------------------------
781 */
782static int
783CameraCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
784{
785    Tcl_ObjCmdProc *proc;
786
787    proc = Rappture::GetOpFromObj(interp, nCameraOps, cameraOps,
788                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
789    if (proc == NULL) {
790        return TCL_ERROR;
791    }
792    return (*proc) (cdata, interp, objc, objv);
793}
794
795/*ARGSUSED*/
796static int
797SnapshotCmd(ClientData cdata, Tcl_Interp *interp, int objc,
798              Tcl_Obj *const *objv)
799{
800    int w, h;
801
802    w = NanoVis::win_width, h = NanoVis::win_height;
803    NanoVis::resize_offscreen_buffer(2048, 2048);
804#ifdef notdef
805    NanoVis::cam->set_screen_size(0, 0, NanoVis::win_width,NanoVis::win_height);
806    NanoVis::cam->set_screen_size(30, 90, 2048 - 60, 2048 - 120);
807#endif
808    NanoVis::offscreen_buffer_capture();  //enable offscreen render
809    NanoVis::display();
810    NanoVis::read_screen();
811#ifdef notdef
812    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
813#endif
814    NanoVis::ppm_write("nv>image -bytes %d -type print");
815    NanoVis::resize_offscreen_buffer(w, h);
816    return TCL_OK;
817}
818
819static int
820CutplanePositionOp(ClientData cdata, Tcl_Interp *interp, int objc,
821                   Tcl_Obj *const *objv)
822{
823    float relval;
824    if (GetFloatFromObj(interp, objv[2], &relval) != TCL_OK) {
825        return TCL_ERROR;
826    }
827
828    // keep this just inside the volume so it doesn't disappear
829    if (relval < 0.01f) {
830        relval = 0.01f;
831    } else if (relval > 0.99f) {
832        relval = 0.99f;
833    }
834
835    int axis;
836    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
837        return TCL_ERROR;
838    }
839
840    vector<Volume *> ivol;
841    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
842        return TCL_ERROR;
843    }
844    vector<Volume *>::iterator iter;
845    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
846        (*iter)->move_cutplane(axis, relval);
847    }
848    return TCL_OK;
849}
850
851static int
852CutplaneStateOp(ClientData cdata, Tcl_Interp *interp, int objc,
853                Tcl_Obj *const *objv)
854{
855    bool state;
856    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
857        return TCL_ERROR;
858    }
859
860    int axis;
861    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
862        return TCL_ERROR;
863    }
864
865    vector<Volume *> ivol;
866    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
867        return TCL_ERROR;
868    }
869    if (state) {
870        vector<Volume *>::iterator iter;
871        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
872            (*iter)->enable_cutplane(axis);
873        }
874    } else {
875        vector<Volume *>::iterator iter;
876        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
877            (*iter)->disable_cutplane(axis);
878        }
879    }
880    return TCL_OK;
881}
882
883static Rappture::CmdSpec cutplaneOps[] = {
884    {"position", 1, CutplanePositionOp, 4, 0, "bool axis ?indices?",},
885    {"state",    1, CutplaneStateOp,    4, 0, "relval axis ?indices?",},
886};
887static int nCutplaneOps = NumCmdSpecs(cutplaneOps);
888
889/*
890 * ----------------------------------------------------------------------
891 * CLIENT COMMAND:
892 *   cutplane state on|off <axis> ?<volume>...?
893 *   cutplane position <relvalue> <axis> ?<volume>...?
894 *
895 * Clients send these commands to manipulate the cutplanes in one or
896 * more data volumes.  The "state" command turns a cutplane on or
897 * off.  The "position" command changes the position to a relative
898 * value in the range 0-1.  The <axis> can be x, y, or z.  These
899 * options are applied to the volumes represented by one or more
900 * <volume> indices.  If no volumes are specified, then all volumes
901 * are updated.
902 * ----------------------------------------------------------------------
903 */
904static int
905CutplaneCmd(ClientData cdata, Tcl_Interp *interp, int objc,
906            Tcl_Obj *const *objv)
907{
908    Tcl_ObjCmdProc *proc;
909
910    proc = Rappture::GetOpFromObj(interp, nCutplaneOps, cutplaneOps,
911                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
912    if (proc == NULL) {
913        return TCL_ERROR;
914    }
915    return (*proc) (cdata, interp, objc, objv);
916}
917
918/*
919 * ----------------------------------------------------------------------
920 * CLIENT COMMAND:
921 *   legend <volumeIndex> <width> <height>
922 *
923 * Clients use this to generate a legend image for the specified
924 * transfer function.  The legend image is a color gradient from 0
925 * to one, drawn in the given transfer function.  The resulting image
926 * is returned in the size <width> x <height>.
927 * ----------------------------------------------------------------------
928 */
929static int
930LegendCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
931{
932    if (objc != 4) {
933        Tcl_AppendResult(interp, "wrong # args: should be \"",
934            Tcl_GetString(objv[0]), " transfunc width height\"", (char*)NULL);
935        return TCL_ERROR;
936    }
937
938    const char *string = Tcl_GetString(objv[1]);
939    TransferFunction *tf;
940    tf = NanoVis::get_transfunc(string);
941    if (tf == NULL) {
942        Tcl_AppendResult(interp, "unknown transfer function \"", string, "\"",
943                             (char*)NULL);
944        return TCL_ERROR;
945    }
946    const char *label;
947    label = Tcl_GetString(objv[1]);
948    int w, h;
949    if ((Tcl_GetIntFromObj(interp, objv[2], &w) != TCL_OK) ||
950        (Tcl_GetIntFromObj(interp, objv[3], &h) != TCL_OK)) {
951        return TCL_ERROR;
952    }
953    if (Volume::update_pending) {
954        NanoVis::SetVolumeRanges();
955    }
956    NanoVis::render_legend(tf, NanoVis::grid->yAxis.min(),
957                           NanoVis::grid->yAxis.max(), w, h, label);
958    return TCL_OK;
959}
960
961/*
962 * ----------------------------------------------------------------------
963 * CLIENT COMMAND:
964 *   screen <width> <height>
965 *
966 * Clients send this command to set the size of the rendering area.
967 * Future images are generated at the specified width/height.
968 * ----------------------------------------------------------------------
969 */
970static int
971ScreenCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
972{
973    if (objc != 3) {
974        Tcl_AppendResult(interp, "wrong # args: should be \"",
975                         Tcl_GetString(objv[0]), " width height\"", (char*)NULL);
976        return TCL_ERROR;
977    }
978
979    int w, h;
980    if ((Tcl_GetIntFromObj(interp, objv[1], &w) != TCL_OK) ||
981        (Tcl_GetIntFromObj(interp, objv[2], &h) != TCL_OK)) {
982        return TCL_ERROR;
983    }
984    NanoVis::resize_offscreen_buffer(w, h);
985    return TCL_OK;
986}
987
988/*
989 * ----------------------------------------------------------------------
990 * CLIENT COMMAND:
991 *   transfunc define <name> <colormap> <alphamap>
992 *     where <colormap> = { <v> <r> <g> <b> ... }
993 *           <alphamap> = { <v> <w> ... }
994 *
995 * Clients send these commands to manipulate the transfer functions.
996 * ----------------------------------------------------------------------
997 */
998static int
999TransfuncCmd(ClientData cdata, Tcl_Interp *interp, int objc,
1000             Tcl_Obj *const *objv)
1001{
1002    if (objc < 2) {
1003        Tcl_AppendResult(interp, "wrong # args: should be \"",
1004                Tcl_GetString(objv[0]), " option arg arg...\"", (char*)NULL);
1005        return TCL_ERROR;
1006    }
1007
1008    const char *string = Tcl_GetString(objv[1]);
1009    char c = string[0];
1010    if ((c == 'd') && (strcmp(string, "define") == 0)) {
1011        if (objc != 5) {
1012            Tcl_AppendResult(interp, "wrong # args: should be \"",
1013                Tcl_GetString(objv[0]), " define name colorMap alphaMap\"",
1014                (char*)NULL);
1015            return TCL_ERROR;
1016        }
1017
1018        // decode the data and store in a series of fields
1019        Rappture::Field1D rFunc, gFunc, bFunc, wFunc;
1020        int cmapc, wmapc, i;
1021        Tcl_Obj **cmapv;
1022        Tcl_Obj **wmapv;
1023
1024        wmapv = cmapv = NULL;
1025        if (Tcl_ListObjGetElements(interp, objv[3], &cmapc, &cmapv) != TCL_OK) {
1026            return TCL_ERROR;
1027        }
1028        if ((cmapc % 4) != 0) {
1029            Tcl_AppendResult(interp, "wrong # elements is colormap: should be ",
1030                "{ v r g b ... }", (char*)NULL);
1031            return TCL_ERROR;
1032        }
1033        if (Tcl_ListObjGetElements(interp, objv[4], &wmapc, &wmapv) != TCL_OK) {
1034            return TCL_ERROR;
1035        }
1036        if ((wmapc % 2) != 0) {
1037            Tcl_AppendResult(interp, "wrong # elements in alphamap: should be ",
1038                " { v w ... }", (char*)NULL);
1039            return TCL_ERROR;
1040        }
1041        for (i = 0; i < cmapc; i += 4) {
1042            int j;
1043            double q[4];
1044
1045            for (j=0; j < 4; j++) {
1046                if (Tcl_GetDoubleFromObj(interp, cmapv[i+j], &q[j]) != TCL_OK) {
1047                    return TCL_ERROR;
1048                }
1049                if ((q[j] < 0.0) || (q[j] > 1.0)) {
1050                    Tcl_AppendResult(interp, "bad colormap value \"",
1051                        Tcl_GetString(cmapv[i+j]),
1052                        "\": should be in the range 0-1", (char*)NULL);
1053                    return TCL_ERROR;
1054                }
1055            }
1056            rFunc.define(q[0], q[1]);
1057            gFunc.define(q[0], q[2]);
1058            bFunc.define(q[0], q[3]);
1059        }
1060        for (i=0; i < wmapc; i += 2) {
1061            double q[2];
1062            int j;
1063
1064            for (j=0; j < 2; j++) {
1065                if (Tcl_GetDoubleFromObj(interp, wmapv[i+j], &q[j]) != TCL_OK) {
1066                    return TCL_ERROR;
1067                }
1068                if ((q[j] < 0.0) || (q[j] > 1.0)) {
1069                    Tcl_AppendResult(interp, "bad alphamap value \"",
1070                        Tcl_GetString(wmapv[i+j]),
1071                        "\": should be in the range 0-1", (char*)NULL);
1072                    return TCL_ERROR;
1073                }
1074            }
1075            wFunc.define(q[0], q[1]);
1076        }
1077        // sample the given function into discrete slots
1078        const int nslots = 256;
1079        float data[4*nslots];
1080        for (i=0; i < nslots; i++) {
1081            double x = double(i)/(nslots-1);
1082            data[4*i]   = rFunc.value(x);
1083            data[4*i+1] = gFunc.value(x);
1084            data[4*i+2] = bFunc.value(x);
1085            data[4*i+3] = wFunc.value(x);
1086        }
1087        // find or create this transfer function
1088        NanoVis::DefineTransferFunction(Tcl_GetString(objv[2]), nslots, data);
1089    } else {
1090        Tcl_AppendResult(interp, "bad option \"", string,
1091                "\": should be define", (char*)NULL);
1092        return TCL_ERROR;
1093    }
1094    return TCL_OK;
1095}
1096
1097/*
1098 * ----------------------------------------------------------------------
1099 * CLIENT COMMAND:
1100 *   up axis
1101 *
1102 * Clients use this to set the "up" direction for all volumes.  Volumes
1103 * are oriented such that this direction points upward.
1104 * ----------------------------------------------------------------------
1105 */
1106static int
1107UpCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
1108{
1109    if (objc != 2) {
1110        Tcl_AppendResult(interp, "wrong # args: should be \"",
1111                         Tcl_GetString(objv[0]), " x|y|z|-x|-y|-z\"", (char*)NULL);
1112        return TCL_ERROR;
1113    }
1114
1115    int sign;
1116    int axis;
1117    if (GetAxisDirFromObj(interp, objv[1], &axis, &sign) != TCL_OK) {
1118        return TCL_ERROR;
1119    }
1120    NanoVis::updir = (axis+1)*sign;
1121    return TCL_OK;
1122}
1123
1124
1125static int
1126VolumeAnimationCaptureOp(ClientData cdata, Tcl_Interp *interp, int objc,
1127                         Tcl_Obj *const *objv)
1128{
1129    int total;
1130    if (Tcl_GetIntFromObj(interp, objv[3], &total) != TCL_OK) {
1131        return TCL_ERROR;
1132    }
1133    VolumeInterpolator* interpolator;
1134    interpolator = NanoVis::vol_renderer->getVolumeInterpolator();
1135    interpolator->start();
1136    if (interpolator->is_started()) {
1137        const char *fileName = (objc < 5) ? NULL : Tcl_GetString(objv[4]);
1138        for (int frame_num = 0; frame_num < total; ++frame_num) {
1139            float fraction;
1140
1141            fraction = ((float)frame_num) / (total - 1);
1142            Trace("fraction : %f\n", fraction);
1143            //interpolator->update(((float)frame_num) / (total - 1));
1144            interpolator->update(fraction);
1145
1146            NanoVis::offscreen_buffer_capture();  //enable offscreen render
1147
1148            NanoVis::display();
1149            NanoVis::read_screen();
1150
1151            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1152
1153            NanoVis::bmp_write_to_file(frame_num, fileName);
1154        }
1155    }
1156    return TCL_OK;
1157}
1158
1159static int
1160VolumeAnimationClearOp(ClientData cdata, Tcl_Interp *interp, int objc,
1161                       Tcl_Obj *const *objv)
1162{
1163    NanoVis::vol_renderer->clearAnimatedVolumeInfo();
1164    return TCL_OK;
1165}
1166
1167static int
1168VolumeAnimationStartOp(ClientData cdata, Tcl_Interp *interp, int objc,
1169                       Tcl_Obj *const *objv)
1170{
1171    NanoVis::vol_renderer->startVolumeAnimation();
1172    return TCL_OK;
1173}
1174
1175static int
1176VolumeAnimationStopOp(ClientData cdata, Tcl_Interp *interp, int objc,
1177                      Tcl_Obj *const *objv)
1178{
1179    NanoVis::vol_renderer->stopVolumeAnimation();
1180    return TCL_OK;
1181}
1182
1183static int
1184VolumeAnimationVolumesOp(ClientData cdata, Tcl_Interp *interp, int objc,
1185                         Tcl_Obj *const *objv)
1186{
1187    vector<unsigned int> ivol;
1188    if (GetVolumeIndices(interp, objc - 3, objv + 3, &ivol) != TCL_OK) {
1189        return TCL_ERROR;
1190    }
1191    Trace("parsing volume index\n");
1192    vector<unsigned int>::iterator iter;
1193    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1194        Trace("index: %d\n", *iter);
1195        NanoVis::vol_renderer->addAnimatedVolume(NanoVis::volume[*iter], *iter);
1196    }
1197    return TCL_OK;
1198}
1199
1200static Rappture::CmdSpec volumeAnimationOps[] = {
1201    {"capture",   2, VolumeAnimationCaptureOp,  4, 5, "numframes ?filename?",},
1202    {"clear",     2, VolumeAnimationClearOp,    3, 3, "",},
1203    {"start",     3, VolumeAnimationStartOp,    3, 3, "",},
1204    {"stop",      3, VolumeAnimationStopOp,     3, 3, "",},
1205    {"volumes",   1, VolumeAnimationVolumesOp,  3, 0, "?indices?",},
1206};
1207
1208static int nVolumeAnimationOps = NumCmdSpecs(volumeAnimationOps);
1209
1210static int
1211VolumeAnimationOp(ClientData cdata, Tcl_Interp *interp, int objc,
1212                  Tcl_Obj *const *objv)
1213{
1214    Tcl_ObjCmdProc *proc;
1215
1216    proc = Rappture::GetOpFromObj(interp, nVolumeAnimationOps, volumeAnimationOps,
1217                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
1218    if (proc == NULL) {
1219        return TCL_ERROR;
1220    }
1221    return (*proc) (cdata, interp, objc, objv);
1222}
1223
1224
1225static int
1226VolumeDataFollowsOp(ClientData cdata, Tcl_Interp *interp, int objc,
1227                    Tcl_Obj *const *objv)
1228{
1229    printf("Data Loading\n");
1230    fflush(stdout);
1231
1232    int nbytes;
1233    if (Tcl_GetIntFromObj(interp, objv[3], &nbytes) != TCL_OK) {
1234        return TCL_ERROR;
1235    }
1236
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        Rappture::Outcome err;
1320
1321        printf("OpenDX loading...\n");
1322        fflush(stdout);
1323        std::stringstream fdata;
1324        fdata.write(buf.bytes(),buf.size());
1325
1326        bool result;
1327#if ISO_TEST
1328        result = load_volume_stream2(err, n, fdata);
1329#else
1330        result = load_volume_stream(err, n, fdata);
1331#endif
1332        if (!result) {
1333            Tcl_AppendResult(interp, err.remark(), (char*)NULL);
1334            return TCL_ERROR;
1335        }
1336    }
1337
1338    //
1339    // BE CAREFUL: Set the number of slices to something slightly different
1340    // for each volume.  If we have identical volumes at exactly the same
1341    // position with exactly the same number of slices, the second volume will
1342    // overwrite the first, so the first won't appear at all.
1343    //
1344    if (NanoVis::volume[n] != NULL) {
1345        //NanoVis::volume[n]->set_n_slice(512-n);
1346        NanoVis::volume[n]->set_n_slice(256-n);
1347        NanoVis::volume[n]->disable_cutplane(0);
1348        NanoVis::volume[n]->disable_cutplane(1);
1349        NanoVis::volume[n]->disable_cutplane(2);
1350
1351        NanoVis::vol_renderer->add_volume(NanoVis::volume[n],
1352                                          NanoVis::get_transfunc("default"));
1353    }
1354
1355    {
1356        Volume *volPtr;
1357        char info[1024];
1358        ssize_t nWritten;
1359
1360        if (Volume::update_pending) {
1361            NanoVis::SetVolumeRanges();
1362        }
1363        volPtr = NanoVis::volume[n];
1364        // FIXME: strlen(info) is the return value of sprintf
1365        sprintf(info, "nv>data id %d min %g max %g vmin %g vmax %g\n",
1366                n, volPtr->wAxis.min(), volPtr->wAxis.max(),
1367                Volume::valueMin, Volume::valueMax);
1368        nWritten  = write(0, info, strlen(info));
1369        assert(nWritten == (ssize_t)strlen(info));
1370    }
1371    return TCL_OK;
1372}
1373
1374static int
1375VolumeDataStateOp(ClientData cdata, Tcl_Interp *interp, int objc,
1376                  Tcl_Obj *const *objv)
1377{
1378    bool state;
1379    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
1380        return TCL_ERROR;
1381    }
1382    vector<Volume *> ivol;
1383    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1384        return TCL_ERROR;
1385    }
1386    if (state) {
1387        vector<Volume *>::iterator iter;
1388        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1389            (*iter)->enable_data();
1390        }
1391    } else {
1392        vector<Volume *>::iterator iter;
1393        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1394            (*iter)->disable_data();
1395        }
1396    }
1397    return TCL_OK;
1398}
1399
1400static Rappture::CmdSpec volumeDataOps[] = {
1401    {"follows",   1, VolumeDataFollowsOp, 4, 4, "size",},
1402    {"state",     1, VolumeDataStateOp,   4, 0, "bool ?indices?",},
1403};
1404static int nVolumeDataOps = NumCmdSpecs(volumeDataOps);
1405
1406static int
1407VolumeDataOp(ClientData cdata, Tcl_Interp *interp, int objc,
1408             Tcl_Obj *const *objv)
1409{
1410    Tcl_ObjCmdProc *proc;
1411
1412    proc = Rappture::GetOpFromObj(interp, nVolumeDataOps, volumeDataOps,
1413                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
1414    if (proc == NULL) {
1415        return TCL_ERROR;
1416    }
1417    return (*proc) (cdata, interp, objc, objv);
1418}
1419
1420static int
1421VolumeOutlineColorOp(ClientData cdata, Tcl_Interp *interp, int objc,
1422                     Tcl_Obj *const *objv)
1423{
1424    float rgb[3];
1425    if (GetColor(interp, objc - 3, objv + 3, rgb) != TCL_OK) {
1426        return TCL_ERROR;
1427    }
1428    vector<Volume *> ivol;
1429    if (GetVolumes(interp, objc - 6, objv + 6, &ivol) != TCL_OK) {
1430        return TCL_ERROR;
1431    }
1432    vector<Volume *>::iterator iter;
1433    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1434        (*iter)->set_outline_color(rgb);
1435    }
1436    return TCL_OK;
1437}
1438
1439static int
1440VolumeOutlineStateOp(ClientData cdata, Tcl_Interp *interp, int objc,
1441                     Tcl_Obj *const *objv)
1442{
1443    bool state;
1444    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
1445        return TCL_ERROR;
1446    }
1447    vector<Volume *> ivol;
1448    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1449        return TCL_ERROR;
1450    }
1451    if (state) {
1452        vector<Volume *>::iterator iter;
1453        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1454            (*iter)->enable_outline();
1455        }
1456    } else {
1457        vector<Volume *>::iterator iter;
1458        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1459            (*iter)->disable_outline();
1460        }
1461    }
1462    return TCL_OK;
1463}
1464
1465
1466static Rappture::CmdSpec volumeOutlineOps[] = {
1467    {"color",     1, VolumeOutlineColorOp,  6, 0, "r g b ?indices?",},
1468    {"state",     1, VolumeOutlineStateOp,  4, 0, "bool ?indices?",},
1469    {"visible",   1, VolumeOutlineStateOp,  4, 0, "bool ?indices?",},
1470};
1471static int nVolumeOutlineOps = NumCmdSpecs(volumeOutlineOps);
1472
1473static int
1474VolumeOutlineOp(ClientData cdata, Tcl_Interp *interp, int objc,
1475                Tcl_Obj *const *objv)
1476{
1477    Tcl_ObjCmdProc *proc;
1478
1479    proc = Rappture::GetOpFromObj(interp, nVolumeOutlineOps, volumeOutlineOps,
1480        Rappture::CMDSPEC_ARG2, objc, objv, 0);
1481    if (proc == NULL) {
1482        return TCL_ERROR;
1483    }
1484    return (*proc) (cdata, interp, objc, objv);
1485}
1486
1487static int
1488VolumeShadingDiffuseOp(ClientData cdata, Tcl_Interp *interp, int objc,
1489                       Tcl_Obj *const *objv)
1490{
1491    float diffuse;
1492    if (GetFloatFromObj(interp, objv[3], &diffuse) != TCL_OK) {
1493        return TCL_ERROR;
1494    }
1495
1496    vector<Volume *> ivol;
1497    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1498        return TCL_ERROR;
1499    }
1500    vector<Volume *>::iterator iter;
1501    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1502        (*iter)->set_diffuse(diffuse);
1503    }
1504    return TCL_OK;
1505}
1506
1507static int
1508VolumeShadingIsosurfaceOp(ClientData cdata, Tcl_Interp *interp, int objc,
1509                          Tcl_Obj *const *objv)
1510{
1511    bool iso_surface;
1512    if (GetBooleanFromObj(interp, objv[3], &iso_surface) != TCL_OK) {
1513        return TCL_ERROR;
1514    }
1515    vector<Volume *> ivol;
1516    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1517        return TCL_ERROR;
1518    }
1519    vector<Volume *>::iterator iter;
1520    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1521        (*iter)->set_isosurface(iso_surface);
1522    }
1523    return TCL_OK;
1524}
1525
1526static int
1527VolumeShadingOpacityOp(ClientData cdata, Tcl_Interp *interp, int objc,
1528                       Tcl_Obj *const *objv)
1529{
1530
1531    float opacity;
1532    if (GetFloatFromObj(interp, objv[3], &opacity) != TCL_OK) {
1533        return TCL_ERROR;
1534    }
1535    printf("set opacity %f\n", opacity);
1536    vector<Volume *> ivol;
1537    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1538        return TCL_ERROR;
1539    }
1540    vector<Volume *>::iterator iter;
1541    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1542        (*iter)->set_opacity_scale(opacity);
1543    }
1544    return TCL_OK;
1545}
1546
1547static int
1548VolumeShadingSpecularOp(ClientData cdata, Tcl_Interp *interp, int objc,
1549                        Tcl_Obj *const *objv)
1550{
1551    float specular;
1552    if (GetFloatFromObj(interp, objv[3], &specular) != TCL_OK) {
1553        return TCL_ERROR;
1554    }
1555    vector<Volume *> ivol;
1556    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1557        return TCL_ERROR;
1558    }
1559    vector<Volume *>::iterator iter;
1560    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1561        (*iter)->set_specular(specular);
1562    }
1563    return TCL_OK;
1564}
1565
1566static int
1567VolumeShadingTransFuncOp(ClientData cdata, Tcl_Interp *interp, int objc,
1568                         Tcl_Obj *const *objv)
1569{
1570    TransferFunction *tf;
1571    const char *name = Tcl_GetString(objv[3]);
1572    tf = NanoVis::get_transfunc(name);
1573    if (tf == NULL) {
1574        Tcl_AppendResult(interp, "transfer function \"", name,
1575                         "\" is not defined", (char*)NULL);
1576        return TCL_ERROR;
1577    }
1578    vector<Volume *> ivol;
1579    if (GetVolumes(interp, objc - 4, objv + 4, &ivol) != TCL_OK) {
1580        return TCL_ERROR;
1581    }
1582    vector<Volume *>::iterator iter;
1583    for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1584        NanoVis::vol_renderer->shade_volume(*iter, tf);
1585#ifdef POINTSET
1586        // TBD..
1587        // POINTSET
1588        if ((*iter)->pointsetIndex != -1) {
1589            g_pointSet[(*iter)->pointsetIndex]->updateColor(tf->getData(), 256);
1590        }
1591#endif /*POINTSET*/
1592    }
1593    return TCL_OK;
1594}
1595
1596static Rappture::CmdSpec volumeShadingOps[] = {
1597    {"diffuse",     1, VolumeShadingDiffuseOp,    4, 0, "value ?indices?",},
1598    {"isosurface",  1, VolumeShadingIsosurfaceOp, 4, 0, "bool ?indices?",},
1599    {"opacity",     1, VolumeShadingOpacityOp,    4, 0, "value ?indices?",},
1600    {"specular",    1, VolumeShadingSpecularOp,   4, 0, "value ?indices?",},
1601    {"transfunc",   1, VolumeShadingTransFuncOp,  4, 0, "funcName ?indices?",},
1602};
1603static int nVolumeShadingOps = NumCmdSpecs(volumeShadingOps);
1604
1605static int
1606VolumeShadingOp(ClientData cdata, Tcl_Interp *interp, int objc,
1607                Tcl_Obj *const *objv)
1608{
1609    Tcl_ObjCmdProc *proc;
1610
1611    proc = Rappture::GetOpFromObj(interp, nVolumeShadingOps, volumeShadingOps,
1612        Rappture::CMDSPEC_ARG2, objc, objv, 0);
1613    if (proc == NULL) {
1614        return TCL_ERROR;
1615    }
1616    return (*proc) (cdata, interp, objc, objv);
1617}
1618
1619static int
1620VolumeAxisOp(ClientData cdata, Tcl_Interp *interp, int objc,
1621             Tcl_Obj *const *objv)
1622{
1623    const char *string = Tcl_GetString(objv[2]);
1624    char c;
1625    c = string[0];
1626    if ((c == 'l') && (strcmp(string, "label") == 0)) {
1627        int axis;
1628        if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
1629            return TCL_ERROR;
1630        }
1631        vector<Volume *> ivol;
1632        if (GetVolumes(interp, objc - 5, objv + 5, &ivol) != TCL_OK) {
1633            return TCL_ERROR;
1634        }
1635        vector<Volume *>::iterator iter;
1636        const char *label;
1637        label = Tcl_GetString(objv[4]);
1638        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1639            (*iter)->set_label(axis, label);
1640        }
1641    } else {
1642        Tcl_AppendResult(interp, "bad option \"", string,
1643                         "\": should be label", (char*)NULL);
1644        return TCL_ERROR;
1645    }
1646    return TCL_OK;
1647}
1648
1649static int
1650VolumeStateOp(ClientData cdata, Tcl_Interp *interp, int objc,
1651              Tcl_Obj *const *objv)
1652{
1653    bool state;
1654    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1655        return TCL_ERROR;
1656    }
1657    vector<Volume *> ivol;
1658    if (GetVolumes(interp, objc - 3, objv + 3, &ivol) != TCL_OK) {
1659        return TCL_ERROR;
1660    }
1661    if (state) {
1662        vector<Volume *>::iterator iter;
1663        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1664            (*iter)->enable();
1665        }
1666    } else {
1667        vector<Volume *>::iterator iter;
1668        for (iter = ivol.begin(); iter != ivol.end(); iter++) {
1669            (*iter)->disable();
1670        }
1671    }
1672    return TCL_OK;
1673}
1674
1675static int
1676VolumeTestOp(ClientData cdata, Tcl_Interp *interp, int objc,
1677             Tcl_Obj *const *objv)
1678{
1679    NanoVis::volume[1]->disable_data();
1680    NanoVis::volume[1]->disable();
1681    return TCL_OK;
1682}
1683
1684static Rappture::CmdSpec volumeOps[] = {
1685    {"animation", 2, VolumeAnimationOp,   3, 0, "oper ?args?",},
1686    {"axis",      2, VolumeAxisOp,        4, 0, "label axis value ?indices?",},
1687    {"data",      1, VolumeDataOp,        3, 0, "oper ?args?",},
1688    {"outline",   1, VolumeOutlineOp,     3, 0, "oper ?args?",},
1689    {"shading",   2, VolumeShadingOp,     3, 0, "oper ?args?",},
1690    {"state",     2, VolumeStateOp,       3, 0, "bool ?indices?",},
1691    {"test2",     1, VolumeTestOp,        2, 2, "",},
1692};
1693static int nVolumeOps = NumCmdSpecs(volumeOps);
1694
1695/*
1696 * ----------------------------------------------------------------------
1697 * CLIENT COMMAND:
1698 *   volume axis label x|y|z <value> ?<volumeId> ...?
1699 *   volume data state on|off ?<volumeId> ...?
1700 *   volume outline state on|off ?<volumeId> ...?
1701 *   volume outline color on|off ?<volumeId> ...?
1702 *   volume shading transfunc <name> ?<volumeId> ...?
1703 *   volume shading diffuse <value> ?<volumeId> ...?
1704 *   volume shading specular <value> ?<volumeId> ...?
1705 *   volume shading opacity <value> ?<volumeId> ...?
1706 *   volume state on|off ?<volumeId> ...?
1707 *
1708 * Clients send these commands to manipulate the volumes.
1709 * ----------------------------------------------------------------------
1710 */
1711static int
1712VolumeCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
1713{
1714    Tcl_ObjCmdProc *proc;
1715
1716    proc = Rappture::GetOpFromObj(interp, nVolumeOps, volumeOps,
1717        Rappture::CMDSPEC_ARG1, objc, objv, 0);
1718    if (proc == NULL) {
1719        return TCL_ERROR;
1720    }
1721    return (*proc) (cdata, interp, objc, objv);
1722}
1723
1724// ========================= VOLUME END ==================================
1725
1726// ============================= FLOW ==================================
1727
1728static int
1729FlowDataFollowsOp(ClientData cdata, Tcl_Interp *interp, int objc,
1730                    Tcl_Obj *const *objv)
1731{
1732    Rappture::Outcome result;
1733
1734    Trace("Flow Data Loading\n");
1735
1736    int nbytes;
1737    if (Tcl_GetIntFromObj(interp, objv[3], &nbytes) != TCL_OK) {
1738        return TCL_ERROR;
1739    }
1740    int extents;
1741    if (Tcl_GetIntFromObj(interp, objv[4], &extents) != TCL_OK) {
1742        return TCL_ERROR;
1743    }
1744
1745    Rappture::Buffer buf;
1746    if (GetDataStream(interp, buf, nbytes) != TCL_OK) {
1747        return TCL_ERROR;
1748    }
1749    int n = NanoVis::n_volumes;
1750    if (strncmp(buf.bytes(), "<DX>", 4) == 0) {
1751        if (!load_vector_stream2(result, n, buf.size(), (char *)buf.bytes())) {
1752            Tcl_AppendResult(interp, result.remark(), (char *)NULL);
1753            return TCL_ERROR;
1754        }
1755#ifdef notdef
1756    } else if (strncmp(buf.bytes(), "<unirect3d>", 4) == 0) {
1757
1758        Rappture::Unirect3d data;
1759        Tcl_CmdInfo cmdInfo;
1760
1761        /* Set the clientdata field of the unirect3d command to contain
1762         * the local data structure. */
1763        if (!Tcl_GetCommandInfo(interp, "unirect3d", &cmdInfo)) {
1764            return TCL_ERROR;
1765        }
1766        data.extents(extents);
1767        cmdInfo.objClientData = (ClientData)&data;     
1768        Tcl_SetCommandInfo(interp, "unirect3d", &cmdInfo);
1769        if (Tcl_Eval(interp, (const char *)buf.bytes()) != TCL_OK) {
1770            return TCL_ERROR;
1771        }
1772        if (!data.isInitialized()) {
1773            return TCL_ERROR;
1774        }
1775        if (!MakeVectorFieldFromUnirect3d(result, data)) {
1776            Tcl_AppendResult(interp, result.remark(), (char *)NULL);
1777            return TCL_ERROR;
1778        }
1779#endif
1780    }
1781
1782    Volume *volPtr = NanoVis::volume[NanoVis::n_volumes];
1783    //
1784    // BE CAREFUL:  Set the number of slices to something
1785    //   slightly different for each volume.  If we have
1786    //   identical volumes at exactly the same position
1787    //   with exactly the same number of slices, the second
1788    //   volume will overwrite the first, so the first won't
1789    //   appear at all.
1790    //
1791    volPtr->set_n_slice(256-n);
1792    // volPtr->set_n_slice(512-n);
1793    volPtr->disable_cutplane(0);
1794    volPtr->disable_cutplane(1);
1795    volPtr->disable_cutplane(2);
1796   
1797    NanoVis::vol_renderer->add_volume(volPtr,
1798        NanoVis::get_transfunc("default"));
1799   
1800    float dx0 = -0.5;
1801    float dy0 = -0.5*volPtr->height/volPtr->width;
1802    float dz0 = -0.5*volPtr->depth/volPtr->width;
1803    volPtr->move(Vector3(dx0, dy0, dz0));
1804    return TCL_OK;
1805}
1806
1807static Rappture::CmdSpec flowDataOps[] = {
1808    {"follows",   1, FlowDataFollowsOp, 4, 4, "size",},
1809};
1810static int nFlowDataOps = NumCmdSpecs(flowDataOps);
1811
1812static int
1813FlowDataOp(ClientData cdata, Tcl_Interp *interp, int objc,
1814             Tcl_Obj *const *objv)
1815{
1816    Tcl_ObjCmdProc *proc;
1817
1818    proc = Rappture::GetOpFromObj(interp, nFlowDataOps, flowDataOps,
1819                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
1820    if (proc == NULL) {
1821        return TCL_ERROR;
1822    }
1823    return (*proc) (cdata, interp, objc, objv);
1824}
1825
1826// INSOO
1827// I got an compile error
1828#ifndef SHRT_MAX
1829#define SHRT_MAX 4096
1830#endif
1831
1832static int
1833FlowVideoOp(ClientData cdata, Tcl_Interp *interp, int objc,
1834            Tcl_Obj *const *objv)
1835{
1836    int width, height;          // Resolution of video.
1837    int numFrames;              // Total number of frames.
1838    float frameRate;            // Frame rate of the video.
1839    float bitRate;              // Bit rate of the vide.
1840
1841    if ((Tcl_GetIntFromObj(interp, objv[2], &width) != TCL_OK) ||
1842        (Tcl_GetIntFromObj(interp, objv[3], &height) != TCL_OK) ||
1843        (Tcl_GetIntFromObj(interp, objv[4], &numFrames) != TCL_OK) ||
1844        (GetFloatFromObj(interp, objv[5], &frameRate) != TCL_OK) ||
1845        (GetFloatFromObj(interp, objv[6], &bitRate) != TCL_OK)) {
1846        return TCL_ERROR;
1847    }
1848    if ((width<0) || (width>SHRT_MAX) || (height<0) || (height>SHRT_MAX)) {
1849        Tcl_AppendResult(interp, "bad dimensions for video", (char *)NULL);
1850        return TCL_ERROR;
1851    }
1852    if ((frameRate < 0.0f) || (frameRate > 30.0f)) {
1853        Tcl_AppendResult(interp, "bad frame rate \"", Tcl_GetString(objv[5]),
1854                         "\"", (char *)NULL);
1855        return TCL_ERROR;
1856    }
1857    if ((bitRate < 0.0f) || (frameRate > 30.0f)) {
1858        Tcl_AppendResult(interp, "bad bit rate \"", Tcl_GetString(objv[6]),
1859                         "\"", (char *)NULL);
1860        return TCL_ERROR;
1861    }
1862       
1863    if (NanoVis::licRenderer) {
1864        NanoVis::licRenderer->activate();
1865    }
1866    if (NanoVis::flowVisRenderer) {
1867        NanoVis::flowVisRenderer->activate();
1868    }
1869
1870    // Save the old dimensions of the offscreen buffer.
1871    int oldWidth, oldHeight;
1872    oldWidth = NanoVis::win_width;
1873    oldHeight = NanoVis::win_height;
1874
1875    if ((width != oldWidth) || (height != oldHeight)) {
1876        // Resize to the requested size.
1877        NanoVis::resize_offscreen_buffer(width, height);
1878    }
1879
1880    char fileName[128];
1881    sprintf(fileName,"/tmp/flow%d.mpeg", getpid());
1882
1883    Trace("FLOW started\n");
1884
1885    Rappture::Outcome result;
1886    Rappture::AVTranslate movie(width, height, frameRate, bitRate);
1887
1888    int pad = 0;
1889    if ((3*NanoVis::win_width) % 4 > 0) {
1890        pad = 4 - ((3*NanoVis::win_width) % 4);
1891    }
1892
1893    movie.init(result, fileName);
1894
1895    for (int i = 0; i < numFrames; i++) {
1896        // Generate the latest frame and send it back to the client
1897        if (NanoVis::licRenderer &&
1898            NanoVis::licRenderer->isActivated()) {
1899            NanoVis::licRenderer->convolve();
1900        }
1901        if (NanoVis::flowVisRenderer &&
1902            NanoVis::flowVisRenderer->isActivated()) {
1903            NanoVis::flowVisRenderer->advect();
1904        }
1905        NanoVis::offscreen_buffer_capture();  //enable offscreen render
1906        NanoVis::display();
1907
1908        NanoVis::read_screen();
1909        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1910
1911        // This is done before bmp_write_to_file because bmp_write_to_file
1912        // turns rgb data to bgr
1913        movie.append(result, NanoVis::screen_buffer, pad);
1914        // NanoVis::bmp_write_to_file(frame_count, fileName);
1915    }
1916
1917    movie.done(result);
1918    Trace("FLOW end\n");
1919
1920    if (NanoVis::licRenderer) {
1921        NanoVis::licRenderer->deactivate();
1922    }
1923    if (NanoVis::flowVisRenderer) {
1924        NanoVis::flowVisRenderer->deactivate();
1925    }
1926    NanoVis::initParticle();
1927
1928    // FIXME: find a way to get the data from the movie object as a void*
1929    Rappture::Buffer data;
1930    if (!data.load(result, fileName)) {
1931        Tcl_AppendResult(interp, "can't load data from temporary movie file \"",
1932                fileName, "\": ", result.remark(), (char *)NULL);
1933        return TCL_ERROR;
1934    }
1935
1936    // Build the command string for the client.
1937    char command[200];
1938    sprintf(command,"nv>image -bytes %lu -type movie\n",
1939            (unsigned long)data.size());
1940
1941    NanoVis::sendDataToClient(command, data.bytes(), data.size());
1942    if (unlink(fileName) != 0) {
1943        Tcl_AppendResult(interp, "can't unlink temporary movie file \"",
1944                fileName, "\": ", Tcl_PosixError(interp), (char *)NULL);
1945        return TCL_ERROR;
1946    }
1947    return TCL_OK;
1948}
1949
1950static int
1951FlowLicOp(ClientData cdata, Tcl_Interp *interp, int objc,
1952             Tcl_Obj *const *objv)
1953{
1954    bool state;
1955    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1956        return TCL_ERROR;
1957    }
1958    NanoVis::lic_on = state;
1959    return TCL_OK;
1960}
1961
1962static int
1963FlowSliceVisibleOp(ClientData cdata, Tcl_Interp *interp, int objc,
1964             Tcl_Obj *const *objv)
1965{
1966    int axis;
1967    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
1968        return TCL_ERROR;
1969    }
1970    int state;
1971    if (Tcl_GetBooleanFromObj(interp, objv[4], &state) != TCL_OK) {
1972        return TCL_ERROR;
1973    }
1974    switch (axis) {
1975    case 0 :
1976        NanoVis::lic_slice_x_visible = state;
1977        break;
1978    case 1 :
1979        NanoVis::lic_slice_y_visible = state;
1980        break;
1981    case 2 :
1982        NanoVis::lic_slice_z_visible = state;
1983        break;
1984    }
1985    return TCL_OK;
1986}
1987
1988static int
1989FlowSlicePositionOp(ClientData cdata, Tcl_Interp *interp, int objc,
1990                    Tcl_Obj *const *objv)
1991{
1992    int axis;
1993    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
1994        return TCL_ERROR;
1995    }
1996    float pos;
1997    if (GetFloatFromObj(interp, objv[4], &pos) != TCL_OK) {
1998        return TCL_ERROR;
1999    }
2000    if (pos < 0.0f) {
2001        pos = 0.0f;
2002    } else if (pos > 1.0f) {
2003        pos = 1.0f;
2004    }
2005    switch (axis) {
2006    case 0 :
2007        NanoVis::lic_slice_x = pos;
2008        NanoVis::licRenderer->set_axis(0);
2009        NanoVis::licRenderer->set_offset(NanoVis::lic_slice_x);
2010        break;
2011    case 1 :
2012        NanoVis::lic_slice_y = pos;
2013        NanoVis::licRenderer->set_axis(1);
2014        NanoVis::licRenderer->set_offset(NanoVis::lic_slice_y);
2015        break;
2016    case 2 :
2017        NanoVis::lic_slice_z = pos;
2018        NanoVis::licRenderer->set_axis(2);
2019        NanoVis::licRenderer->set_offset(NanoVis::lic_slice_z);
2020        break;
2021    }
2022    return TCL_OK;
2023}
2024
2025static Rappture::CmdSpec flowSliceOps[] = {
2026    {"position",  1, FlowSlicePositionOp, 5, 5, "axis value",},
2027    {"visible",   1, FlowSliceVisibleOp,  5, 5, "axis bool",},
2028};
2029static int nFlowSliceOps = NumCmdSpecs(flowSliceOps);
2030
2031static int
2032FlowSliceOp(ClientData cdata, Tcl_Interp *interp, int objc,
2033             Tcl_Obj *const *objv)
2034{
2035                                                                                                                                                                                        Tcl_ObjCmdProc *proc;
2036
2037    proc = Rappture::GetOpFromObj(interp, nFlowSliceOps, flowSliceOps,
2038        Rappture::CMDSPEC_ARG2, objc, objv, 0);
2039    if (proc == NULL) {
2040        return TCL_ERROR;
2041    }
2042    return (*proc) (cdata, interp, objc, objv);
2043}
2044
2045static int
2046FlowParticlesVisibleOp(ClientData cdata, Tcl_Interp *interp, int objc,
2047             Tcl_Obj *const *objv)
2048{
2049    bool state;
2050    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
2051        return TCL_ERROR;
2052    }
2053
2054    NanoVis::particle_on = state;
2055    return TCL_OK;
2056}
2057
2058static Rappture::CmdSpec flowParticlesOps[] = {
2059    {"visible",    1, FlowParticlesVisibleOp,  4, 4, "on|off",},
2060};
2061static int nFlowParticlesOps = NumCmdSpecs(flowParticlesOps);
2062
2063static int
2064FlowParticlesOp(ClientData cdata, Tcl_Interp *interp, int objc,
2065             Tcl_Obj *const *objv)
2066{
2067    Tcl_ObjCmdProc *proc;
2068
2069    proc = Rappture::GetOpFromObj(interp, nFlowParticlesOps, flowParticlesOps,
2070                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
2071    if (proc == NULL) {
2072        return TCL_ERROR;
2073    }
2074    return (*proc) (cdata, interp, objc, objv);
2075}
2076
2077static int
2078FlowNextOp(ClientData cdata, Tcl_Interp *interp, int objc,
2079             Tcl_Obj *const *objv)
2080{
2081    if (!NanoVis::licRenderer->isActivated()) {
2082        NanoVis::licRenderer->activate();
2083    }
2084    if (!NanoVis::flowVisRenderer->isActivated()) {
2085        NanoVis::flowVisRenderer->activate();
2086    }
2087
2088    Trace("sending flow playback frame\n");
2089
2090    // Generate the latest frame and send it back to the client
2091    if (NanoVis::licRenderer->isActivated()) {
2092        NanoVis::licRenderer->convolve();
2093    }
2094    NanoVis::flowVisRenderer->advect();
2095    NanoVis::offscreen_buffer_capture();  //enable offscreen render
2096    NanoVis::display();
2097    NanoVis::read_screen();
2098
2099    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2100
2101    // NanoVis::bmp_write_to_file(frame_count, fileName);
2102    Trace("FLOW end\n");
2103    return TCL_OK;
2104}
2105
2106static int
2107FlowResetOp(ClientData cdata, Tcl_Interp *interp, int objc,
2108             Tcl_Obj *const *objv)
2109{
2110    NanoVis::initParticle();
2111    return TCL_OK;
2112}
2113
2114static int
2115FlowVectorIdOp(ClientData cdata, Tcl_Interp *interp, int objc,
2116             Tcl_Obj *const *objv)
2117{
2118    Volume *volPtr;
2119    if (GetVolumeFromObj(interp, objv[2], &volPtr) != TCL_OK) {
2120        return TCL_ERROR;
2121    }
2122    if (NanoVis::flowVisRenderer != NULL) {
2123        // INSOO
2124#ifndef NEW_FLOW_ENGINE
2125        NanoVis::flowVisRenderer->setVectorField(volPtr->id,
2126            *(volPtr->get_location()),
2127            1.0f,
2128            volPtr->height / (float)volPtr->width,
2129            volPtr->depth  / (float)volPtr->width,
2130            volPtr->wAxis.max());
2131#else
2132
2133        NanoVis::flowVisRenderer->addVectorField("vname", volPtr,
2134            *(volPtr->get_location()),
2135            1.0f,
2136            volPtr->height / (float)volPtr->width,
2137            volPtr->depth  / (float)volPtr->width,
2138            volPtr->wAxis.max());
2139#endif
2140        NanoVis::initParticle();
2141
2142    }
2143    if (NanoVis::licRenderer != NULL) {
2144        // INSOO
2145        // TBD..
2146        NanoVis::licRenderer->setVectorField(volPtr->id,
2147            *(volPtr->get_location()),
2148            1.0f / volPtr->aspect_ratio_width,
2149            1.0f / volPtr->aspect_ratio_height,
2150            1.0f / volPtr->aspect_ratio_depth,
2151            volPtr->wAxis.max());
2152        NanoVis::licRenderer->set_offset(NanoVis::lic_slice_z);
2153    }
2154    return TCL_OK;
2155}
2156
2157static Rappture::CmdSpec flowOps[] = {
2158    {"data",      1, FlowDataOp,          3, 0, "oper ?args?",},
2159    {"lic",       1, FlowLicOp,           3, 3, "on|off",},
2160    {"particles", 2, FlowParticlesOp,     3, 0, "oper ?args?",},
2161    {"next",      2, FlowNextOp,          2, 2, "",},
2162    {"reset",     1, FlowResetOp,         2, 2, "",},
2163    {"slice",     1, FlowSliceOp,         3, 0, "oper ?args?",},
2164    {"vectorid",  2, FlowVectorIdOp,      3, 3, "index",},
2165    {"video",     2, FlowVideoOp,         7, 7,
2166        "width height numFrames frameRate bitRate ",},
2167};
2168static int nFlowOps = NumCmdSpecs(flowOps);
2169
2170/*
2171 * ----------------------------------------------------------------------
2172 * CLIENT COMMAND:
2173 *   flow data follows <value>
2174 *   flow capture frames filename
2175 *   flow lic on|off
2176 *   flow particles visible on|off
2177 *   flow slice visible axis on|off
2178 *   flow slice position axis value
2179 *   flow next
2180 *   flow reset
2181 *   flow vectorid <volumeId>
2182 *
2183 * Clients send these commands to manipulate the flow.
2184 * ----------------------------------------------------------------------
2185 */
2186static int
2187FlowCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
2188{
2189    Tcl_ObjCmdProc *proc;
2190
2191    proc = Rappture::GetOpFromObj(interp, nFlowOps, flowOps,
2192        Rappture::CMDSPEC_ARG1, objc, objv, 0);
2193    if (proc == NULL) {
2194        return TCL_ERROR;
2195    }
2196    return (*proc) (cdata, interp, objc, objv);
2197}
2198
2199// ============================ FLOW END ==================================
2200
2201static int
2202HeightMapDataFollowsOp(ClientData cdata, Tcl_Interp *interp, int objc,
2203                       Tcl_Obj *const *objv)
2204{
2205    Rappture::Buffer buf;
2206    int nBytes;
2207
2208    if (Tcl_GetIntFromObj(interp, objv[3], &nBytes) != TCL_OK) {
2209        return TCL_ERROR;
2210    }
2211    if (GetDataStream(interp, buf, nBytes) != TCL_OK) {
2212        return TCL_ERROR;
2213    }
2214    buf.append("\0", 1);
2215
2216    Rappture::Unirect2d grid;
2217    Tcl_CmdInfo cmdInfo;
2218
2219    /* Set the clientdata field of the unirect2d command to contain the local
2220     * grid structure. This is how we communicate through the Tcl command
2221     * interface. */
2222    if (!Tcl_GetCommandInfo(interp, "unirect2d", &cmdInfo)) {
2223        return TCL_ERROR;
2224    }
2225    cmdInfo.objClientData = (ClientData)&grid; 
2226    Tcl_SetCommandInfo(interp, "unirect2d", &cmdInfo);
2227    if (Tcl_Eval(interp, (const char *)buf.bytes()) != TCL_OK) {
2228        fprintf(NanoVis::logfile, "error in command: %s\n",
2229                Tcl_GetStringResult(interp));
2230        fflush(NanoVis::logfile);
2231        return TCL_ERROR;
2232    }
2233    if (!grid.isInitialized()) {
2234        return TCL_ERROR;
2235    }
2236
2237    HeightMap* hmPtr;
2238    hmPtr = new HeightMap();
2239
2240    // Must set units before the heights.
2241    hmPtr->xAxis.units(grid.xUnits());
2242    hmPtr->yAxis.units(grid.yUnits());
2243    hmPtr->zAxis.units(grid.vUnits());
2244    hmPtr->wAxis.units(grid.yUnits());
2245    hmPtr->setHeight(grid.xMin(), grid.yMin(), grid.xMax(), grid.yMax(),
2246                     grid.xNum(), grid.yNum(), grid.acceptValues());
2247    hmPtr->setColorMap(NanoVis::get_transfunc("default"));
2248    hmPtr->setVisible(true);
2249    hmPtr->setLineContourVisible(true);
2250    NanoVis::heightMap.push_back(hmPtr);
2251    return TCL_OK;
2252}
2253
2254static int
2255HeightMapDataVisibleOp(ClientData cdata, Tcl_Interp *interp, int objc,
2256                       Tcl_Obj *const *objv)
2257{
2258    bool visible;
2259    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
2260        return TCL_ERROR;
2261    }
2262    vector<HeightMap *> imap;
2263    if (GetHeightMaps(interp, objc - 4, objv + 4, &imap) != TCL_OK) {
2264        return TCL_ERROR;
2265    }
2266    vector<HeightMap *>::iterator iter;
2267    for (iter = imap.begin(); iter != imap.end(); iter++) {
2268        (*iter)->setVisible(visible);
2269    }
2270    return TCL_OK;
2271}
2272
2273static Rappture::CmdSpec heightMapDataOps[] = {
2274    {"follows",      1, HeightMapDataFollowsOp, 4, 4, "length",},
2275    {"visible",      1, HeightMapDataVisibleOp, 4, 0, "bool ?indices?",},
2276};
2277static int nHeightMapDataOps = NumCmdSpecs(heightMapDataOps);
2278
2279static int
2280HeightMapDataOp(ClientData cdata, Tcl_Interp *interp, int objc,
2281                Tcl_Obj *const *objv)
2282{
2283    Tcl_ObjCmdProc *proc;
2284
2285    proc = Rappture::GetOpFromObj(interp, nHeightMapDataOps, heightMapDataOps,
2286                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
2287    if (proc == NULL) {
2288        return TCL_ERROR;
2289    }
2290    return (*proc) (cdata, interp, objc, objv);
2291}
2292
2293
2294static int
2295HeightMapLineContourColorOp(ClientData cdata, Tcl_Interp *interp, int objc,
2296                            Tcl_Obj *const *objv)
2297{
2298    float rgb[3];
2299    if (GetColor(interp, objc - 3, objv + 3, rgb) != TCL_OK) {
2300        return TCL_ERROR;
2301    }
2302    vector<HeightMap *> imap;
2303    if (GetHeightMaps(interp, objc - 6, objv + 6, &imap) != TCL_OK) {
2304        return TCL_ERROR;
2305    }
2306    vector<HeightMap *>::iterator iter;
2307    for (iter = imap.begin(); iter != imap.end(); iter++) {
2308        (*iter)->setLineContourColor(rgb);
2309    }
2310    return TCL_OK;
2311}
2312
2313static int
2314HeightMapLineContourVisibleOp(ClientData cdata, Tcl_Interp *interp, int objc,
2315                              Tcl_Obj *const *objv)
2316{
2317    bool visible;
2318    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
2319        return TCL_ERROR;
2320    }
2321    vector<HeightMap *> imap;
2322    if (GetHeightMaps(interp, objc - 4, objv + 4, &imap) != TCL_OK) {
2323        return TCL_ERROR;
2324    }
2325    vector<HeightMap *>::iterator iter;
2326    for (iter = imap.begin(); iter != imap.end(); iter++) {
2327        (*iter)->setLineContourVisible(visible);
2328    }
2329    return TCL_OK;
2330}
2331
2332static Rappture::CmdSpec heightMapLineContourOps[] = {
2333    {"color",   1, HeightMapLineContourColorOp,   4, 4, "length",},
2334    {"visible", 1, HeightMapLineContourVisibleOp, 4, 0, "bool ?indices?",},
2335};
2336static int nHeightMapLineContourOps = NumCmdSpecs(heightMapLineContourOps);
2337
2338static int
2339HeightMapLineContourOp(ClientData cdata, Tcl_Interp *interp, int objc,
2340                       Tcl_Obj *const *objv)
2341{
2342    Tcl_ObjCmdProc *proc;
2343
2344    proc = Rappture::GetOpFromObj(interp, nHeightMapLineContourOps,
2345        heightMapLineContourOps, Rappture::CMDSPEC_ARG2, objc, objv, 0);
2346    if (proc == NULL) {
2347        return TCL_ERROR;
2348    }
2349    return (*proc) (cdata, interp, objc, objv);
2350}
2351
2352static int
2353HeightMapCullOp(ClientData cdata, Tcl_Interp *interp, int objc,
2354                Tcl_Obj *const *objv)
2355{
2356    graphics::RenderContext::CullMode mode;
2357    if (GetCullMode(interp, objv[2], &mode) != TCL_OK) {
2358        return TCL_ERROR;
2359    }
2360    NanoVis::renderContext->setCullMode(mode);
2361    return TCL_OK;
2362}
2363
2364static int
2365HeightMapCreateOp(ClientData cdata, Tcl_Interp *interp, int objc,
2366                  Tcl_Obj *const *objv)
2367{
2368    HeightMap *hmPtr;
2369
2370    /* heightmap create xmin ymin xmax ymax xnum ynum values */
2371    hmPtr = CreateHeightMap(cdata, interp, objc - 2, objv + 2);
2372    if (hmPtr == NULL) {
2373        return TCL_ERROR;
2374    }
2375    NanoVis::heightMap.push_back(hmPtr);
2376    Tcl_SetIntObj(Tcl_GetObjResult(interp), NanoVis::heightMap.size() - 1);;
2377    return TCL_OK;
2378}
2379
2380static int
2381HeightMapLegendOp(ClientData cdata, Tcl_Interp *interp, int objc,
2382                  Tcl_Obj *const *objv)
2383{
2384    HeightMap *hmPtr;
2385    if (GetHeightMapFromObj(interp, objv[2], &hmPtr) != TCL_OK) {
2386        return TCL_ERROR;
2387    }
2388    TransferFunction *tf;
2389    tf = hmPtr->getColorMap();
2390    if (tf == NULL) {
2391        Tcl_AppendResult(interp, "no transfer function defined for heightmap \"",
2392                         Tcl_GetString(objv[2]), "\"", (char*)NULL);
2393        return TCL_ERROR;
2394    }
2395    int w, h;
2396    if ((Tcl_GetIntFromObj(interp, objv[3], &w) != TCL_OK) ||
2397        (Tcl_GetIntFromObj(interp, objv[4], &h) != TCL_OK)) {
2398        return TCL_ERROR;
2399    }
2400    if (HeightMap::update_pending) {
2401        NanoVis::SetHeightmapRanges();
2402    }
2403    NanoVis::render_legend(tf, HeightMap::valueMin, HeightMap::valueMax, w, h,
2404        "label");
2405    return TCL_OK;
2406}
2407
2408static int
2409HeightMapPolygonOp(ClientData cdata, Tcl_Interp *interp, int objc,
2410                   Tcl_Obj *const *objv)
2411{
2412    graphics::RenderContext::PolygonMode mode;
2413    if (GetPolygonMode(interp, objv[2], &mode) != TCL_OK) {
2414        return TCL_ERROR;
2415    }
2416    NanoVis::renderContext->setPolygonMode(mode);
2417    return TCL_OK;
2418}
2419
2420static int
2421HeightMapShadingOp(ClientData cdata, Tcl_Interp *interp, int objc,
2422                 Tcl_Obj *const *objv)
2423{
2424    graphics::RenderContext::ShadingModel model;
2425    if (GetShadingModel(interp, objv[2], &model) != TCL_OK) {
2426        return TCL_ERROR;
2427    }
2428    NanoVis::renderContext->setShadingModel(model);
2429    return TCL_OK;
2430}
2431
2432
2433static int
2434HeightMapTopView(ClientData data, Tcl_Interp *interp, int objc,
2435                Tcl_Obj *const *objv)
2436{
2437
2438    // the variables below should be reassigned
2439    int image_width = 512;
2440    int image_height = 512;
2441    HeightMap* heightmap = 0;
2442
2443    // HELP ME
2444    // GEORGE
2445
2446    NanoVis::render_2d_contour(heightmap, image_width, image_height);
2447
2448    return TCL_OK;
2449}
2450
2451static int
2452HeightMapTestOp(ClientData cdata, Tcl_Interp *interp, int objc,
2453                Tcl_Obj *const *objv)
2454{
2455    srand((unsigned)time(NULL));
2456
2457    int size = 20 * 20;
2458    double sigma = 5.0;
2459    double mean = exp(0.0) / (sigma * sqrt(2.0));
2460    float* data = (float*) malloc(sizeof(float) * size);
2461
2462    float x, y;
2463    for (int i = 0; i < size; ++i) {
2464        x = - 10 + i%20;
2465        y = - 10 + (i/20);
2466        data[i] = exp(- (x * y)/(2 * sigma * sigma)) /
2467            (sigma * sqrt(2.0)) / mean * 2 + 1000;
2468        //data[i] = ((float)rand()) / RAND_MAX * 1.0;
2469    }
2470
2471    HeightMap* hmPtr = new HeightMap();
2472    float minx = 0.0f;
2473    float maxx = 1.0f;
2474    float miny = 0.5f;
2475    float maxy = 3.5f;
2476    hmPtr->setHeight(minx, miny, maxx, maxy, 20, 20, data);
2477    hmPtr->setColorMap(NanoVis::get_transfunc("default"));
2478    hmPtr->setVisible(true);
2479    hmPtr->setLineContourVisible(true);
2480    NanoVis::grid->setVisible(true);
2481    NanoVis::heightMap.push_back(hmPtr);
2482
2483    int image_width = 512;
2484    int image_height = 512;
2485
2486    NanoVis::render_2d_contour(hmPtr, image_width, image_height);
2487
2488    return TCL_OK;
2489}
2490
2491static int
2492HeightMapTransFuncOp(ClientData cdata, Tcl_Interp *interp, int objc,
2493                     Tcl_Obj *const *objv)
2494{
2495    const char *name;
2496    name = Tcl_GetString(objv[2]);
2497    TransferFunction *tf;
2498    tf = NanoVis::get_transfunc(name);
2499    if (tf == NULL) {
2500        Tcl_AppendResult(interp, "transfer function \"", name,
2501                         "\" is not defined", (char*)NULL);
2502        return TCL_ERROR;
2503    }
2504    vector<HeightMap *> imap;
2505    if (GetHeightMaps(interp, objc - 3, objv + 3, &imap) != TCL_OK) {
2506        return TCL_ERROR;
2507    }
2508    vector<HeightMap *>::iterator iter;
2509    for (iter = imap.begin(); iter != imap.end(); iter++) {
2510        (*iter)->setColorMap(tf);
2511    }
2512    return TCL_OK;
2513}
2514
2515static Rappture::CmdSpec heightMapOps[] = {
2516    {"create",       2, HeightMapCreateOp,      9, 9,
2517     "xmin ymin xmax ymax xnum ynum values",},
2518    {"cull",         2, HeightMapCullOp,        3, 3, "mode",},
2519    {"data",         1, HeightMapDataOp,        3, 0, "oper ?args?",},
2520    {"legend",       2, HeightMapLegendOp,      5, 5, "index width height",},
2521    {"linecontour",  2, HeightMapLineContourOp, 2, 0, "oper ?args?",},
2522    {"polygon",      1, HeightMapPolygonOp,     3, 3, "mode",},
2523    {"shading",      1, HeightMapShadingOp,     3, 3, "model",},
2524    {"test",         2, HeightMapTestOp,        2, 2, "",},
2525    {"transfunc",    2, HeightMapTransFuncOp,   3, 0, "name ?indices?",},
2526
2527    // HELP ME
2528    // GOERGE
2529    {"topview",      2, HeightMapTopView,     2, 2, "",},
2530};
2531static int nHeightMapOps = NumCmdSpecs(heightMapOps);
2532
2533static int
2534HeightMapCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
2535{
2536    Tcl_ObjCmdProc *proc;
2537
2538    proc = Rappture::GetOpFromObj(interp, nHeightMapOps, heightMapOps,
2539                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
2540    if (proc == NULL) {
2541        return TCL_ERROR;
2542    }
2543    return (*proc) (cdata, interp, objc, objv);
2544}
2545
2546static int
2547GridAxisColorOp(ClientData cdata, Tcl_Interp *interp, int objc,
2548                Tcl_Obj *const *objv)
2549{
2550    float r, g, b, a;
2551    if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
2552        (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
2553        (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
2554        return TCL_ERROR;
2555    }
2556    a = 1.0f;
2557    if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
2558        return TCL_ERROR;
2559    }
2560    if (NanoVis::grid) {
2561        NanoVis::grid->setAxisColor(r, g, b, a);
2562    }
2563    return TCL_OK;
2564}
2565
2566static int
2567GridAxisNameOp(ClientData cdata, Tcl_Interp *interp, int objc,
2568               Tcl_Obj *const *objv)
2569{
2570    int axis;
2571    if (GetAxisFromObj(interp, objv[2], &axis) != TCL_OK) {
2572        return TCL_ERROR;
2573    }
2574    if (NanoVis::grid != NULL) {
2575        Axis *axisPtr;
2576
2577        axisPtr = NULL;     /* Suppress compiler warning. */
2578        switch (axis) {
2579        case 0: axisPtr = &NanoVis::grid->xAxis; break;
2580        case 1: axisPtr = &NanoVis::grid->yAxis; break;
2581        case 2: axisPtr = &NanoVis::grid->zAxis; break;
2582        }
2583        axisPtr->name(Tcl_GetString(objv[3]));
2584        axisPtr->units(Tcl_GetString(objv[4]));
2585    }
2586    return TCL_OK;
2587}
2588
2589static int
2590GridLineColorOp(ClientData cdata, Tcl_Interp *interp, int objc,
2591                Tcl_Obj *const *objv)
2592{
2593    float r, g, b, a;
2594    if ((GetFloatFromObj(interp, objv[2], &r) != TCL_OK) ||
2595        (GetFloatFromObj(interp, objv[3], &g) != TCL_OK) ||
2596        (GetFloatFromObj(interp, objv[4], &b) != TCL_OK)) {
2597        return TCL_ERROR;
2598    }
2599    a = 1.0f;
2600    if ((objc == 6) && (GetFloatFromObj(interp, objv[5], &a) != TCL_OK)) {
2601        return TCL_ERROR;
2602    }
2603    if (NanoVis::grid) {
2604        NanoVis::grid->setLineColor(r, g, b, a);
2605    }
2606    return TCL_OK;
2607}
2608
2609static int
2610GridVisibleOp(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
2611{
2612    bool visible;
2613    if (GetBooleanFromObj(interp, objv[2], &visible) != TCL_OK) {
2614        return TCL_ERROR;
2615    }
2616    NanoVis::grid->setVisible(visible);
2617    return TCL_OK;
2618}
2619
2620static Rappture::CmdSpec gridOps[] = {
2621    {"axiscolor",  5, GridAxisColorOp,  5, 6, "r g b ?a?",},
2622    {"axisname",   5, GridAxisNameOp,   5, 5, "index title units",},
2623    {"linecolor",  7, GridLineColorOp,  5, 6, "r g b ?a?",},
2624    {"visible",    1, GridVisibleOp,    3, 3, "bool",},
2625};
2626static int nGridOps = NumCmdSpecs(gridOps);
2627
2628static int
2629GridCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
2630{
2631    Tcl_ObjCmdProc *proc;
2632
2633    proc = Rappture::GetOpFromObj(interp, nGridOps, gridOps,
2634        Rappture::CMDSPEC_ARG1, objc, objv, 0);
2635    if (proc == NULL) {
2636        return TCL_ERROR;
2637    }
2638    return (*proc) (cdata, interp, objc, objv);
2639}
2640
2641static int
2642AxisCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
2643{
2644    if (objc < 2) {
2645        Tcl_AppendResult(interp, "wrong # args: should be \"",
2646                Tcl_GetString(objv[0]), " option arg arg...\"", (char*)NULL);
2647        return TCL_ERROR;
2648    }
2649    const char *string = Tcl_GetString(objv[1]);
2650    char c = string[0];
2651    if ((c == 'v') && (strcmp(string, "visible") == 0)) {
2652        bool visible;
2653
2654        if (GetBooleanFromObj(interp, objv[2], &visible) != TCL_OK) {
2655            return TCL_ERROR;
2656        }
2657        NanoVis::axis_on = visible;
2658    } else {
2659        Tcl_AppendResult(interp, "bad axis option \"", string,
2660                         "\": should be visible", (char*)NULL);
2661        return TCL_ERROR;
2662    }
2663    return TCL_OK;
2664}
2665
2666#if PLANE_CMD
2667static int
2668PlaneNewOp(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
2669{
2670    fprintf(stderr, "load plane for 2D visualization command\n");
2671    int index, w, h;
2672    if (objc != 4) {
2673        Tcl_AppendResult(interp, "wrong # args: should be \"",
2674            Tcl_GetString(objv[0]), " plane_index w h \"", (char*)NULL);
2675        return TCL_ERROR;
2676    }
2677    if (Tcl_GetIntFromObj(interp, objv[1], &index) != TCL_OK) {
2678        return TCL_ERROR;
2679    }
2680    if (Tcl_GetIntFromObj(interp, objv[2], &w) != TCL_OK) {
2681        return TCL_ERROR;
2682    }
2683    if (Tcl_GetIntFromObj(interp, objv[3], &h) != TCL_OK) {
2684        return TCL_ERROR;
2685    }
2686
2687    //Now read w*h*4 bytes. The server expects the plane to be a stream of
2688    //floats
2689    char* tmp = new char[int(w*h*sizeof(float))];
2690    if (tmp == NULL) {
2691        Tcl_AppendResult(interp, "can't allocate stream data", (char *)NULL);
2692        return TCL_ERROR;
2693    }
2694    bzero(tmp, w*h*4);
2695    int status = read(0, tmp, w*h*sizeof(float));
2696    if (status <= 0) {
2697        exit(0);                // Bail out on read error?  Should log the
2698                                // error and return a non-zero exit status.
2699    }
2700    plane[index] = new Texture2D(w, h, GL_FLOAT, GL_LINEAR, 1, (float*)tmp);
2701    delete[] tmp;
2702    return TCL_OK;
2703}
2704
2705
2706static int
2707PlaneLinkOp(ClientData cdata, Tcl_Interp *interp, int objc,
2708            Tcl_Obj *const *objv)
2709{
2710    fprintf(stderr, "link the plane to the 2D renderer command\n");
2711
2712    int plane_index, tf_index;
2713
2714    if (objc != 3) {
2715        Tcl_AppendResult(interp, "wrong # args: should be \"",
2716            Tcl_GetString(objv[0]), " plane_index tf_index \"", (char*)NULL);
2717        return TCL_ERROR;
2718    }
2719    if (Tcl_GetIntFromObj(interp, objv[1], &plane_index) != TCL_OK) {
2720        return TCL_ERROR;
2721    }
2722    if (Tcl_GetIntFromObj(interp, objv[2], &tf_index) != TCL_OK) {
2723        return TCL_ERROR;
2724    }
2725    //plane_render->add_plane(plane[plane_index], tf[tf_index]);
2726    return TCL_OK;
2727}
2728
2729//Enable a 2D plane for render
2730//The plane_index is the index mantained in the 2D plane renderer
2731static int
2732PlaneEnableOp(ClientData cdata, Tcl_Interp *interp, int objc,
2733              Tcl_Obj *const *objv)
2734{
2735    fprintf(stderr,"enable a plane so the 2D renderer can render it command\n");
2736
2737    if (objc != 3) {
2738        Tcl_AppendResult(interp, "wrong # args: should be \"",
2739            Tcl_GetString(objv[0]), " plane_index mode \"", (char*)NULL);
2740        return TCL_ERROR;
2741    }
2742    int plane_index;
2743    if (Tcl_GetIntFromObj(interp, objv[1], &plane_index) != TCL_OK) {
2744        return TCL_ERROR;
2745    }
2746    int mode;
2747    if (Tcl_GetIntFromObj(interp, objv[2], &mode) != TCL_OK) {
2748        return TCL_ERROR;
2749    }
2750    if (mode == 0) {
2751        plane_index = -1;
2752    }
2753    plane_render->set_active_plane(plane_index);
2754    return TCL_OK;
2755}
2756
2757static Rappture::CmdSpec planeOps[] = {
2758    {"enable",     1, PlaneEnableOp,    4, 4, "planeIdx mode",},
2759    {"link",       1, PlaneLinkOp,      4, 4, "planeIdx transfuncIdx",},
2760    {"new",        1, PlaneNewOp,       5, 5, "planeIdx width height",},
2761};
2762static int nPlaneOps = NumCmdSpecs(planeOps);
2763
2764static int
2765PlaneCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
2766{
2767    Tcl_ObjCmdProc *proc;
2768
2769    proc = Rappture::GetOpFromObj(interp, nPlaneOps, planeOps,
2770                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
2771    if (proc == NULL) {
2772        return TCL_ERROR;
2773    }
2774    return (*proc) (cdata, interp, objc, objv);
2775}
2776
2777#endif  /*PLANE_CMD*/
2778
2779/*
2780 * This command should be Tcl procedure instead of a C command.  The reason
2781 * for this that 1) we are using a safe interpreter so we would need a master
2782 * interpreter to load the Tcl environment properly (including our "unirect2d"
2783 * procedure). And 2) the way nanovis is currently deployed doesn't make it
2784 * easy to add new directories for procedures, since it's loaded into /tmp.
2785 *
2786 * Ideally, the "unirect2d" proc would do a rundimentary parsing of the data
2787 * to verify the structure and then pass it to the appropiate Tcl command
2788 * (heightmap, volume, etc). Our C command always creates a heightmap.
2789 */
2790static int
2791Unirect2dCmd(ClientData clientData, Tcl_Interp *interp, int objc,
2792             Tcl_Obj *const *objv)
2793{
2794    Rappture::Unirect2d *dataPtr = (Rappture::Unirect2d *)clientData;
2795
2796    return dataPtr->LoadData(interp, objc, objv);
2797}
2798
2799/*
2800 * This command should be Tcl procedure instead of a C command.  The reason
2801 * for this that 1) we are using a safe interpreter so we would need a master
2802 * interpreter to load the Tcl environment properly (including our "unirect2d"
2803 * procedure). And 2) the way nanovis is currently deployed doesn't make it
2804 * easy to add new directories for procedures, since it's loaded into /tmp.
2805 *
2806 * Ideally, the "unirect2d" proc would do a rundimentary parsing of the data
2807 * to verify the structure and then pass it to the appropiate Tcl command
2808 * (heightmap, volume, etc). Our C command always creates a heightmap.
2809 */
2810
2811static int
2812Unirect3dCmd(ClientData clientData, Tcl_Interp *interp, int objc,
2813             Tcl_Obj *const *objv)
2814{
2815    Rappture::Unirect3d *dataPtr = (Rappture::Unirect3d *)clientData;
2816
2817    return dataPtr->LoadData(interp, objc, objv);
2818}
2819
2820Tcl_Interp *
2821initTcl()
2822{
2823
2824    /*
2825     * Ideally the connection is authenticated by nanoscale.  I still like the
2826     * idea of creating a non-safe master interpreter with a safe slave
2827     * interpreter.  Alias all the nanovis commands in the slave. That way we
2828     * can still run Tcl code within nanovis.  The eventual goal is to create
2829     * a test harness through the interpreter for nanovis.
2830     */
2831    Tcl_Interp *interp;
2832    interp = Tcl_CreateInterp();
2833    Tcl_MakeSafe(interp);
2834
2835    Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        NULL, NULL);
2836    Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      NULL, NULL);
2837    Tcl_CreateObjCommand(interp, "cutplane",    CutplaneCmd,    NULL, NULL);
2838    Tcl_CreateObjCommand(interp, "flow",        FlowCmd,        NULL, NULL);
2839    Tcl_CreateObjCommand(interp, "grid",        GridCmd,        NULL, NULL);
2840    Tcl_CreateObjCommand(interp, "heightmap",   HeightMapCmd,   NULL, NULL);
2841    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      NULL, NULL);
2842    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      NULL, NULL);
2843    Tcl_CreateObjCommand(interp, "snapshot",    SnapshotCmd,    NULL, NULL);
2844    Tcl_CreateObjCommand(interp, "transfunc",   TransfuncCmd,   NULL, NULL);
2845    Tcl_CreateObjCommand(interp, "unirect2d",   Unirect2dCmd,   NULL, NULL);
2846    Tcl_CreateObjCommand(interp, "unirect3d",   Unirect3dCmd,   NULL, NULL);
2847    Tcl_CreateObjCommand(interp, "up",          UpCmd,          NULL, NULL);
2848    Tcl_CreateObjCommand(interp, "volume",      VolumeCmd,      NULL, NULL);
2849#if __TEST_CODE__
2850    Tcl_CreateObjCommand(interp, "test", TestCmd, NULL, NULL);
2851#endif
2852
2853    // create a default transfer function
2854    if (Tcl_Eval(interp, def_transfunc) != TCL_OK) {
2855        fprintf(NanoVis::logfile, "WARNING: bad default transfer function\n");
2856        fprintf(NanoVis::logfile, "%s\n", Tcl_GetStringResult(interp));
2857    }
2858    return interp;
2859}
2860
2861
Note: See TracBrowser for help on using the repository browser.