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

Last change on this file since 1699 was 1558, checked in by gah, 15 years ago

fix and re-enable <ODX> output type

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