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

Last change on this file since 1484 was 1484, checked in by vrinside, 15 years ago

added 2d arrows (arrow tip will be added)

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