source: trunk/packages/vizservers/vtkvis/RpVtkRendererCmd.cpp @ 2269

Last change on this file since 2269 was 2269, checked in by ldelgass, 13 years ago

Add glyphs command/object for rendering 3D glyph objects at all points in a
data set with scaling and color mapping. Useful for vector field hedgehogs
and general 3D scatter plots. Still need to deal with data ranges better and
add options for using vector mag. vs. components for scaling, etc.
Also compute point data when only cell data is present and point data is needed.
Probably this should be done in the DataSet? class instead to minimize
duplicating work.

  • Property svn:eol-style set to native
File size: 68.6 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2011, Purdue Research Foundation
4 *
5 * Author: Leif Delgass <ldelgass@purdue.edu>
6 */
7
8#include <cstdlib>
9#include <cstdio>
10#include <cstring>
11#include <cerrno>
12#include <unistd.h>
13#include <sys/uio.h>
14#include <fcntl.h>
15#include <tcl.h>
16
17#include "Trace.h"
18#include "CmdProc.h"
19#include "RpVtkRendererCmd.h"
20#include "RpVtkRenderServer.h"
21#include "PPMWriter.h"
22#include "TGAWriter.h"
23
24using namespace Rappture::VtkVis;
25
26static int
27ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr)
28{
29    int result;
30
31    result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr));
32    Tcl_DStringSetLength(dsPtr, 0);
33
34    return result;
35}
36
37static bool
38GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, bool *boolPtr)
39{
40    int value;
41
42    if (Tcl_GetBooleanFromObj(interp, objPtr, &value) != TCL_OK) {
43        return TCL_ERROR;
44    }
45    *boolPtr = (bool)value;
46    return TCL_OK;
47}
48
49int
50GetFloatFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, float *valuePtr)
51{
52    double value;
53
54    if (Tcl_GetDoubleFromObj(interp, objPtr, &value) != TCL_OK) {
55        return TCL_ERROR;
56    }
57    *valuePtr = (float)value;
58    return TCL_OK;
59}
60
61static int
62AxisColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
63            Tcl_Obj *const *objv)
64{
65    double color[3];
66    if (Tcl_GetDoubleFromObj(interp, objv[2], &color[0]) != TCL_OK ||
67        Tcl_GetDoubleFromObj(interp, objv[3], &color[1]) != TCL_OK ||
68        Tcl_GetDoubleFromObj(interp, objv[4], &color[2]) != TCL_OK) {
69        return TCL_ERROR;
70    }
71    g_renderer->setAxesColor(color);
72    return TCL_OK;
73}
74
75static int
76AxisFlyModeOp(ClientData clientData, Tcl_Interp *interp, int objc,
77              Tcl_Obj *const *objv)
78{
79    const char *string = Tcl_GetString(objv[2]);
80    char c = string[0];
81    Renderer::AxesFlyMode mode;
82    if ((c == 's') && (strcmp(string, "static_edges") == 0)) {
83        mode = Renderer::FLY_STATIC_EDGES;
84    } else if ((c == 's') && (strcmp(string, "static_triad") == 0)) {
85        mode = Renderer::FLY_STATIC_TRIAD;
86    } else if ((c == 'o') && (strcmp(string, "outer_edges") == 0)) {
87        mode = Renderer::FLY_OUTER_EDGES;
88    } else if ((c == 'f') && (strcmp(string, "furthest_triad") == 0)) {
89        mode = Renderer::FLY_FURTHEST_TRIAD;
90    } else if ((c == 'c') && (strcmp(string, "closest_triad") == 0)) {
91        mode = Renderer::FLY_CLOSEST_TRIAD;
92    } else {
93        Tcl_AppendResult(interp, "bad axis flymode option \"", string,
94                         "\": should be static_edges, static_triad, outer_edges, furthest_triad, or closest_triad", (char*)NULL);
95        return TCL_ERROR;
96    }
97    g_renderer->setAxesFlyMode(mode);
98    return TCL_OK;
99}
100
101static int
102AxisGridOp(ClientData clientData, Tcl_Interp *interp, int objc,
103           Tcl_Obj *const *objv)
104{
105    bool visible;
106    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
107        return TCL_ERROR;
108    }
109    const char *string = Tcl_GetString(objv[2]);
110    char c = string[0];
111    if ((c == 'x') && (strcmp(string, "x") == 0)) {
112        g_renderer->setAxisGridVisibility(Renderer::X_AXIS, visible);
113    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
114        g_renderer->setAxisGridVisibility(Renderer::Y_AXIS, visible);
115    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
116        g_renderer->setAxisGridVisibility(Renderer::Z_AXIS, visible);
117    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
118        g_renderer->setAxesGridVisibility(visible);
119    } else {
120        Tcl_AppendResult(interp, "bad axis option \"", string,
121                         "\": should be axisName visible", (char*)NULL);
122        return TCL_ERROR;
123    }
124    return TCL_OK;
125}
126
127static int
128AxisNameOp(ClientData clientData, Tcl_Interp *interp, int objc,
129           Tcl_Obj *const *objv)
130{
131    const char *title = Tcl_GetString(objv[3]);
132    const char *string = Tcl_GetString(objv[2]);
133    char c = string[0];
134    if ((c == 'x') && (strcmp(string, "x") == 0)) {
135        g_renderer->setAxisTitle(Renderer::X_AXIS, title);
136    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
137        g_renderer->setAxisTitle(Renderer::Y_AXIS, title);
138    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
139        g_renderer->setAxisTitle(Renderer::Z_AXIS, title);
140    } else {
141        Tcl_AppendResult(interp, "bad axis option \"", string,
142                         "\": should be axisName title", (char*)NULL);
143        return TCL_ERROR;
144    }
145    return TCL_OK;
146}
147
148static int
149AxisUnitsOp(ClientData clientData, Tcl_Interp *interp, int objc,
150            Tcl_Obj *const *objv)
151{
152    const char *units = Tcl_GetString(objv[3]);
153    const char *string = Tcl_GetString(objv[2]);
154    char c = string[0];
155    if ((c == 'x') && (strcmp(string, "x") == 0)) {
156        g_renderer->setAxisUnits(Renderer::X_AXIS, units);
157    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
158        g_renderer->setAxisUnits(Renderer::Y_AXIS, units);
159    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
160        g_renderer->setAxisUnits(Renderer::Z_AXIS, units);
161    } else {
162        Tcl_AppendResult(interp, "bad axis option \"", string,
163                         "\": should be axisName units", (char*)NULL);
164        return TCL_ERROR;
165    }
166    return TCL_OK;
167}
168
169static int
170AxisVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
171              Tcl_Obj *const *objv)
172{
173    bool visible;
174    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
175        return TCL_ERROR;
176    }
177    const char *string = Tcl_GetString(objv[2]);
178    char c = string[0];
179    if ((c == 'x') && (strcmp(string, "x") == 0)) {
180        g_renderer->setAxisVisibility(Renderer::X_AXIS, visible);
181    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
182        g_renderer->setAxisVisibility(Renderer::Y_AXIS, visible);
183    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
184        g_renderer->setAxisVisibility(Renderer::Z_AXIS, visible);
185    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
186        g_renderer->setAxesVisibility(visible);
187    } else {
188        Tcl_AppendResult(interp, "bad axis option \"", string,
189                         "\": should be axisName visible", (char*)NULL);
190        return TCL_ERROR;
191    }
192    return TCL_OK;
193}
194
195static Rappture::CmdSpec axisOps[] = {
196    {"color",   1, AxisColorOp, 5, 5, "r g b"},
197    {"flymode", 1, AxisFlyModeOp, 3, 3, "mode"},
198    {"grid",    1, AxisGridOp, 4, 4, "axis bool"},
199    {"name",    1, AxisNameOp, 4, 4, "axis title"},
200    {"units",   1, AxisUnitsOp, 4, 4, "axis units"},
201    {"visible", 1, AxisVisibleOp, 4, 4, "axis bool"}
202};
203static int nAxisOps = NumCmdSpecs(axisOps);
204
205static int
206AxisCmd(ClientData clientData, Tcl_Interp *interp, int objc,
207        Tcl_Obj *const *objv)
208{
209    Tcl_ObjCmdProc *proc;
210
211    proc = Rappture::GetOpFromObj(interp, nAxisOps, axisOps,
212                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
213    if (proc == NULL) {
214        return TCL_ERROR;
215    }
216    return (*proc) (clientData, interp, objc, objv);
217}
218
219static int
220CameraModeOp(ClientData clientData, Tcl_Interp *interp, int objc,
221             Tcl_Obj *const *objv)
222{
223    Renderer::CameraMode mode;
224    const char *string = Tcl_GetString(objv[2]);
225    if ((strcmp(string, "persp") == 0)) {
226        mode = Renderer::PERSPECTIVE;
227    } else if ((strcmp(string, "ortho") == 0)) {
228        mode = Renderer::ORTHO;
229    } else if ((strcmp(string, "image") == 0)) {
230        mode = Renderer::IMAGE;
231    } else {
232        Tcl_AppendResult(interp, "bad camera mode option \"", string,
233                         "\": should be persp, ortho or image", (char*)NULL);
234        return TCL_ERROR;
235    }
236    g_renderer->setCameraMode(mode);
237    return TCL_OK;
238}
239
240static int
241CameraGetOrientationOp(ClientData clientData, Tcl_Interp *interp, int objc,
242                       Tcl_Obj *const *objv)
243{
244    double pos[3];
245    double focalPt[3];
246    double viewUp[3];
247
248    g_renderer->getCameraOrientationAndPosition(pos, focalPt, viewUp);
249
250    char buf[256];
251    snprintf(buf, sizeof(buf), "nv>camera orient %.12e %.12e %.12e %.12e %.12e %.12e %.12e %.12e %.12e",
252             pos[0], pos[1], pos[2], focalPt[0], focalPt[1], focalPt[2], viewUp[0], viewUp[1], viewUp[2]);
253    ssize_t bytesWritten;
254    size_t len = strlen(buf);
255    size_t ofs = 0;
256    while ((bytesWritten = write(g_fdOut, buf + ofs, len - ofs)) > 0) {
257        ofs += bytesWritten;
258        if (ofs == len)
259            break;
260    }
261    if (bytesWritten < 0) {
262        return TCL_ERROR;
263    }
264    return TCL_OK;
265}
266
267static int
268CameraOrientationOp(ClientData clientData, Tcl_Interp *interp, int objc,
269                    Tcl_Obj *const *objv)
270{
271    double quat[4];
272
273    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
274        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
275        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
276        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
277        return TCL_ERROR;
278    }
279
280    g_renderer->setCameraOrientation(quat);
281    return TCL_OK;
282}
283
284static int
285CameraOrthoOp(ClientData clientData, Tcl_Interp *interp, int objc,
286              Tcl_Obj *const *objv)
287{
288    double x, y, width, height;
289
290    if (Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK ||
291        Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK ||
292        Tcl_GetDoubleFromObj(interp, objv[4], &width) != TCL_OK ||
293        Tcl_GetDoubleFromObj(interp, objv[5], &height) != TCL_OK) {
294        return TCL_ERROR;
295    }
296
297    g_renderer->setCameraZoomRegion(x, y, width, height);
298    return TCL_OK;
299}
300
301static int
302CameraPanOp(ClientData clientData, Tcl_Interp *interp, int objc,
303            Tcl_Obj *const *objv)
304{
305    double x, y;
306
307    if (Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK ||
308        Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK) {
309        return TCL_ERROR;
310    }
311
312    g_renderer->panCamera(x, y);
313    return TCL_OK;
314}
315
316static int
317CameraResetOp(ClientData clientData, Tcl_Interp *interp, int objc,
318              Tcl_Obj *const *objv)
319{
320    if (objc == 3) {
321        const char *string = Tcl_GetString(objv[2]);
322        char c = string[0];
323        if ((c != 'a') || (strcmp(string, "all") != 0)) {
324            Tcl_AppendResult(interp, "bad camera reset option \"", string,
325                         "\": should be all", (char*)NULL);
326            return TCL_ERROR;
327        }
328        g_renderer->resetCamera(true);
329    } else {
330        g_renderer->resetCamera(false);
331    }
332    return TCL_OK;
333}
334
335static int
336CameraRotateOp(ClientData clientData, Tcl_Interp *interp, int objc,
337               Tcl_Obj *const *objv)
338{
339    double yaw, pitch, roll;
340
341    if (Tcl_GetDoubleFromObj(interp, objv[2], &yaw) != TCL_OK ||
342        Tcl_GetDoubleFromObj(interp, objv[3], &pitch) != TCL_OK ||
343        Tcl_GetDoubleFromObj(interp, objv[4], &roll) != TCL_OK) {
344        return TCL_ERROR;
345    }
346
347    g_renderer->rotateCamera(yaw, pitch, roll);
348    return TCL_OK;
349}
350
351static int
352CameraSetOp(ClientData clientData, Tcl_Interp *interp, int objc,
353            Tcl_Obj *const *objv)
354{
355    double pos[3];
356    double focalPt[3];
357    double viewUp[3];
358
359    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
360        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
361        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK ||
362        Tcl_GetDoubleFromObj(interp, objv[5], &focalPt[0]) != TCL_OK ||
363        Tcl_GetDoubleFromObj(interp, objv[6], &focalPt[1]) != TCL_OK ||
364        Tcl_GetDoubleFromObj(interp, objv[7], &focalPt[2]) != TCL_OK ||
365        Tcl_GetDoubleFromObj(interp, objv[8], &viewUp[0]) != TCL_OK ||
366        Tcl_GetDoubleFromObj(interp, objv[9], &viewUp[1]) != TCL_OK ||
367        Tcl_GetDoubleFromObj(interp, objv[10], &viewUp[2]) != TCL_OK) {
368        return TCL_ERROR;
369    }
370
371    g_renderer->setCameraOrientationAndPosition(pos, focalPt, viewUp);
372    return TCL_OK;
373}
374
375static int
376CameraZoomOp(ClientData clientData, Tcl_Interp *interp, int objc,
377            Tcl_Obj *const *objv)
378{
379    double z;
380
381    if (Tcl_GetDoubleFromObj(interp, objv[2], &z) != TCL_OK) {
382        return TCL_ERROR;
383    }
384
385    g_renderer->zoomCamera(z);
386    return TCL_OK;
387}
388
389static Rappture::CmdSpec cameraOps[] = {
390    {"get", 1, CameraGetOrientationOp, 2, 2, ""},
391    {"mode", 1, CameraModeOp, 3, 3, "mode"},
392    {"orient", 3, CameraOrientationOp, 6, 6, "qw qx qy qz"},
393    {"ortho", 1, CameraOrthoOp, 6, 6, "x y width height"},
394    {"pan", 1, CameraPanOp, 4, 4, "panX panY"},
395    {"reset", 2, CameraResetOp, 2, 3, "?all?"},
396    {"rotate", 2, CameraRotateOp, 5, 5, "angle angle angle"},
397    {"set", 1, CameraSetOp, 11, 11, "posX posY posZ focalPtX focalPtY focalPtZ viewUpX viewUpY viewUpZ"},
398    {"zoom", 1, CameraZoomOp, 3, 3, "zoomAmount"}
399};
400static int nCameraOps = NumCmdSpecs(cameraOps);
401
402static int
403CameraCmd(ClientData clientData, Tcl_Interp *interp, int objc,
404          Tcl_Obj *const *objv)
405{
406    Tcl_ObjCmdProc *proc;
407
408    proc = Rappture::GetOpFromObj(interp, nCameraOps, cameraOps,
409                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
410    if (proc == NULL) {
411        return TCL_ERROR;
412    }
413    return (*proc) (clientData, interp, objc, objv);
414}
415
416static int
417ColorMapAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
418              Tcl_Obj *const *objv)
419{
420    const char *name = Tcl_GetString(objv[2]);
421    int cmapc, omapc;
422    Tcl_Obj **cmapv = NULL;
423    Tcl_Obj **omapv = NULL;
424
425    if (Tcl_ListObjGetElements(interp, objv[3], &cmapc, &cmapv) != TCL_OK) {
426        return TCL_ERROR;
427    }
428    if ((cmapc % 4) != 0) {
429        Tcl_AppendResult(interp, "wrong # elements in colormap: should be ",
430                         "{ value r g b ... }", (char*)NULL);
431        return TCL_ERROR;
432    }
433
434    ColorMap *colorMap = new ColorMap(name);
435    colorMap->setNumberOfTableEntries(256);
436
437    for (int i = 0; i < cmapc; i += 4) {
438        double val[4];
439        for (int j = 0; j < 4; j++) {
440            if (Tcl_GetDoubleFromObj(interp, cmapv[i+j], &val[j]) != TCL_OK) {
441                delete colorMap;
442                return TCL_ERROR;
443            }
444            if ((val[j] < 0.0) || (val[j] > 1.0)) {
445                Tcl_AppendResult(interp, "bad colormap value \"",
446                                 Tcl_GetString(cmapv[i+j]),
447                                 "\": should be in the range [0,1]", (char*)NULL);
448                delete colorMap;
449                return TCL_ERROR;
450            }
451        }
452        ColorMap::ControlPoint cp;
453        cp.value = val[0];
454        for (int c = 0; c < 3; c++) {
455            cp.color[c] = val[c+1];
456        }
457        colorMap->addControlPoint(cp);
458    }
459
460    if (Tcl_ListObjGetElements(interp, objv[4], &omapc, &omapv) != TCL_OK) {
461        delete colorMap;
462        return TCL_ERROR;
463    }
464    if ((omapc % 2) != 0) {
465        Tcl_AppendResult(interp, "wrong # elements in opacitymap: should be ",
466                         "{ value alpha ... }", (char*)NULL);
467        delete colorMap;
468        return TCL_ERROR;
469    }
470    for (int i = 0; i < omapc; i += 2) {
471        double val[2];
472        for (int j = 0; j < 2; j++) {
473            if (Tcl_GetDoubleFromObj(interp, omapv[i+j], &val[j]) != TCL_OK) {
474                delete colorMap;
475                return TCL_ERROR;
476            }
477            if ((val[j] < 0.0) || (val[j] > 1.0)) {
478                Tcl_AppendResult(interp, "bad opacitymap value \"",
479                                 Tcl_GetString(omapv[i+j]),
480                                 "\": should be in the range [0,1]", (char*)NULL);
481                delete colorMap;
482                return TCL_ERROR;
483            }
484        }
485        ColorMap::OpacityControlPoint ocp;
486        ocp.value = val[0];
487        ocp.alpha = val[1];
488        colorMap->addOpacityControlPoint(ocp);
489    }
490
491    colorMap->build();
492    g_renderer->addColorMap(name, colorMap);
493    return TCL_OK;
494}
495
496static int
497ColorMapDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
498                 Tcl_Obj *const *objv)
499{
500    if (objc == 3) {
501        const char *name = Tcl_GetString(objv[2]);
502        g_renderer->deleteColorMap(name);
503    } else {
504        g_renderer->deleteColorMap("all");
505    }
506    return TCL_OK;
507}
508
509static Rappture::CmdSpec colorMapOps[] = {
510    { "add",    1, ColorMapAddOp,    5, 5, "colorMapName colormap alphamap"},
511    { "delete", 1, ColorMapDeleteOp, 2, 3, "?colorMapName?"}
512};
513static int nColorMapOps = NumCmdSpecs(colorMapOps);
514
515static int
516ColorMapCmd(ClientData clientData, Tcl_Interp *interp, int objc,
517            Tcl_Obj *const *objv)
518{
519    Tcl_ObjCmdProc *proc;
520
521    proc = Rappture::GetOpFromObj(interp, nColorMapOps, colorMapOps,
522                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
523    if (proc == NULL) {
524        return TCL_ERROR;
525    }
526    return (*proc) (clientData, interp, objc, objv);
527}
528
529static int
530Contour2DAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc,
531                          Tcl_Obj *const *objv)
532{
533    std::vector<double> contourList;
534
535    int clistc;
536    Tcl_Obj **clistv;
537
538    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
539        return TCL_ERROR;
540    }
541
542    for (int i = 0; i < clistc; i++) {
543        double val;
544        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
545            return TCL_ERROR;
546        }
547        contourList.push_back(val);
548    }
549
550    if (objc == 5) {
551        const char *name = Tcl_GetString(objv[4]);
552        g_renderer->addContour2D(name);
553        g_renderer->setContourList(name, contourList);
554    } else {
555        g_renderer->addContour2D("all");
556        g_renderer->setContourList("all", contourList);
557    }
558    return TCL_OK;
559}
560
561static int
562Contour2DAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc,
563                          Tcl_Obj *const *objv)
564{
565    int numContours;
566    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
567        return TCL_ERROR;
568    }
569    if (objc == 5) {
570        const char *name = Tcl_GetString(objv[4]);
571        g_renderer->addContour2D(name);
572        g_renderer->setContours(name, numContours);
573    } else {
574        g_renderer->addContour2D("all");
575        g_renderer->setContours("all", numContours);
576    }
577    return TCL_OK;
578}
579
580static Rappture::CmdSpec contour2dAddOps[] = {
581    {"contourlist", 1, Contour2DAddContourListOp, 4, 5, "contourList ?dataSetName?"},
582    {"numcontours", 1, Contour2DAddNumContoursOp, 4, 5, "numContours ?dataSetName?"}
583};
584static int nContour2dAddOps = NumCmdSpecs(contour2dAddOps);
585
586static int
587Contour2DAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
588               Tcl_Obj *const *objv)
589{
590    Tcl_ObjCmdProc *proc;
591
592    proc = Rappture::GetOpFromObj(interp, nContour2dAddOps, contour2dAddOps,
593                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
594    if (proc == NULL) {
595        return TCL_ERROR;
596    }
597    return (*proc) (clientData, interp, objc, objv);
598}
599
600static int
601Contour2DDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
602                  Tcl_Obj *const *objv)
603{
604    if (objc == 3) {
605        const char *name = Tcl_GetString(objv[2]);
606        g_renderer->deleteContour2D(name);
607    } else {
608        g_renderer->deleteContour2D("all");
609    }
610    return TCL_OK;
611}
612
613static int
614Contour2DLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
615                    Tcl_Obj *const *objv)
616{
617    bool state;
618    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
619        return TCL_ERROR;
620    }
621    if (objc == 4) {
622        const char *name = Tcl_GetString(objv[3]);
623        g_renderer->setContourLighting(name, state);
624    } else {
625        g_renderer->setContourLighting("all", state);
626    }
627    return TCL_OK;
628}
629
630static int
631Contour2DLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
632                     Tcl_Obj *const *objv)
633{
634    float color[3];
635    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
636        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
637        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
638        return TCL_ERROR;
639    }
640    if (objc == 6) {
641        const char *name = Tcl_GetString(objv[5]);
642        g_renderer->setContourEdgeColor(name, color);
643    } else {
644        g_renderer->setContourEdgeColor("all", color);
645    }
646    return TCL_OK;
647}
648
649static int
650Contour2DLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
651                     Tcl_Obj *const *objv)
652{
653    float width;
654    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
655        return TCL_ERROR;
656    }
657    if (objc == 4) {
658        const char *name = Tcl_GetString(objv[3]);
659        g_renderer->setContourEdgeWidth(name, width);
660    } else {
661        g_renderer->setContourEdgeWidth("all", width);
662    }
663    return TCL_OK;
664}
665
666static int
667Contour2DOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
668                   Tcl_Obj *const *objv)
669{
670    double opacity;
671    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
672        return TCL_ERROR;
673    }
674    if (objc == 4) {
675        const char *name = Tcl_GetString(objv[3]);
676        g_renderer->setContourOpacity(name, opacity);
677    } else {
678        g_renderer->setContourOpacity("all", opacity);
679    }
680    return TCL_OK;
681}
682
683static int
684Contour2DVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
685                   Tcl_Obj *const *objv)
686{
687    bool state;
688    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
689        return TCL_ERROR;
690    }
691    if (objc == 4) {
692        const char *name = Tcl_GetString(objv[3]);
693        g_renderer->setContourVisibility(name, state);
694    } else {
695        g_renderer->setContourVisibility("all", state);
696    }
697    return TCL_OK;
698}
699
700static Rappture::CmdSpec contour2dOps[] = {
701    {"add",       1, Contour2DAddOp, 4, 5, "oper value ?dataSetName?"},
702    {"delete",    1, Contour2DDeleteOp, 2, 3, "?dataSetName?"},
703    {"lighting",  3, Contour2DLightingOp, 3, 4, "bool ?dataSetName?"},
704    {"linecolor", 5, Contour2DLineColorOp, 5, 6, "r g b ?dataSetName?"},
705    {"linewidth", 5, Contour2DLineWidthOp, 3, 4, "width ?dataSetName?"},
706    {"opacity",   1, Contour2DOpacityOp, 3, 4, "value ?dataSetName?"},
707    {"visible",   1, Contour2DVisibleOp, 3, 4, "bool ?dataSetName?"}
708};
709static int nContour2dOps = NumCmdSpecs(contour2dOps);
710
711static int
712Contour2DCmd(ClientData clientData, Tcl_Interp *interp, int objc,
713             Tcl_Obj *const *objv)
714{
715    Tcl_ObjCmdProc *proc;
716
717    proc = Rappture::GetOpFromObj(interp, nContour2dOps, contour2dOps,
718                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
719    if (proc == NULL) {
720        return TCL_ERROR;
721    }
722    return (*proc) (clientData, interp, objc, objv);
723}
724
725static int
726DataSetAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
727             Tcl_Obj *const *objv)
728{
729    const char *name = Tcl_GetString(objv[2]);
730    const char *string = Tcl_GetString(objv[3]);
731    char c = string[0];
732    if ((c != 'd') || (strcmp(string, "data") != 0)) {
733        Tcl_AppendResult(interp, "bad dataset option \"", string,
734                         "\": should be data", (char*)NULL);
735        return TCL_ERROR;
736    }
737    string = Tcl_GetString(objv[4]);
738    c = string[0];
739    if ((c != 'f') || (strcmp(string, "follows") != 0)) {
740        Tcl_AppendResult(interp, "bad dataset option \"", string,
741                         "\": should be follows", (char*)NULL);
742        return TCL_ERROR;
743    }
744    int nbytes = 0;
745    if (Tcl_GetIntFromObj(interp, objv[5], &nbytes) != TCL_OK ||
746        nbytes < 0) {
747        return TCL_ERROR;
748    }
749    char *data = (char *)malloc(nbytes);
750#ifdef notdef
751    size_t ofs = 0;
752    ssize_t bytesRead = 0;
753    while ((bytesRead = read(g_fdIn, data + ofs, nbytes - ofs)) > 0) {
754        ofs += bytesRead;
755        if (ofs == nbytes)
756            break;
757    }
758    TRACE("bytesRead: %d", ofs);
759    if (bytesRead < 0) {
760        return TCL_ERROR;
761    }
762#else
763    size_t bytesRead = fread(data, 1, nbytes, g_fIn);
764    TRACE("bytesRead: %d '%c'", bytesRead, data[0]);
765    if (bytesRead < (size_t)nbytes) {
766        return TCL_ERROR;
767    }
768#endif
769    g_renderer->addDataSet(name);
770    g_renderer->setData(name, data, nbytes);
771    free(data);
772    return TCL_OK;
773}
774
775static int
776DataSetDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
777                Tcl_Obj *const *objv)
778{
779    if (objc == 3) {
780        const char *name = Tcl_GetString(objv[2]);
781        TRACE("Deleting dataset %s", name);
782        g_renderer->deleteDataSet(name);
783    } else {
784        g_renderer->deleteDataSet("all");
785    }
786    return TCL_OK;
787}
788
789static int
790DataSetGetValuePixelOp(ClientData clientData, Tcl_Interp *interp, int objc,
791                       Tcl_Obj *const *objv)
792{
793    const char *name = Tcl_GetString(objv[5]);
794    int x, y;
795    if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK ||
796        Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
797        return TCL_ERROR;
798    }
799    double value = g_renderer->getDataValueAtPixel(name, x, y);
800    char buf[128];
801    snprintf(buf, sizeof(buf), "nv>dataset value pixel %d %d %.12e", x, y, value);
802    ssize_t bytesWritten;
803    size_t len = strlen(buf);
804    size_t ofs = 0;
805    while ((bytesWritten = write(g_fdOut, buf + ofs, len - ofs)) > 0) {
806        ofs += bytesWritten;
807        if (ofs == len)
808            break;
809    }
810    if (bytesWritten < 0) {
811        return TCL_ERROR;
812    }
813    return TCL_OK;
814}
815
816static int
817DataSetGetValueWorldOp(ClientData clientData, Tcl_Interp *interp, int objc,
818                       Tcl_Obj *const *objv)
819{
820    const char *name = Tcl_GetString(objv[6]);
821    double x, y, z;
822    if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK ||
823        Tcl_GetDoubleFromObj(interp, objv[4], &y) != TCL_OK ||
824        Tcl_GetDoubleFromObj(interp, objv[5], &z) != TCL_OK) {
825        return TCL_ERROR;
826    }
827    double value = g_renderer->getDataValue(name, x, y, z);
828    char buf[128];
829    snprintf(buf, sizeof(buf), "nv>dataset value world %.12e %.12e %.12e %.12e", x, y, z, value);
830    ssize_t bytesWritten;
831    size_t len = strlen(buf);
832    size_t ofs = 0;
833    while ((bytesWritten = write(g_fdOut, buf + ofs, len - ofs)) > 0) {
834        ofs += bytesWritten;
835        if (ofs == len)
836            break;
837    }
838    if (bytesWritten < 0) {
839        return TCL_ERROR;
840    }
841    return TCL_OK;
842}
843
844static Rappture::CmdSpec dataSetGetValueOps[] = {
845    {"pixel", 1, DataSetGetValuePixelOp, 6, 6, "x y dataSetName"},
846    {"world", 1, DataSetGetValueWorldOp, 7, 7, "x y z dataSetName"}
847};
848static int nDataSetGetValueOps = NumCmdSpecs(dataSetGetValueOps);
849
850static int
851DataSetGetValueOp(ClientData clientData, Tcl_Interp *interp, int objc,
852                  Tcl_Obj *const *objv)
853{
854    Tcl_ObjCmdProc *proc;
855
856    proc = Rappture::GetOpFromObj(interp, nDataSetGetValueOps, dataSetGetValueOps,
857                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
858    if (proc == NULL) {
859        return TCL_ERROR;
860    }
861    return (*proc) (clientData, interp, objc, objv);
862}
863
864static int
865DataSetOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
866                 Tcl_Obj *const *objv)
867{
868    double opacity;
869    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
870        return TCL_ERROR;
871    }
872    if (objc == 4) {
873        const char *name = Tcl_GetString(objv[3]);
874        g_renderer->setOpacity(name, opacity);
875    } else {
876        g_renderer->setOpacity("all", opacity);
877    }
878    return TCL_OK;
879}
880
881static int
882DataSetMapRangeOp(ClientData clientData, Tcl_Interp *interp, int objc,
883                  Tcl_Obj *const *objv)
884{
885    const char *value = Tcl_GetString(objv[2]);
886    if (strcmp(value, "all") == 0) {
887        g_renderer->setUseCumulativeDataRange(true);
888    } else if (strcmp(value, "visible") == 0) {
889        g_renderer->setUseCumulativeDataRange(true, true);
890    } else if (strcmp(value, "separate") == 0) {
891        g_renderer->setUseCumulativeDataRange(false);
892    } else {
893        return TCL_ERROR;
894    }
895    return TCL_OK;
896}
897
898static int
899DataSetVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
900                 Tcl_Obj *const *objv)
901{
902    bool state;
903    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
904        return TCL_ERROR;
905    }
906    if (objc == 4) {
907        const char *name = Tcl_GetString(objv[3]);
908        g_renderer->setVisibility(name, state);
909    } else {
910        g_renderer->setVisibility("all", state);
911    }
912    return TCL_OK;
913}
914
915static Rappture::CmdSpec dataSetOps[] = {
916    {"add",      1, DataSetAddOp, 6, 6, "name data follows nBytes"},
917    {"delete",   1, DataSetDeleteOp, 2, 3, "?name?"},
918    {"getvalue", 1, DataSetGetValueOp, 6, 7, "oper x y ?z? name"},
919    {"maprange", 1, DataSetMapRangeOp, 3, 3, "value"},
920    {"opacity",  1, DataSetOpacityOp, 3, 4, "value ?name?"},
921    {"visible",  1, DataSetVisibleOp, 3, 4, "bool ?name?"}
922};
923static int nDataSetOps = NumCmdSpecs(dataSetOps);
924
925static int
926DataSetCmd(ClientData clientData, Tcl_Interp *interp, int objc,
927           Tcl_Obj *const *objv)
928{
929    Tcl_ObjCmdProc *proc;
930
931    proc = Rappture::GetOpFromObj(interp, nDataSetOps, dataSetOps,
932                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
933    if (proc == NULL) {
934        return TCL_ERROR;
935    }
936    return (*proc) (clientData, interp, objc, objv);
937}
938
939static int
940GlyphsAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
941            Tcl_Obj *const *objv)
942{
943    Glyphs::GlyphShape shape;
944
945    const char *shapeOpt = Tcl_GetString(objv[2]);
946    if (shapeOpt[0] == 'a' && strcmp(shapeOpt, "arrow") == 0) {
947        shape = Glyphs::ARROW;
948    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cone") == 0) {
949        shape = Glyphs::CONE;
950    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cube") == 0) {
951        shape = Glyphs::CUBE;
952    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cylinder") == 0) {
953        shape = Glyphs::CYLINDER;
954    } else if (shapeOpt[0] == 'd' && strcmp(shapeOpt, "dodecahedron") == 0) {
955        shape = Glyphs::DODECAHEDRON;
956    } else if (shapeOpt[0] == 'i' && strcmp(shapeOpt, "icosahedron") == 0) {
957        shape = Glyphs::ICOSAHEDRON;
958    } else if (shapeOpt[0] == 'o' && strcmp(shapeOpt, "octahedron") == 0) {
959        shape = Glyphs::OCTAHEDRON;
960    } else if (shapeOpt[0] == 's' && strcmp(shapeOpt, "sphere") == 0) {
961        shape = Glyphs::SPHERE;
962    } else if (shapeOpt[0] == 't' && strcmp(shapeOpt, "tetrahedron") == 0) {
963        shape = Glyphs::TETRAHEDRON;
964    } else {
965        Tcl_AppendResult(interp, "bad shape option \"", shapeOpt,
966                         "\": should be one of: 'arrow', 'cone', 'cube', 'cylinder', 'dodecahedron', 'icosahedron', 'octahedron', 'sphere', 'tetrahedron'", (char*)NULL);
967        return TCL_ERROR;
968    }
969
970    if (objc == 4) {
971        const char *name = Tcl_GetString(objv[3]);
972        g_renderer->addGlyphs(name);
973        g_renderer->setGlyphsShape(name, shape);
974    } else {
975        g_renderer->addGlyphs("all");
976        g_renderer->setGlyphsShape("all", shape);
977    }
978    return TCL_OK;
979}
980
981static int
982GlyphsColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
983                 Tcl_Obj *const *objv)
984{
985    const char *colorMapName = Tcl_GetString(objv[2]);
986    if (objc == 4) {
987        const char *dataSetName = Tcl_GetString(objv[3]);
988        g_renderer->setGlyphsColorMap(dataSetName, colorMapName);
989    } else {
990        g_renderer->setGlyphsColorMap("all", colorMapName);
991    }
992    return TCL_OK;
993}
994
995static int
996GlyphsDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
997               Tcl_Obj *const *objv)
998{
999    if (objc == 3) {
1000        const char *name = Tcl_GetString(objv[2]);
1001        g_renderer->deleteGlyphs(name);
1002    } else {
1003        g_renderer->deleteGlyphs("all");
1004    }
1005    return TCL_OK;
1006}
1007
1008static int
1009GlyphsLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
1010                 Tcl_Obj *const *objv)
1011{
1012    bool state;
1013    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1014        return TCL_ERROR;
1015    }
1016    if (objc == 4) {
1017        const char *name = Tcl_GetString(objv[3]);
1018        g_renderer->setGlyphsLighting(name, state);
1019    } else {
1020        g_renderer->setGlyphsLighting("all", state);
1021    }
1022    return TCL_OK;
1023}
1024
1025static int
1026GlyphsOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
1027                Tcl_Obj *const *objv)
1028{
1029    double opacity;
1030    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
1031        return TCL_ERROR;
1032    }
1033    if (objc == 4) {
1034        const char *name = Tcl_GetString(objv[3]);
1035        g_renderer->setGlyphsOpacity(name, opacity);
1036    } else {
1037        g_renderer->setGlyphsOpacity("all", opacity);
1038    }
1039    return TCL_OK;
1040}
1041
1042static int
1043GlyphsScaleOp(ClientData clientData, Tcl_Interp *interp, int objc,
1044              Tcl_Obj *const *objv)
1045{
1046    double scale;
1047    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
1048        return TCL_ERROR;
1049    }
1050    if (objc == 4) {
1051        const char *name = Tcl_GetString(objv[3]);
1052        g_renderer->setGlyphsScaleFactor(name, scale);
1053    } else {
1054        g_renderer->setGlyphsScaleFactor("all", scale);
1055    }
1056    return TCL_OK;
1057}
1058
1059static int
1060GlyphsShapeOp(ClientData clientData, Tcl_Interp *interp, int objc,
1061              Tcl_Obj *const *objv)
1062{
1063    Glyphs::GlyphShape shape;
1064
1065    const char *shapeOpt = Tcl_GetString(objv[2]);
1066    if (shapeOpt[0] == 'a' && strcmp(shapeOpt, "arrow") == 0) {
1067        shape = Glyphs::ARROW;
1068    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cone") == 0) {
1069        shape = Glyphs::CONE;
1070    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cube") == 0) {
1071        shape = Glyphs::CUBE;
1072    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cylinder") == 0) {
1073        shape = Glyphs::CYLINDER;
1074    } else if (shapeOpt[0] == 'd' && strcmp(shapeOpt, "dodecahedron") == 0) {
1075        shape = Glyphs::DODECAHEDRON;
1076    } else if (shapeOpt[0] == 'i' && strcmp(shapeOpt, "icosahedron") == 0) {
1077        shape = Glyphs::ICOSAHEDRON;
1078    } else if (shapeOpt[0] == 'o' && strcmp(shapeOpt, "octahedron") == 0) {
1079        shape = Glyphs::OCTAHEDRON;
1080    } else if (shapeOpt[0] == 's' && strcmp(shapeOpt, "sphere") == 0) {
1081        shape = Glyphs::SPHERE;
1082    } else if (shapeOpt[0] == 't' && strcmp(shapeOpt, "tetrahedron") == 0) {
1083        shape = Glyphs::TETRAHEDRON;
1084    } else {
1085        Tcl_AppendResult(interp, "bad shape option \"", shapeOpt,
1086                         "\": should be one of: 'arrow', 'cone', 'cube', 'cylinder', 'dodecahedron', 'icosahedron', 'octahedron', 'sphere', 'tetrahedron'", (char*)NULL);
1087        return TCL_ERROR;
1088    }
1089
1090    if (objc == 4) {
1091        const char *name = Tcl_GetString(objv[3]);
1092        g_renderer->setGlyphsShape(name, shape);
1093    } else {
1094        g_renderer->setGlyphsShape("all", shape);
1095    }
1096    return TCL_OK;
1097}
1098
1099static int
1100GlyphsVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
1101                Tcl_Obj *const *objv)
1102{
1103    bool state;
1104    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1105        return TCL_ERROR;
1106    }
1107    if (objc == 4) {
1108        const char *name = Tcl_GetString(objv[3]);
1109        g_renderer->setGlyphsVisibility(name, state);
1110    } else {
1111        g_renderer->setGlyphsVisibility("all", state);
1112    }
1113    return TCL_OK;
1114}
1115
1116static Rappture::CmdSpec glyphsOps[] = {
1117    {"add",      1, GlyphsAddOp, 3, 4, "shape ?dataSetNme?"},
1118    {"colormap", 1, GlyphsColorMapOp, 3, 4, "colorMapName ?dataSetNme?"},
1119    {"delete",   1, GlyphsDeleteOp, 2, 3, "?dataSetName?"},
1120    {"lighting", 1, GlyphsLightingOp, 3, 4, "bool ?dataSetName?"},
1121    {"opacity",  1, GlyphsOpacityOp, 3, 4, "value ?dataSetName?"},
1122    {"scale",    2, GlyphsScaleOp, 3, 4, "scaleFactor ?dataSetName?"},
1123    {"shape",    2, GlyphsShapeOp, 3, 4, "shapeVal ?dataSetName?"},
1124    {"visible",  1, GlyphsVisibleOp, 3, 4, "bool ?dataSetName?"}
1125};
1126static int nGlyphsOps = NumCmdSpecs(glyphsOps);
1127
1128static int
1129GlyphsCmd(ClientData clientData, Tcl_Interp *interp, int objc,
1130          Tcl_Obj *const *objv)
1131{
1132    Tcl_ObjCmdProc *proc;
1133
1134    proc = Rappture::GetOpFromObj(interp, nGlyphsOps, glyphsOps,
1135                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
1136    if (proc == NULL) {
1137        return TCL_ERROR;
1138    }
1139    return (*proc) (clientData, interp, objc, objv);
1140}
1141
1142static int
1143HeightMapAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc,
1144                          Tcl_Obj *const *objv)
1145{
1146    std::vector<double> contourList;
1147
1148    int clistc;
1149    Tcl_Obj **clistv;
1150
1151    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
1152        return TCL_ERROR;
1153    }
1154
1155    for (int i = 0; i < clistc; i++) {
1156        double val;
1157        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
1158            return TCL_ERROR;
1159        }
1160        contourList.push_back(val);
1161    }
1162
1163    if (objc == 5) {
1164        const char *name = Tcl_GetString(objv[4]);
1165        g_renderer->addHeightMap(name);
1166        g_renderer->setHeightMapContourList(name, contourList);
1167    } else {
1168        g_renderer->addHeightMap("all");
1169        g_renderer->setHeightMapContourList("all", contourList);
1170    }
1171    return TCL_OK;
1172}
1173
1174static int
1175HeightMapAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc,
1176                          Tcl_Obj *const *objv)
1177{
1178    int numContours;
1179    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
1180        return TCL_ERROR;
1181    }
1182    if (objc == 5) {
1183        const char *name = Tcl_GetString(objv[4]);
1184        g_renderer->addHeightMap(name);
1185        g_renderer->setHeightMapContours(name, numContours);
1186    } else {
1187        g_renderer->addHeightMap("all");
1188        g_renderer->setHeightMapContours("all", numContours);
1189    }
1190    return TCL_OK;
1191}
1192
1193static Rappture::CmdSpec heightmapAddOps[] = {
1194    {"contourlist", 1, HeightMapAddContourListOp, 4, 5, "contourList ?dataSetName?"},
1195    {"numcontours", 1, HeightMapAddNumContoursOp, 4, 5, "numContours ?dataSetName?"}
1196};
1197static int nHeightmapAddOps = NumCmdSpecs(heightmapAddOps);
1198
1199static int
1200HeightMapAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
1201               Tcl_Obj *const *objv)
1202{
1203    Tcl_ObjCmdProc *proc;
1204
1205    proc = Rappture::GetOpFromObj(interp, nHeightmapAddOps, heightmapAddOps,
1206                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
1207    if (proc == NULL) {
1208        return TCL_ERROR;
1209    }
1210    return (*proc) (clientData, interp, objc, objv);
1211}
1212
1213static int
1214HeightMapColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
1215                    Tcl_Obj *const *objv)
1216{
1217    const char *colorMapName = Tcl_GetString(objv[2]);
1218    if (objc == 4) {
1219        const char *dataSetName = Tcl_GetString(objv[3]);
1220        g_renderer->setHeightMapColorMap(dataSetName, colorMapName);
1221    } else {
1222        g_renderer->setHeightMapColorMap("all", colorMapName);
1223    }
1224    return TCL_OK;
1225}
1226
1227static int
1228HeightMapContourLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
1229                            Tcl_Obj *const *objv)
1230{
1231    float color[3];
1232    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
1233        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
1234        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
1235        return TCL_ERROR;
1236    }
1237    if (objc == 6) {
1238        const char *name = Tcl_GetString(objv[5]);
1239        g_renderer->setHeightMapContourEdgeColor(name, color);
1240    } else {
1241        g_renderer->setHeightMapContourEdgeColor("all", color);
1242    }
1243    return TCL_OK;
1244}
1245
1246static int
1247HeightMapContourLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
1248                            Tcl_Obj *const *objv)
1249{
1250    float width;
1251    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
1252        return TCL_ERROR;
1253    }
1254    if (objc == 4) {
1255        const char *name = Tcl_GetString(objv[3]);
1256        g_renderer->setHeightMapContourEdgeWidth(name, width);
1257    } else {
1258        g_renderer->setHeightMapContourEdgeWidth("all", width);
1259    }
1260    return TCL_OK;
1261}
1262
1263static int
1264HeightMapContourVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
1265                          Tcl_Obj *const *objv)
1266{
1267    bool state;
1268    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1269        return TCL_ERROR;
1270    }
1271    if (objc == 4) {
1272        const char *name = Tcl_GetString(objv[3]);
1273        g_renderer->setHeightMapContourVisibility(name, state);
1274    } else {
1275        g_renderer->setHeightMapContourVisibility("all", state);
1276    }
1277    return TCL_OK;
1278}
1279
1280static int
1281HeightMapDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
1282                  Tcl_Obj *const *objv)
1283{
1284    if (objc == 3) {
1285        const char *name = Tcl_GetString(objv[2]);
1286        g_renderer->deleteHeightMap(name);
1287    } else {
1288        g_renderer->deleteHeightMap("all");
1289    }
1290    return TCL_OK;
1291}
1292
1293static int
1294HeightMapEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc,
1295                          Tcl_Obj *const *objv)
1296{
1297    bool state;
1298    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1299        return TCL_ERROR;
1300    }
1301    if (objc == 4) {
1302        const char *name = Tcl_GetString(objv[3]);
1303        g_renderer->setHeightMapEdgeVisibility(name, state);
1304    } else {
1305        g_renderer->setHeightMapEdgeVisibility("all", state);
1306    }
1307    return TCL_OK;
1308}
1309
1310static int
1311HeightMapHeightScaleOp(ClientData clientData, Tcl_Interp *interp, int objc,
1312                       Tcl_Obj *const *objv)
1313{
1314    double scale;
1315    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
1316        return TCL_ERROR;
1317    }
1318    if (objc == 4) {
1319        const char *name = Tcl_GetString(objv[3]);
1320        g_renderer->setHeightMapHeightScale(name, scale);
1321    } else {
1322        g_renderer->setHeightMapHeightScale("all", scale);
1323    }
1324    return TCL_OK;
1325}
1326
1327static int
1328HeightMapLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
1329                    Tcl_Obj *const *objv)
1330{
1331    bool state;
1332    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1333        return TCL_ERROR;
1334    }
1335    if (objc == 4) {
1336        const char *name = Tcl_GetString(objv[3]);
1337        g_renderer->setHeightMapLighting(name, state);
1338    } else {
1339        g_renderer->setHeightMapLighting("all", state);
1340    }
1341    return TCL_OK;
1342}
1343
1344static int
1345HeightMapLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
1346                     Tcl_Obj *const *objv)
1347{
1348    float color[3];
1349    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
1350        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
1351        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
1352        return TCL_ERROR;
1353    }
1354    if (objc == 6) {
1355        const char *name = Tcl_GetString(objv[5]);
1356        g_renderer->setHeightMapEdgeColor(name, color);
1357    } else {
1358        g_renderer->setHeightMapEdgeColor("all", color);
1359    }
1360    return TCL_OK;
1361}
1362
1363static int
1364HeightMapLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
1365                     Tcl_Obj *const *objv)
1366{
1367    float width;
1368    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
1369        return TCL_ERROR;
1370    }
1371    if (objc == 4) {
1372        const char *name = Tcl_GetString(objv[3]);
1373        g_renderer->setHeightMapEdgeWidth(name, width);
1374    } else {
1375        g_renderer->setHeightMapEdgeWidth("all", width);
1376    }
1377    return TCL_OK;
1378}
1379
1380static int
1381HeightMapOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
1382                   Tcl_Obj *const *objv)
1383{
1384    double opacity;
1385    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
1386        return TCL_ERROR;
1387    }
1388    if (objc == 4) {
1389        const char *name = Tcl_GetString(objv[3]);
1390        g_renderer->setHeightMapOpacity(name, opacity);
1391    } else {
1392        g_renderer->setHeightMapOpacity("all", opacity);
1393    }
1394    return TCL_OK;
1395}
1396
1397static int
1398HeightMapVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
1399                   Tcl_Obj *const *objv)
1400{
1401    bool state;
1402    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1403        return TCL_ERROR;
1404    }
1405    if (objc == 4) {
1406        const char *name = Tcl_GetString(objv[3]);
1407        g_renderer->setHeightMapVisibility(name, state);
1408    } else {
1409        g_renderer->setHeightMapVisibility("all", state);
1410    }
1411    return TCL_OK;
1412}
1413
1414static int
1415HeightMapVolumeSliceOp(ClientData clientData, Tcl_Interp *interp, int objc,
1416                       Tcl_Obj *const *objv)
1417{
1418    double ratio;
1419    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
1420        return TCL_ERROR;
1421    }
1422    const char *string = Tcl_GetString(objv[2]);
1423    char c = string[0];
1424    HeightMap::Axis axis;
1425    if ((c == 'x') && (strcmp(string, "x") == 0)) {
1426        axis = HeightMap::X_AXIS;
1427    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
1428        axis = HeightMap::Y_AXIS;
1429    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
1430        axis = HeightMap::Z_AXIS;
1431    } else {
1432        Tcl_AppendResult(interp, "bad axis option \"", string,
1433                         "\": should be axisName ratio", (char*)NULL);
1434        return TCL_ERROR;
1435    }
1436    if (objc == 5) {
1437        const char *name = Tcl_GetString(objv[4]);
1438        g_renderer->setHeightMapVolumeSlice(name, axis, ratio);
1439    } else {
1440        g_renderer->setHeightMapVolumeSlice("all", axis, ratio);
1441    }
1442    return TCL_OK;
1443}
1444
1445static Rappture::CmdSpec heightmapOps[] = {
1446    {"add",          1, HeightMapAddOp, 4, 5, "oper value ?dataSetName?"},
1447    {"colormap",     1, HeightMapColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
1448    {"delete",       1, HeightMapDeleteOp, 2, 3, "?dataSetName?"},
1449    {"edges",        1, HeightMapEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
1450    {"heightscale",  1, HeightMapHeightScaleOp, 3, 4, "value ?dataSetName?"},
1451    {"isolinecolor", 8, HeightMapContourLineColorOp, 5, 6, "r g b ?dataSetName?"},
1452    {"isolines",     8, HeightMapContourVisibleOp, 3, 4, "bool ?dataSetName?"},
1453    {"isolinewidth", 8, HeightMapContourLineWidthOp, 3, 4, "width ?dataSetName?"},
1454    {"lighting",     3, HeightMapLightingOp, 3, 4, "bool ?dataSetName?"},
1455    {"linecolor",    5, HeightMapLineColorOp, 5, 6, "r g b ?dataSetName?"},
1456    {"linewidth",    5, HeightMapLineWidthOp, 3, 4, "width ?dataSetName?"},
1457    {"opacity",      1, HeightMapOpacityOp, 3, 4, "value ?dataSetName?"},
1458    {"visible",      2, HeightMapVisibleOp, 3, 4, "bool ?dataSetName?"},
1459    {"volumeslice",  2, HeightMapVolumeSliceOp, 4, 5, "axis ratio ?dataSetName?"}
1460};
1461static int nHeightmapOps = NumCmdSpecs(heightmapOps);
1462
1463static int
1464HeightMapCmd(ClientData clientData, Tcl_Interp *interp, int objc,
1465             Tcl_Obj *const *objv)
1466{
1467    Tcl_ObjCmdProc *proc;
1468
1469    proc = Rappture::GetOpFromObj(interp, nHeightmapOps, heightmapOps,
1470                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
1471    if (proc == NULL) {
1472        return TCL_ERROR;
1473    }
1474    return (*proc) (clientData, interp, objc, objv);
1475}
1476
1477static int
1478LegendCmd(ClientData clientData, Tcl_Interp *interp, int objc,
1479          Tcl_Obj *const *objv)
1480{
1481    if (objc < 4) {
1482        Tcl_AppendResult(interp, "wrong # args: should be \"",
1483                Tcl_GetString(objv[0]), " colormapName title width height ?dataSetName?\"", (char*)NULL);
1484        return TCL_ERROR;
1485    }
1486    const char *name = Tcl_GetString(objv[1]);
1487    const char *title = Tcl_GetString(objv[2]);
1488    int width, height;
1489
1490    if (Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK ||
1491        Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK) {
1492        return TCL_ERROR;
1493    }
1494
1495    vtkSmartPointer<vtkUnsignedCharArray> imgData =
1496        vtkSmartPointer<vtkUnsignedCharArray>::New();
1497
1498    if (objc == 6) {
1499        const char *dataSetName = Tcl_GetString(objv[5]);
1500        if (!g_renderer->renderColorMap(name, dataSetName, title, width, height, imgData)) {
1501            Tcl_AppendResult(interp, "Color map \"",
1502                             name, "\" was not found", (char*)NULL);
1503            return TCL_ERROR;
1504        }
1505    } else {
1506        if (!g_renderer->renderColorMap(name, "all", title, width, height, imgData)) {
1507            Tcl_AppendResult(interp, "Color map \"",
1508                             name, "\" was not found", (char*)NULL);
1509            return TCL_ERROR;
1510        }
1511    }
1512
1513#ifdef DEBUG
1514    writeTGAFile("/tmp/legend.tga", imgData->GetPointer(0), width, height,
1515                 TARGA_BYTES_PER_PIXEL);
1516#else
1517    char cmd[256];
1518    snprintf(cmd, sizeof(cmd), "nv>legend %s", name);
1519#ifdef RENDER_TARGA
1520    writeTGA(g_fdOut, cmd, imgData->GetPointer(0), width, height,
1521                 TARGA_BYTES_PER_PIXEL);
1522#else
1523    writePPM(g_fdOut, cmd, imgData->GetPointer(0), width, height);
1524#endif
1525#endif
1526
1527    return TCL_OK;
1528}
1529
1530static int
1531PseudoColorAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
1532               Tcl_Obj *const *objv)
1533{
1534    if (objc == 3) {
1535        const char *name = Tcl_GetString(objv[2]);
1536        g_renderer->addPseudoColor(name);
1537    } else {
1538        g_renderer->addPseudoColor("all");
1539    }
1540    return TCL_OK;
1541}
1542
1543static int
1544PseudoColorColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
1545                      Tcl_Obj *const *objv)
1546{
1547    const char *colorMapName = Tcl_GetString(objv[2]);
1548    if (objc == 4) {
1549        const char *dataSetName = Tcl_GetString(objv[3]);
1550        g_renderer->setPseudoColorColorMap(dataSetName, colorMapName);
1551    } else {
1552        g_renderer->setPseudoColorColorMap("all", colorMapName);
1553    }
1554    return TCL_OK;
1555}
1556
1557static int
1558PseudoColorDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
1559                  Tcl_Obj *const *objv)
1560{
1561    if (objc == 3) {
1562        const char *name = Tcl_GetString(objv[2]);
1563        g_renderer->deletePseudoColor(name);
1564    } else {
1565        g_renderer->deletePseudoColor("all");
1566    }
1567    return TCL_OK;
1568}
1569
1570static int
1571PseudoColorEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc,
1572                            Tcl_Obj *const *objv)
1573{
1574    bool state;
1575    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1576        return TCL_ERROR;
1577    }
1578    if (objc == 4) {
1579        const char *name = Tcl_GetString(objv[3]);
1580        g_renderer->setPseudoColorEdgeVisibility(name, state);
1581    } else {
1582        g_renderer->setPseudoColorEdgeVisibility("all", state);
1583    }
1584    return TCL_OK;
1585}
1586
1587static int
1588PseudoColorLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
1589                      Tcl_Obj *const *objv)
1590{
1591    bool state;
1592    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1593        return TCL_ERROR;
1594    }
1595    if (objc == 4) {
1596        const char *name = Tcl_GetString(objv[3]);
1597        g_renderer->setPseudoColorLighting(name, state);
1598    } else {
1599        g_renderer->setPseudoColorLighting("all", state);
1600    }
1601    return TCL_OK;
1602}
1603
1604static int
1605PseudoColorLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
1606                       Tcl_Obj *const *objv)
1607{
1608    float color[3];
1609    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
1610        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
1611        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
1612        return TCL_ERROR;
1613    }
1614    if (objc == 6) {
1615        const char *name = Tcl_GetString(objv[5]);
1616        g_renderer->setPseudoColorEdgeColor(name, color);
1617    } else {
1618        g_renderer->setPseudoColorEdgeColor("all", color);
1619    }
1620    return TCL_OK;
1621}
1622
1623static int
1624PseudoColorLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
1625                       Tcl_Obj *const *objv)
1626{
1627    float width;
1628    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
1629        return TCL_ERROR;
1630    }
1631    if (objc == 4) {
1632        const char *name = Tcl_GetString(objv[3]);
1633        g_renderer->setPseudoColorEdgeWidth(name, width);
1634    } else {
1635        g_renderer->setPseudoColorEdgeWidth("all", width);
1636    }
1637    return TCL_OK;
1638}
1639
1640static int
1641PseudoColorOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
1642                     Tcl_Obj *const *objv)
1643{
1644    double opacity;
1645    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
1646        return TCL_ERROR;
1647    }
1648    if (objc == 4) {
1649        const char *name = Tcl_GetString(objv[3]);
1650        g_renderer->setPseudoColorOpacity(name, opacity);
1651    } else {
1652        g_renderer->setPseudoColorOpacity("all", opacity);
1653    }
1654    return TCL_OK;
1655}
1656
1657static int
1658PseudoColorVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
1659                     Tcl_Obj *const *objv)
1660{
1661    bool state;
1662    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1663        return TCL_ERROR;
1664    }
1665    if (objc == 4) {
1666        const char *name = Tcl_GetString(objv[3]);
1667        g_renderer->setPseudoColorVisibility(name, state);
1668    } else {
1669        g_renderer->setPseudoColorVisibility("all", state);
1670    }
1671    return TCL_OK;
1672}
1673
1674static Rappture::CmdSpec pseudoColorOps[] = {
1675    {"add",       1, PseudoColorAddOp, 2, 3, "?dataSetName?"},
1676    {"colormap",  1, PseudoColorColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
1677    {"delete",    1, PseudoColorDeleteOp, 2, 3, "?dataSetName?"},
1678    {"edges",     1, PseudoColorEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
1679    {"lighting",  3, PseudoColorLightingOp, 3, 4, "bool ?dataSetName?"},
1680    {"linecolor", 5, PseudoColorLineColorOp, 5, 6, "r g b ?dataSetName?"},
1681    {"linewidth", 5, PseudoColorLineWidthOp, 3, 4, "width ?dataSetName?"},
1682    {"opacity",   1, PseudoColorOpacityOp, 3, 4, "value ?dataSetName?"},
1683    {"visible",   1, PseudoColorVisibleOp, 3, 4, "bool ?dataSetName?"}
1684};
1685static int nPseudoColorOps = NumCmdSpecs(pseudoColorOps);
1686
1687static int
1688PseudoColorCmd(ClientData clientData, Tcl_Interp *interp, int objc,
1689               Tcl_Obj *const *objv)
1690{
1691    Tcl_ObjCmdProc *proc;
1692
1693    proc = Rappture::GetOpFromObj(interp, nPseudoColorOps, pseudoColorOps,
1694                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
1695    if (proc == NULL) {
1696        return TCL_ERROR;
1697    }
1698    return (*proc) (clientData, interp, objc, objv);
1699}
1700
1701static int
1702PolyDataAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
1703              Tcl_Obj *const *objv)
1704{
1705    if (objc == 3) {
1706        const char *name = Tcl_GetString(objv[2]);
1707        g_renderer->addPolyData(name);
1708    } else {
1709        g_renderer->addPolyData("all");
1710    }
1711    return TCL_OK;
1712}
1713
1714static int
1715PolyDataDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
1716                 Tcl_Obj *const *objv)
1717{
1718    if (objc == 3) {
1719        const char *name = Tcl_GetString(objv[2]);
1720        g_renderer->deletePolyData(name);
1721    } else {
1722        g_renderer->deletePolyData("all");
1723    }
1724    return TCL_OK;
1725}
1726
1727static int
1728PolyDataColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
1729                Tcl_Obj *const *objv)
1730{
1731    float color[3];
1732    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
1733        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
1734        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
1735        return TCL_ERROR;
1736    }
1737    if (objc == 6) {
1738        const char *name = Tcl_GetString(objv[5]);
1739        g_renderer->setPolyDataColor(name, color);
1740    } else {
1741        g_renderer->setPolyDataColor("all", color);
1742    }
1743    return TCL_OK;
1744}
1745
1746static int
1747PolyDataEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc,
1748                         Tcl_Obj *const *objv)
1749{
1750    bool state;
1751    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1752        return TCL_ERROR;
1753    }
1754    if (objc == 4) {
1755        const char *name = Tcl_GetString(objv[3]);
1756        g_renderer->setPolyDataEdgeVisibility(name, state);
1757    } else {
1758        g_renderer->setPolyDataEdgeVisibility("all", state);
1759    }
1760    return TCL_OK;
1761}
1762
1763static int
1764PolyDataLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
1765                   Tcl_Obj *const *objv)
1766{
1767    bool state;
1768    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1769        return TCL_ERROR;
1770    }
1771    if (objc == 4) {
1772        const char *name = Tcl_GetString(objv[3]);
1773        g_renderer->setPolyDataLighting(name, state);
1774    } else {
1775        g_renderer->setPolyDataLighting("all", state);
1776    }
1777    return TCL_OK;
1778}
1779
1780static int
1781PolyDataLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
1782                    Tcl_Obj *const *objv)
1783{
1784    float color[3];
1785    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
1786        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
1787        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
1788        return TCL_ERROR;
1789    }
1790    if (objc == 6) {
1791        const char *name = Tcl_GetString(objv[5]);
1792        g_renderer->setPolyDataEdgeColor(name, color);
1793    } else {
1794        g_renderer->setPolyDataEdgeColor("all", color);
1795    }
1796    return TCL_OK;
1797}
1798
1799static int
1800PolyDataLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
1801                    Tcl_Obj *const *objv)
1802{
1803    float width;
1804    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
1805        return TCL_ERROR;
1806    }
1807    if (objc == 4) {
1808        const char *name = Tcl_GetString(objv[3]);
1809        g_renderer->setPolyDataEdgeWidth(name, width);
1810    } else {
1811        g_renderer->setPolyDataEdgeWidth("all", width);
1812    }
1813    return TCL_OK;
1814}
1815
1816static int
1817PolyDataOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
1818                  Tcl_Obj *const *objv)
1819{
1820    double opacity;
1821    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
1822        return TCL_ERROR;
1823    }
1824    if (objc == 4) {
1825        const char *name = Tcl_GetString(objv[3]);
1826        g_renderer->setPolyDataOpacity(name, opacity);
1827    } else {
1828        g_renderer->setPolyDataOpacity("all", opacity);
1829    }
1830    return TCL_OK;
1831}
1832
1833static int
1834PolyDataVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
1835                  Tcl_Obj *const *objv)
1836{
1837    bool state;
1838    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1839        return TCL_ERROR;
1840    }
1841    if (objc == 4) {
1842        const char *name = Tcl_GetString(objv[3]);
1843        g_renderer->setPolyDataVisibility(name, state);
1844    } else {
1845        g_renderer->setPolyDataVisibility("all", state);
1846    }
1847    return TCL_OK;
1848}
1849
1850static int
1851PolyDataWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc,
1852                    Tcl_Obj *const *objv)
1853{
1854    bool state;
1855    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1856        return TCL_ERROR;
1857    }
1858    if (objc == 4) {
1859        const char *name = Tcl_GetString(objv[3]);
1860        g_renderer->setPolyDataWireframe(name, state);
1861    } else {
1862        g_renderer->setPolyDataWireframe("all", state);
1863    }
1864    return TCL_OK;
1865}
1866
1867static Rappture::CmdSpec polyDataOps[] = {
1868    {"add",       1, PolyDataAddOp, 2, 3, "?dataSetName?"},
1869    {"color",     1, PolyDataColorOp, 5, 6, "r g b ?dataSetName?"},
1870    {"delete",    1, PolyDataDeleteOp, 2, 3, "?dataSetName?"},
1871    {"edges",     1, PolyDataEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
1872    {"lighting",  3, PolyDataLightingOp, 3, 4, "bool ?dataSetName?"},
1873    {"linecolor", 5, PolyDataLineColorOp, 5, 6, "r g b ?dataSetName?"},
1874    {"linewidth", 5, PolyDataLineWidthOp, 3, 4, "width ?dataSetName?"},
1875    {"opacity",   1, PolyDataOpacityOp, 3, 4, "value ?dataSetName?"},
1876    {"visible",   1, PolyDataVisibleOp, 3, 4, "bool ?dataSetName?"},
1877    {"wireframe", 1, PolyDataWireframeOp, 3, 4, "bool ?dataSetName?"}
1878};
1879static int nPolyDataOps = NumCmdSpecs(polyDataOps);
1880
1881static int
1882PolyDataCmd(ClientData clientData, Tcl_Interp *interp, int objc,
1883            Tcl_Obj *const *objv)
1884{
1885    Tcl_ObjCmdProc *proc;
1886
1887    proc = Rappture::GetOpFromObj(interp, nPolyDataOps, polyDataOps,
1888                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
1889    if (proc == NULL) {
1890        return TCL_ERROR;
1891    }
1892    return (*proc) (clientData, interp, objc, objv);
1893}
1894
1895static int
1896ScreenBgColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
1897                Tcl_Obj *const *objv)
1898{
1899    float color[3];
1900
1901    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
1902        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
1903        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
1904        return TCL_ERROR;
1905    }
1906
1907    g_renderer->setBackgroundColor(color);
1908    return TCL_OK;
1909}
1910
1911static int
1912ScreenSizeOp(ClientData clientData, Tcl_Interp *interp, int objc,
1913             Tcl_Obj *const *objv)
1914{
1915    int width, height;
1916
1917    if (Tcl_GetIntFromObj(interp, objv[2], &width) != TCL_OK ||
1918        Tcl_GetIntFromObj(interp, objv[3], &height) != TCL_OK) {
1919        return TCL_ERROR;
1920    }
1921
1922    g_renderer->setWindowSize(width, height);
1923    return TCL_OK;
1924}
1925
1926static Rappture::CmdSpec screenOps[] = {
1927    {"bgcolor", 1, ScreenBgColorOp, 5, 5, "r g b"},
1928    {"size", 1, ScreenSizeOp, 4, 4, "width height"}
1929};
1930static int nScreenOps = NumCmdSpecs(screenOps);
1931
1932static int
1933ScreenCmd(ClientData clientData, Tcl_Interp *interp, int objc,
1934          Tcl_Obj *const *objv)
1935{
1936    Tcl_ObjCmdProc *proc;
1937
1938    proc = Rappture::GetOpFromObj(interp, nScreenOps, screenOps,
1939                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
1940    if (proc == NULL) {
1941        return TCL_ERROR;
1942    }
1943    return (*proc) (clientData, interp, objc, objv);
1944}
1945
1946static int
1947VolumeAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
1948            Tcl_Obj *const *objv)
1949{
1950    if (objc == 3) {
1951        const char *name = Tcl_GetString(objv[2]);
1952        g_renderer->addVolume(name);
1953    } else {
1954        g_renderer->addVolume("all");
1955    }
1956    return TCL_OK;
1957}
1958
1959static int
1960VolumeColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
1961                 Tcl_Obj *const *objv)
1962{
1963    const char *colorMapName = Tcl_GetString(objv[2]);
1964    if (objc == 4) {
1965        const char *dataSetName = Tcl_GetString(objv[3]);
1966        g_renderer->setVolumeColorMap(dataSetName, colorMapName);
1967    } else {
1968        g_renderer->setVolumeColorMap("all", colorMapName);
1969    }
1970    return TCL_OK;
1971}
1972
1973static int
1974VolumeDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
1975               Tcl_Obj *const *objv)
1976{
1977    if (objc == 3) {
1978        const char *name = Tcl_GetString(objv[2]);
1979        g_renderer->deleteVolume(name);
1980    } else {
1981        g_renderer->deleteVolume("all");
1982    }
1983    return TCL_OK;
1984}
1985
1986static int
1987VolumeLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
1988                 Tcl_Obj *const *objv)
1989{
1990    bool state;
1991    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1992        return TCL_ERROR;
1993    }
1994    if (objc == 4) {
1995        const char *name = Tcl_GetString(objv[3]);
1996        g_renderer->setVolumeLighting(name, state);
1997    } else {
1998        g_renderer->setVolumeLighting("all", state);
1999    }
2000    return TCL_OK;
2001}
2002
2003static int
2004VolumeOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
2005                Tcl_Obj *const *objv)
2006{
2007    double opacity;
2008    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
2009        return TCL_ERROR;
2010    }
2011    if (objc == 4) {
2012        const char *name = Tcl_GetString(objv[3]);
2013        g_renderer->setVolumeOpacity(name, opacity);
2014    } else {
2015        g_renderer->setVolumeOpacity("all", opacity);
2016    }
2017    return TCL_OK;
2018}
2019
2020static int
2021VolumeShadingAmbientOp(ClientData clientData, Tcl_Interp *interp, int objc,
2022                       Tcl_Obj *const *objv)
2023{
2024    double coeff;
2025    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK) {
2026        return TCL_ERROR;
2027    }
2028
2029    if (objc == 5) {
2030        const char *name = Tcl_GetString(objv[4]);
2031        g_renderer->setVolumeAmbient(name, coeff);
2032    } else {
2033        g_renderer->setVolumeAmbient("all", coeff);
2034    }
2035    return TCL_OK;
2036}
2037
2038static int
2039VolumeShadingDiffuseOp(ClientData clientData, Tcl_Interp *interp, int objc,
2040                       Tcl_Obj *const *objv)
2041{
2042    double coeff;
2043    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK) {
2044        return TCL_ERROR;
2045    }
2046
2047    if (objc == 5) {
2048        const char *name = Tcl_GetString(objv[4]);
2049        g_renderer->setVolumeDiffuse(name, coeff);
2050    } else {
2051        g_renderer->setVolumeDiffuse("all", coeff);
2052    }
2053    return TCL_OK;
2054}
2055
2056static int
2057VolumeShadingSpecularOp(ClientData clientData, Tcl_Interp *interp, int objc,
2058                        Tcl_Obj *const *objv)
2059{
2060    double coeff, power;
2061    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK ||
2062        Tcl_GetDoubleFromObj(interp, objv[4], &power) != TCL_OK) {
2063        return TCL_ERROR;
2064    }
2065
2066    if (objc == 6) {
2067        const char *name = Tcl_GetString(objv[5]);
2068        g_renderer->setVolumeSpecular(name, coeff, power);
2069    } else {
2070        g_renderer->setVolumeSpecular("all", coeff, power);
2071    }
2072    return TCL_OK;
2073}
2074
2075static Rappture::CmdSpec volumeShadingOps[] = {
2076    {"ambient",  1, VolumeShadingAmbientOp, 4, 5, "coeff ?dataSetName?"},
2077    {"diffuse",  1, VolumeShadingDiffuseOp, 4, 5, "coeff ?dataSetName?"},
2078    {"specular", 1, VolumeShadingSpecularOp, 5, 6, "coeff power ?dataSetName?"}
2079};
2080static int nVolumeShadingOps = NumCmdSpecs(volumeShadingOps);
2081
2082static int
2083VolumeShadingOp(ClientData clientData, Tcl_Interp *interp, int objc,
2084                Tcl_Obj *const *objv)
2085{
2086    Tcl_ObjCmdProc *proc;
2087
2088    proc = Rappture::GetOpFromObj(interp, nVolumeShadingOps, volumeShadingOps,
2089                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
2090    if (proc == NULL) {
2091        return TCL_ERROR;
2092    }
2093    return (*proc) (clientData, interp, objc, objv);
2094}
2095
2096static int
2097VolumeVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
2098                Tcl_Obj *const *objv)
2099{
2100    bool state;
2101    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
2102        return TCL_ERROR;
2103    }
2104    if (objc == 4) {
2105        const char *name = Tcl_GetString(objv[3]);
2106        g_renderer->setVolumeVisibility(name, state);
2107    } else {
2108        g_renderer->setVolumeVisibility("all", state);
2109    }
2110    return TCL_OK;
2111}
2112
2113static Rappture::CmdSpec volumeOps[] = {
2114    {"add",      1, VolumeAddOp, 2, 3, "?dataSetName?"},
2115    {"colormap", 1, VolumeColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
2116    {"delete",   1, VolumeDeleteOp, 2, 3, "?dataSetName?"},
2117    {"lighting", 1, VolumeLightingOp, 3, 4, "bool ?dataSetName?"},
2118    {"opacity",  1, VolumeOpacityOp, 3, 4, "val ?dataSetName?"},
2119    {"shading",  1, VolumeShadingOp, 4, 6, "oper val ?dataSetName?"},
2120    {"visible",  1, VolumeVisibleOp, 3, 4, "bool ?dataSetName?"}
2121};
2122static int nVolumeOps = NumCmdSpecs(volumeOps);
2123
2124static int
2125VolumeCmd(ClientData clientData, Tcl_Interp *interp, int objc,
2126          Tcl_Obj *const *objv)
2127{
2128    Tcl_ObjCmdProc *proc;
2129
2130    proc = Rappture::GetOpFromObj(interp, nVolumeOps, volumeOps,
2131                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
2132    if (proc == NULL) {
2133        return TCL_ERROR;
2134    }
2135    return (*proc) (clientData, interp, objc, objv);
2136}
2137
2138/**
2139 * \brief Execute commands from client in Tcl interpreter
2140 */
2141int
2142Rappture::VtkVis::processCommands(Tcl_Interp *interp, FILE *fin, FILE *fout)
2143{
2144    Tcl_DString cmdbuffer;
2145    Tcl_DStringInit(&cmdbuffer);
2146
2147    int fdIn = fileno(fin);
2148    int fdOut = fileno(fout);
2149    int flags = fcntl(fdIn, F_GETFL, 0);
2150    fcntl(fdIn, F_SETFL, flags & ~O_NONBLOCK);
2151
2152    int status = TCL_OK;
2153    int nCommands = 0;
2154    bool isComplete = false;
2155    while ((!feof(fin)) && (status == TCL_OK)) {
2156        while (!feof(fin)) {
2157            int c = fgetc(fin);
2158            if (c <= 0) {
2159                if (errno == EWOULDBLOCK) {
2160                    break;
2161                }
2162                if (feof(fin))
2163                    return 1;
2164                else
2165                    return c;
2166            }
2167            char ch = (char)c;
2168            Tcl_DStringAppend(&cmdbuffer, &ch, 1);
2169            if (ch == '\n') {
2170                isComplete = Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer));
2171                if (isComplete) {
2172                    break;
2173                }
2174            }
2175        }
2176        // no command? then we're done for now
2177        if (Tcl_DStringLength(&cmdbuffer) == 0) {
2178            break;
2179        }
2180        if (isComplete) {
2181            // back to original flags during command evaluation...
2182            fcntl(fdIn, F_SETFL, flags & ~O_NONBLOCK);
2183            TRACE("command: '%s'", Tcl_DStringValue(&cmdbuffer));
2184            status = ExecuteCommand(interp, &cmdbuffer);
2185            // non-blocking for next read -- we might not get anything
2186            fcntl(fdIn, F_SETFL, flags | O_NONBLOCK);
2187            isComplete = false;
2188            nCommands++;
2189        }
2190    }
2191    fcntl(fdIn, F_SETFL, flags);
2192
2193    if (status != TCL_OK) {
2194        const char *string;
2195        int nBytes;
2196
2197        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
2198        TRACE("ERROR errorInfo=(%s)", string);
2199
2200        nBytes = strlen(string);
2201        struct iovec iov[3];
2202        iov[0].iov_base = (char *)"VtkVis Server Error: ";
2203        iov[0].iov_len = strlen((char *)iov[0].iov_base);
2204        iov[1].iov_base = (char *)string;
2205        iov[1].iov_len = nBytes;
2206        iov[2].iov_base = (char *)"\n";
2207        iov[2].iov_len = 1;
2208        if (writev(fdOut, iov, 3) < 0) {
2209            ERROR("write failed: %s", strerror(errno));
2210        }
2211        return 0;
2212    }
2213
2214    return 1;
2215}
2216
2217/**
2218 * \brief Create Tcl interpreter and add commands
2219 *
2220 * \return The initialized Tcl interpreter
2221 */
2222Tcl_Interp *
2223Rappture::VtkVis::initTcl()
2224{
2225    Tcl_Interp *interp;
2226    interp = Tcl_CreateInterp();
2227    /*
2228    Tcl_MakeSafe(interp);
2229    */
2230    Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        NULL, NULL);
2231    Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      NULL, NULL);
2232    Tcl_CreateObjCommand(interp, "colormap",    ColorMapCmd,    NULL, NULL);
2233    Tcl_CreateObjCommand(interp, "contour2d",   Contour2DCmd,   NULL, NULL);
2234    Tcl_CreateObjCommand(interp, "dataset",     DataSetCmd,     NULL, NULL);
2235    Tcl_CreateObjCommand(interp, "glyphs",      GlyphsCmd,      NULL, NULL);
2236    Tcl_CreateObjCommand(interp, "heightmap",   HeightMapCmd,   NULL, NULL);
2237    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      NULL, NULL);
2238    Tcl_CreateObjCommand(interp, "polydata",    PolyDataCmd,    NULL, NULL);
2239    Tcl_CreateObjCommand(interp, "pseudocolor", PseudoColorCmd, NULL, NULL);
2240    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      NULL, NULL);
2241    Tcl_CreateObjCommand(interp, "volume",      VolumeCmd,      NULL, NULL);
2242    return interp;
2243}
Note: See TracBrowser for help on using the repository browser.