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

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