source: branches/blt4/packages/vizservers/vtkvis/RpVtkRendererCmd.cpp @ 2170

Last change on this file since 2170 was 2170, checked in by gah, 14 years ago
File size: 41.3 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
76AxisGridOp(ClientData clientData, Tcl_Interp *interp, int objc,
77           Tcl_Obj *const *objv)
78{
79    bool visible;
80    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
81        return TCL_ERROR;
82    }
83    const char *string = Tcl_GetString(objv[2]);
84    char c = string[0];
85    if ((c == 'x') && (strcmp(string, "x") == 0)) {
86        g_renderer->setAxisGridVisibility(Renderer::X_AXIS, visible);
87    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
88        g_renderer->setAxisGridVisibility(Renderer::Y_AXIS, visible);
89    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
90        g_renderer->setAxisGridVisibility(Renderer::Z_AXIS, visible);
91    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
92        g_renderer->setAxesGridVisibility(visible);
93    } else {
94        Tcl_AppendResult(interp, "bad axis option \"", string,
95                         "\": should be axisName visible", (char*)NULL);
96        return TCL_ERROR;
97    }
98    return TCL_OK;
99}
100
101static int
102AxisNameOp(ClientData clientData, Tcl_Interp *interp, int objc,
103           Tcl_Obj *const *objv)
104{
105    const char *title = Tcl_GetString(objv[3]);
106    const char *string = Tcl_GetString(objv[2]);
107    char c = string[0];
108    if ((c == 'x') && (strcmp(string, "x") == 0)) {
109        g_renderer->setAxisTitle(Renderer::X_AXIS, title);
110    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
111        g_renderer->setAxisTitle(Renderer::Y_AXIS, title);
112    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
113        g_renderer->setAxisTitle(Renderer::Z_AXIS, title);
114    } else {
115        Tcl_AppendResult(interp, "bad axis option \"", string,
116                         "\": should be axisName title", (char*)NULL);
117        return TCL_ERROR;
118    }
119    return TCL_OK;
120}
121
122static int
123AxisUnitsOp(ClientData clientData, Tcl_Interp *interp, int objc,
124            Tcl_Obj *const *objv)
125{
126    const char *units = Tcl_GetString(objv[3]);
127    const char *string = Tcl_GetString(objv[2]);
128    char c = string[0];
129    if ((c == 'x') && (strcmp(string, "x") == 0)) {
130        g_renderer->setAxisUnits(Renderer::X_AXIS, units);
131    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
132        g_renderer->setAxisUnits(Renderer::Y_AXIS, units);
133    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
134        g_renderer->setAxisUnits(Renderer::Z_AXIS, units);
135    } else {
136        Tcl_AppendResult(interp, "bad axis option \"", string,
137                         "\": should be axisName units", (char*)NULL);
138        return TCL_ERROR;
139    }
140    return TCL_OK;
141}
142
143static int
144AxisVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
145              Tcl_Obj *const *objv)
146{
147    bool visible;
148    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
149        return TCL_ERROR;
150    }
151    const char *string = Tcl_GetString(objv[2]);
152    char c = string[0];
153    if ((c == 'x') && (strcmp(string, "x") == 0)) {
154        g_renderer->setAxisVisibility(Renderer::X_AXIS, visible);
155    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
156        g_renderer->setAxisVisibility(Renderer::Y_AXIS, visible);
157    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
158        g_renderer->setAxisVisibility(Renderer::Z_AXIS, visible);
159    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
160        g_renderer->setAxesVisibility(visible);
161    } else {
162        Tcl_AppendResult(interp, "bad axis option \"", string,
163                         "\": should be axisName visible", (char*)NULL);
164        return TCL_ERROR;
165    }
166    return TCL_OK;
167}
168
169static Rappture::CmdSpec axisOps[] = {
170    {"color", 1, AxisColorOp, 5, 5, "r g b"},
171    {"grid", 1, AxisGridOp, 4, 4, "axis bool"},
172    {"name", 1, AxisNameOp, 4, 4, "axis title"},
173    {"units", 1, AxisUnitsOp, 4, 4, "axis units"},
174    {"visible", 1, AxisVisibleOp, 4, 4, "axis bool"}
175};
176static int nAxisOps = NumCmdSpecs(axisOps);
177
178static int
179AxisCmd(ClientData clientData, Tcl_Interp *interp, int objc,
180        Tcl_Obj *const *objv)
181{
182    Tcl_ObjCmdProc *proc;
183
184    proc = Rappture::GetOpFromObj(interp, nAxisOps, axisOps,
185                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
186    if (proc == NULL) {
187        return TCL_ERROR;
188    }
189    return (*proc) (clientData, interp, objc, objv);
190}
191
192static int
193CameraModeOp(ClientData clientData, Tcl_Interp *interp, int objc,
194             Tcl_Obj *const *objv)
195{
196    Renderer::CameraMode mode;
197    const char *string = Tcl_GetString(objv[2]);
198    if ((strcmp(string, "persp") == 0)) {
199        mode = Renderer::PERSPECTIVE;
200    } else if ((strcmp(string, "ortho") == 0)) {
201        mode = Renderer::ORTHO;
202    } else if ((strcmp(string, "image") == 0)) {
203        mode = Renderer::IMAGE;
204    } else {
205        Tcl_AppendResult(interp, "bad camera mode option \"", string,
206                         "\": should be perspective, ortho or image", (char*)NULL);
207        return TCL_ERROR;
208    }
209    g_renderer->setCameraMode(mode);
210    return TCL_OK;
211}
212
213static int
214CameraOrthoOp(ClientData clientData, Tcl_Interp *interp, int objc,
215              Tcl_Obj *const *objv)
216{
217    float x, y, width, height;
218
219    if (GetFloatFromObj(interp, objv[2], &x) != TCL_OK ||
220        GetFloatFromObj(interp, objv[3], &y) != TCL_OK ||
221        GetFloatFromObj(interp, objv[4], &width) != TCL_OK ||
222        GetFloatFromObj(interp, objv[5], &height) != TCL_OK) {
223        return TCL_ERROR;
224    }
225
226    g_renderer->setCameraZoomRegion(x, y, width, height);
227    return TCL_OK;
228}
229
230static int
231CameraPanOp(ClientData clientData, Tcl_Interp *interp, int objc,
232            Tcl_Obj *const *objv)
233{
234    float x, y;
235
236    if (GetFloatFromObj(interp, objv[2], &x) != TCL_OK ||
237        GetFloatFromObj(interp, objv[3], &y) != TCL_OK) {
238        return TCL_ERROR;
239    }
240
241    g_renderer->panCamera(x, y);
242    return TCL_OK;
243}
244
245static int
246CameraResetOp(ClientData clientData, Tcl_Interp *interp, int objc,
247              Tcl_Obj *const *objv)
248{
249    if (objc == 3) {
250        const char *string = Tcl_GetString(objv[2]);
251        char c = string[0];
252        if ((c != 'a') || (strcmp(string, "all") != 0)) {
253            Tcl_AppendResult(interp, "bad camera reset option \"", string,
254                         "\": should be all", (char*)NULL);
255            return TCL_ERROR;
256        }
257        g_renderer->resetCamera(true);
258    } else {
259        g_renderer->resetCamera(false);
260    }
261    return TCL_OK;
262}
263
264static int
265CameraRotateOp(ClientData clientData, Tcl_Interp *interp, int objc,
266               Tcl_Obj *const *objv)
267{
268    float yaw, pitch, roll;
269
270    if (GetFloatFromObj(interp, objv[2], &yaw) != TCL_OK ||
271        GetFloatFromObj(interp, objv[3], &pitch) != TCL_OK ||
272        GetFloatFromObj(interp, objv[4], &roll) != TCL_OK) {
273        return TCL_ERROR;
274    }
275
276    g_renderer->rotateCamera(yaw, pitch, roll);
277    return TCL_OK;
278}
279
280static int
281CameraZoomOp(ClientData clientData, Tcl_Interp *interp, int objc,
282            Tcl_Obj *const *objv)
283{
284    float z;
285
286    if (GetFloatFromObj(interp, objv[2], &z) != TCL_OK) {
287        return TCL_ERROR;
288    }
289
290    g_renderer->zoomCamera(z);
291    return TCL_OK;
292}
293
294static Rappture::CmdSpec cameraOps[] = {
295    {"mode", 1, CameraModeOp, 3, 3, "mode"},
296    {"ortho", 1, CameraOrthoOp, 6, 6, "x y width height"},
297    {"pan", 1, CameraPanOp, 4, 4, "panX panY"},
298    {"reset", 2, CameraResetOp, 2, 3, "?all?"},
299    {"rotate", 2, CameraRotateOp, 5, 5, "angle angle angle"},
300    {"zoom", 1, CameraZoomOp, 3, 3, "zoomAmount"}
301};
302static int nCameraOps = NumCmdSpecs(cameraOps);
303
304static int
305CameraCmd(ClientData clientData, Tcl_Interp *interp, int objc,
306          Tcl_Obj *const *objv)
307{
308    Tcl_ObjCmdProc *proc;
309
310    proc = Rappture::GetOpFromObj(interp, nCameraOps, cameraOps,
311                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
312    if (proc == NULL) {
313        return TCL_ERROR;
314    }
315    return (*proc) (clientData, interp, objc, objv);
316}
317
318static int
319ColorMapAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
320              Tcl_Obj *const *objv)
321{
322    const char *name = Tcl_GetString(objv[2]);
323    int cmapc, omapc;
324    Tcl_Obj **cmapv = NULL;
325    Tcl_Obj **omapv = NULL;
326
327    if (Tcl_ListObjGetElements(interp, objv[3], &cmapc, &cmapv) != TCL_OK) {
328        return TCL_ERROR;
329    }
330    if ((cmapc % 4) != 0) {
331        Tcl_AppendResult(interp, "wrong # elements in colormap: should be ",
332                         "{ value r g b ... }", (char*)NULL);
333        return TCL_ERROR;
334    }
335
336    ColorMap *colorMap = new ColorMap(name);
337    colorMap->setNumberOfTableEntries(256);
338
339    for (int i = 0; i < cmapc; i += 4) {
340        double val[4];
341        for (int j = 0; j < 4; j++) {
342            if (Tcl_GetDoubleFromObj(interp, cmapv[i+j], &val[j]) != TCL_OK) {
343                delete colorMap;
344                return TCL_ERROR;
345            }
346            if ((val[j] < 0.0) || (val[j] > 1.0)) {
347                Tcl_AppendResult(interp, "bad colormap value \"",
348                                 Tcl_GetString(cmapv[i+j]),
349                                 "\": should be in the range [0,1]", (char*)NULL);
350                delete colorMap;
351                return TCL_ERROR;
352            }
353        }
354        ColorMap::ControlPoint cp;
355        cp.value = val[0];
356        for (int c = 0; c < 3; c++) {
357            cp.color[c] = val[c+1];
358        }
359        colorMap->addControlPoint(cp);
360    }
361
362    if (Tcl_ListObjGetElements(interp, objv[4], &omapc, &omapv) != TCL_OK) {
363        delete colorMap;
364        return TCL_ERROR;
365    }
366    if ((omapc % 2) != 0) {
367        Tcl_AppendResult(interp, "wrong # elements in opacitymap: should be ",
368                         "{ value alpha ... }", (char*)NULL);
369        delete colorMap;
370        return TCL_ERROR;
371    }
372    for (int i = 0; i < omapc; i += 2) {
373        double val[2];
374        for (int j = 0; j < 2; j++) {
375            if (Tcl_GetDoubleFromObj(interp, omapv[i+j], &val[j]) != TCL_OK) {
376                delete colorMap;
377                return TCL_ERROR;
378            }
379            if ((val[j] < 0.0) || (val[j] > 1.0)) {
380                Tcl_AppendResult(interp, "bad opacitymap value \"",
381                                 Tcl_GetString(omapv[i+j]),
382                                 "\": should be in the range [0,1]", (char*)NULL);
383                delete colorMap;
384                return TCL_ERROR;
385            }
386        }
387        ColorMap::OpacityControlPoint ocp;
388        ocp.value = val[0];
389        ocp.alpha = val[1];
390        colorMap->addOpacityControlPoint(ocp);
391    }
392
393    colorMap->build();
394    g_renderer->addColorMap(name, colorMap);
395    return TCL_OK;
396}
397
398static int
399ColorMapDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
400                 Tcl_Obj *const *objv)
401{
402    if (objc == 3) {
403        const char *name = Tcl_GetString(objv[2]);
404        g_renderer->deleteColorMap(name);
405    } else {
406        g_renderer->deleteColorMap("all");
407    }
408    return TCL_OK;
409}
410
411static Rappture::CmdSpec colorMapOps[] = {
412    {"add", 1, ColorMapAddOp, 5, 5, "colorMapName colormap alphamap"},
413    {"delete", 1, ColorMapDeleteOp, 2, 3, "?colorMapName?"}
414};
415static int nColorMapOps = NumCmdSpecs(colorMapOps);
416
417static int
418ColorMapCmd(ClientData clientData, Tcl_Interp *interp, int objc,
419            Tcl_Obj *const *objv)
420{
421    Tcl_ObjCmdProc *proc;
422
423    proc = Rappture::GetOpFromObj(interp, nColorMapOps, colorMapOps,
424                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
425    if (proc == NULL) {
426        return TCL_ERROR;
427    }
428    return (*proc) (clientData, interp, objc, objv);
429}
430
431static int
432Contour2DAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc,
433                          Tcl_Obj *const *objv)
434{
435    std::vector<double> contourList;
436
437    int clistc;
438    Tcl_Obj **clistv;
439
440    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
441        return TCL_ERROR;
442    }
443
444    for (int i = 0; i < clistc; i++) {
445        double val;
446        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
447            return TCL_ERROR;
448        }
449        contourList.push_back(val);
450    }
451
452    if (objc == 5) {
453        const char *name = Tcl_GetString(objv[4]);
454        g_renderer->addContour2D(name);
455        g_renderer->setContourList(name, contourList);
456    } else {
457        g_renderer->addContour2D("all");
458        g_renderer->setContourList("all", contourList);
459    }
460    return TCL_OK;
461}
462
463static int
464Contour2DAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc,
465                          Tcl_Obj *const *objv)
466{
467    int numContours;
468    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
469        return TCL_ERROR;
470    }
471    if (objc == 5) {
472        const char *name = Tcl_GetString(objv[4]);
473        g_renderer->addContour2D(name);
474        g_renderer->setContours(name, numContours);
475    } else {
476        g_renderer->addContour2D("all");
477        g_renderer->setContours("all", numContours);
478    }
479    return TCL_OK;
480}
481
482static Rappture::CmdSpec contour2dAddOps[] = {
483    {"contourlist", 1, Contour2DAddContourListOp, 4, 5, "contourList ?dataSetName?"},
484    {"numcontours", 1, Contour2DAddNumContoursOp, 4, 5, "numContours ?dataSetName?"}
485};
486static int nContour2dAddOps = NumCmdSpecs(contour2dAddOps);
487
488static int
489Contour2DAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
490               Tcl_Obj *const *objv)
491{
492    Tcl_ObjCmdProc *proc;
493
494    proc = Rappture::GetOpFromObj(interp, nContour2dAddOps, contour2dAddOps,
495                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
496    if (proc == NULL) {
497        return TCL_ERROR;
498    }
499    return (*proc) (clientData, interp, objc, objv);
500}
501
502static int
503Contour2DDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
504                  Tcl_Obj *const *objv)
505{
506    if (objc == 3) {
507        const char *name = Tcl_GetString(objv[2]);
508        g_renderer->deleteContour2D(name);
509    } else {
510        g_renderer->deleteContour2D("all");
511    }
512    return TCL_OK;
513}
514
515static int
516Contour2DLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
517                    Tcl_Obj *const *objv)
518{
519    bool state;
520    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
521        return TCL_ERROR;
522    }
523    if (objc == 4) {
524        const char *name = Tcl_GetString(objv[3]);
525        g_renderer->setContourLighting(name, state);
526    } else {
527        g_renderer->setContourLighting("all", state);
528    }
529    return TCL_OK;
530}
531
532static int
533Contour2DLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
534                     Tcl_Obj *const *objv)
535{
536    float color[3];
537    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
538        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
539        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
540        return TCL_ERROR;
541    }
542    if (objc == 6) {
543        const char *name = Tcl_GetString(objv[5]);
544        g_renderer->setContourEdgeColor(name, color);
545    } else {
546        g_renderer->setContourEdgeColor("all", color);
547    }
548    return TCL_OK;
549}
550
551static int
552Contour2DLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
553                     Tcl_Obj *const *objv)
554{
555    float width;
556    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
557        return TCL_ERROR;
558    }
559    if (objc == 4) {
560        const char *name = Tcl_GetString(objv[3]);
561        g_renderer->setContourEdgeWidth(name, width);
562    } else {
563        g_renderer->setContourEdgeWidth("all", width);
564    }
565    return TCL_OK;
566}
567
568static int
569Contour2DOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
570                   Tcl_Obj *const *objv)
571{
572    double opacity;
573    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
574        return TCL_ERROR;
575    }
576    if (objc == 4) {
577        const char *name = Tcl_GetString(objv[3]);
578        g_renderer->setContourOpacity(name, opacity);
579    } else {
580        g_renderer->setContourOpacity("all", opacity);
581    }
582    return TCL_OK;
583}
584
585static int
586Contour2DVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
587                   Tcl_Obj *const *objv)
588{
589    bool state;
590    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
591        return TCL_ERROR;
592    }
593    if (objc == 4) {
594        const char *name = Tcl_GetString(objv[3]);
595        g_renderer->setContourVisibility(name, state);
596    } else {
597        g_renderer->setContourVisibility("all", state);
598    }
599    return TCL_OK;
600}
601
602static Rappture::CmdSpec contour2dOps[] = {
603    {"add", 1, Contour2DAddOp, 4, 5, "oper value ?dataSetName?"},
604    {"delete", 1, Contour2DDeleteOp, 2, 3, "?dataSetName?"},
605    {"lighting", 3, Contour2DLightingOp, 3, 4, "bool ?dataSetName?"},
606    {"linecolor", 5, Contour2DLineColorOp, 5, 6, "r g b ?dataSetName?"},
607    {"linewidth", 5, Contour2DLineWidthOp, 3, 4, "width ?dataSetName?"},
608    {"opacity", 1, Contour2DOpacityOp, 3, 4, "value ?dataSetName?"},
609    {"visible", 1, Contour2DVisibleOp, 3, 4, "bool ?dataSetName?"}
610};
611static int nContour2dOps = NumCmdSpecs(contour2dOps);
612
613static int
614Contour2DCmd(ClientData clientData, Tcl_Interp *interp, int objc,
615             Tcl_Obj *const *objv)
616{
617    Tcl_ObjCmdProc *proc;
618
619    proc = Rappture::GetOpFromObj(interp, nContour2dOps, contour2dOps,
620                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
621    if (proc == NULL) {
622        return TCL_ERROR;
623    }
624    return (*proc) (clientData, interp, objc, objv);
625}
626
627static int
628DataSetAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
629             Tcl_Obj *const *objv)
630{
631    const char *name = Tcl_GetString(objv[2]);
632    const char *string = Tcl_GetString(objv[3]);
633    char c = string[0];
634    if ((c != 'd') || (strcmp(string, "data") != 0)) {
635        Tcl_AppendResult(interp, "bad dataset option \"", string,
636                         "\": should be data", (char*)NULL);
637        return TCL_ERROR;
638    }
639    string = Tcl_GetString(objv[4]);
640    c = string[0];
641    if ((c != 'f') || (strcmp(string, "follows") != 0)) {
642        Tcl_AppendResult(interp, "bad dataset option \"", string,
643                         "\": should be follows", (char*)NULL);
644        return TCL_ERROR;
645    }
646    int nbytes = 0;
647    if (Tcl_GetIntFromObj(interp, objv[5], &nbytes) != TCL_OK ||
648        nbytes < 0) {
649        return TCL_ERROR;
650    }
651    char *data = (char *)malloc(nbytes);
652#ifdef notdef
653    size_t ofs = 0;
654    ssize_t bytesRead = 0;
655    while ((bytesRead = read(g_fdIn, data + ofs, nbytes - ofs)) > 0) {
656        ofs += bytesRead;
657        if (ofs == nbytes)
658            break;
659    }
660    TRACE("bytesRead: %d", ofs);
661    if (bytesRead < 0) {
662        return TCL_ERROR;
663    }
664#else
665    size_t bytesRead = fread(data, 1, nbytes, g_fIn);
666    TRACE("bytesRead: %d '%c'", bytesRead, data[0]);
667    if (bytesRead < (size_t)nbytes) {
668        return TCL_ERROR;
669    }
670#endif
671    g_renderer->addDataSet(name);
672    g_renderer->setData(name, data, nbytes);
673    free(data);
674    return TCL_OK;
675}
676
677static int
678DataSetDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
679                Tcl_Obj *const *objv)
680{
681    if (objc == 3) {
682        const char *name = Tcl_GetString(objv[2]);
683        TRACE("Deleting dataset %s", name);
684        g_renderer->deleteDataSet(name);
685    } else {
686        g_renderer->deleteDataSet("all");
687    }
688    return TCL_OK;
689}
690
691static int
692DataSetGetValuePixelOp(ClientData clientData, Tcl_Interp *interp, int objc,
693                       Tcl_Obj *const *objv)
694{
695    const char *name = Tcl_GetString(objv[5]);
696    int x, y;
697    if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK ||
698        Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
699        return TCL_ERROR;
700    }
701    double value = g_renderer->getDataValueAtPixel(name, x, y);
702    char buf[128];
703    snprintf(buf, sizeof(buf), "nv>dataset value pixel %d %d %.12e", x, y, value);
704    ssize_t bytesWritten;
705    size_t len = strlen(buf);
706    size_t ofs = 0;
707    while ((bytesWritten = write(g_fdOut, buf + ofs, len - ofs)) > 0) {
708        ofs += bytesWritten;
709        if (ofs == len)
710            break;
711    }
712    if (bytesWritten < 0) {
713        return TCL_ERROR;
714    }
715    return TCL_OK;
716}
717
718static int
719DataSetGetValueWorldOp(ClientData clientData, Tcl_Interp *interp, int objc,
720                       Tcl_Obj *const *objv)
721{
722    const char *name = Tcl_GetString(objv[6]);
723    double x, y, z;
724    if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK ||
725        Tcl_GetDoubleFromObj(interp, objv[4], &y) != TCL_OK ||
726        Tcl_GetDoubleFromObj(interp, objv[5], &z) != TCL_OK) {
727        return TCL_ERROR;
728    }
729    double value = g_renderer->getDataValue(name, x, y, z);
730    char buf[128];
731    snprintf(buf, sizeof(buf), "nv>dataset value world %.12e %.12e %.12e %.12e", x, y, z, value);
732    ssize_t bytesWritten;
733    size_t len = strlen(buf);
734    size_t ofs = 0;
735    while ((bytesWritten = write(g_fdOut, buf + ofs, len - ofs)) > 0) {
736        ofs += bytesWritten;
737        if (ofs == len)
738            break;
739    }
740    if (bytesWritten < 0) {
741        return TCL_ERROR;
742    }
743    return TCL_OK;
744}
745
746static Rappture::CmdSpec dataSetGetValueOps[] = {
747    {"pixel", 1, DataSetGetValuePixelOp, 6, 6, "x y dataSetName"},
748    {"world", 1, DataSetGetValueWorldOp, 7, 7, "x y z dataSetName"}
749};
750static int nDataSetGetValueOps = NumCmdSpecs(dataSetGetValueOps);
751
752static int
753DataSetGetValueOp(ClientData clientData, Tcl_Interp *interp, int objc,
754                  Tcl_Obj *const *objv)
755{
756    Tcl_ObjCmdProc *proc;
757
758    proc = Rappture::GetOpFromObj(interp, nDataSetGetValueOps, dataSetGetValueOps,
759                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
760    if (proc == NULL) {
761        return TCL_ERROR;
762    }
763    return (*proc) (clientData, interp, objc, objv);
764}
765
766static int
767DataSetOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
768                 Tcl_Obj *const *objv)
769{
770    double opacity;
771    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
772        return TCL_ERROR;
773    }
774    if (objc == 4) {
775        const char *name = Tcl_GetString(objv[3]);
776        g_renderer->setOpacity(name, opacity);
777    } else {
778        g_renderer->setOpacity("all", opacity);
779    }
780    return TCL_OK;
781}
782
783static int
784DataSetVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
785                 Tcl_Obj *const *objv)
786{
787    bool state;
788    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
789        return TCL_ERROR;
790    }
791    if (objc == 4) {
792        const char *name = Tcl_GetString(objv[3]);
793        g_renderer->setVisibility(name, state);
794    } else {
795        g_renderer->setVisibility("all", state);
796    }
797    return TCL_OK;
798}
799
800static Rappture::CmdSpec dataSetOps[] = {
801    {"add", 1, DataSetAddOp, 6, 6, "name data follows nBytes"},
802    {"delete", 1, DataSetDeleteOp, 2, 3, "?name?"},
803    {"getvalue", 1, DataSetGetValueOp, 6, 7, "oper x y ?z? name"},
804    {"opacity", 1, DataSetOpacityOp, 3, 4, "value ?name?"},
805    {"visible", 1, DataSetVisibleOp, 3, 4, "bool ?name?"}
806};
807static int nDataSetOps = NumCmdSpecs(dataSetOps);
808
809static int
810DataSetCmd(ClientData clientData, Tcl_Interp *interp, int objc,
811           Tcl_Obj *const *objv)
812{
813    Tcl_ObjCmdProc *proc;
814
815    proc = Rappture::GetOpFromObj(interp, nDataSetOps, dataSetOps,
816                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
817    if (proc == NULL) {
818        return TCL_ERROR;
819    }
820    return (*proc) (clientData, interp, objc, objv);
821}
822
823static int
824LegendCmd(ClientData clientData, Tcl_Interp *interp, int objc,
825          Tcl_Obj *const *objv)
826{
827    if (objc < 4) {
828        Tcl_AppendResult(interp, "wrong # args: should be \"",
829                Tcl_GetString(objv[0]), " colormapName title width height ?dataSetName?\"", (char*)NULL);
830        return TCL_ERROR;
831    }
832    const char *name = Tcl_GetString(objv[1]);
833    const char *title = Tcl_GetString(objv[2]);
834    int width, height;
835
836    if (Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK ||
837        Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK) {
838        return TCL_ERROR;
839    }
840
841    vtkSmartPointer<vtkUnsignedCharArray> imgData =
842        vtkSmartPointer<vtkUnsignedCharArray>::New();
843
844    if (objc == 6) {
845        const char *dataSetName = Tcl_GetString(objv[5]);
846        if (!g_renderer->renderColorMap(name, dataSetName, title, width, height, imgData)) {
847            Tcl_AppendResult(interp, "Color map \"",
848                             name, "\" was not found", (char*)NULL);
849            return TCL_ERROR;
850        }
851    } else {
852        if (!g_renderer->renderColorMap(name, "all", title, width, height, imgData)) {
853            Tcl_AppendResult(interp, "Color map \"",
854                             name, "\" was not found", (char*)NULL);
855            return TCL_ERROR;
856        }
857    }
858
859#ifdef DEBUG
860    writeTGAFile("/tmp/legend.tga", imgData->GetPointer(0), width, height);
861#else
862    char cmd[256];
863    snprintf(cmd, sizeof(cmd), "nv>legend %s", name);
864    writePPM(g_fdOut, cmd, imgData->GetPointer(0), width, height);
865#endif
866
867    return TCL_OK;
868}
869
870static int
871PseudoColorAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
872               Tcl_Obj *const *objv)
873{
874    if (objc == 3) {
875        const char *name = Tcl_GetString(objv[2]);
876        g_renderer->addPseudoColor(name);
877    } else {
878        g_renderer->addPseudoColor("all");
879    }
880    return TCL_OK;
881}
882
883static int
884PseudoColorColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
885                      Tcl_Obj *const *objv)
886{
887    const char *colorMapName = Tcl_GetString(objv[2]);
888    if (objc == 4) {
889        const char *dataSetName = Tcl_GetString(objv[3]);
890        g_renderer->setPseudoColorColorMap(dataSetName, colorMapName);
891    } else {
892        g_renderer->setPseudoColorColorMap("all", colorMapName);
893    }
894    return TCL_OK;
895}
896
897static int
898PseudoColorDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
899                  Tcl_Obj *const *objv)
900{
901    if (objc == 3) {
902        const char *name = Tcl_GetString(objv[2]);
903        g_renderer->deletePseudoColor(name);
904    } else {
905        g_renderer->deletePseudoColor("all");
906    }
907    return TCL_OK;
908}
909
910static int
911PseudoColorEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc,
912                            Tcl_Obj *const *objv)
913{
914    bool state;
915    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
916        return TCL_ERROR;
917    }
918    if (objc == 4) {
919        const char *name = Tcl_GetString(objv[3]);
920        g_renderer->setPseudoColorEdgeVisibility(name, state);
921    } else {
922        g_renderer->setPseudoColorEdgeVisibility("all", state);
923    }
924    return TCL_OK;
925}
926
927static int
928PseudoColorLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
929                      Tcl_Obj *const *objv)
930{
931    bool state;
932    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
933        return TCL_ERROR;
934    }
935    if (objc == 4) {
936        const char *name = Tcl_GetString(objv[3]);
937        g_renderer->setPseudoColorLighting(name, state);
938    } else {
939        g_renderer->setPseudoColorLighting("all", state);
940    }
941    return TCL_OK;
942}
943
944static int
945PseudoColorLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
946                       Tcl_Obj *const *objv)
947{
948    float color[3];
949    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
950        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
951        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
952        return TCL_ERROR;
953    }
954    if (objc == 6) {
955        const char *name = Tcl_GetString(objv[5]);
956        g_renderer->setPseudoColorEdgeColor(name, color);
957    } else {
958        g_renderer->setPseudoColorEdgeColor("all", color);
959    }
960    return TCL_OK;
961}
962
963static int
964PseudoColorLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
965                       Tcl_Obj *const *objv)
966{
967    float width;
968    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
969        return TCL_ERROR;
970    }
971    if (objc == 4) {
972        const char *name = Tcl_GetString(objv[3]);
973        g_renderer->setPseudoColorEdgeWidth(name, width);
974    } else {
975        g_renderer->setPseudoColorEdgeWidth("all", width);
976    }
977    return TCL_OK;
978}
979
980static int
981PseudoColorOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
982                     Tcl_Obj *const *objv)
983{
984    double opacity;
985    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
986        return TCL_ERROR;
987    }
988    if (objc == 4) {
989        const char *name = Tcl_GetString(objv[3]);
990        g_renderer->setPseudoColorOpacity(name, opacity);
991    } else {
992        g_renderer->setPseudoColorOpacity("all", opacity);
993    }
994    return TCL_OK;
995}
996
997static int
998PseudoColorVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
999                     Tcl_Obj *const *objv)
1000{
1001    bool state;
1002    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1003        return TCL_ERROR;
1004    }
1005    if (objc == 4) {
1006        const char *name = Tcl_GetString(objv[3]);
1007        g_renderer->setPseudoColorVisibility(name, state);
1008    } else {
1009        g_renderer->setPseudoColorVisibility("all", state);
1010    }
1011    return TCL_OK;
1012}
1013
1014static Rappture::CmdSpec pseudoColorOps[] = {
1015    {"add", 1, PseudoColorAddOp, 2, 3, "?dataSetName?"},
1016    {"colormap", 1, PseudoColorColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
1017    {"delete", 1, PseudoColorDeleteOp, 2, 3, "?dataSetName?"},
1018    {"edges", 1, PseudoColorEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
1019    {"lighting", 3, PseudoColorLightingOp, 3, 4, "bool ?dataSetName?"},
1020    {"linecolor", 5, PseudoColorLineColorOp, 5, 6, "r g b ?dataSetName?"},
1021    {"linewidth", 5, PseudoColorLineWidthOp, 3, 4, "width ?dataSetName?"},
1022    {"opacity", 1, PseudoColorOpacityOp, 3, 4, "value ?dataSetName?"},
1023    {"visible", 1, PseudoColorVisibleOp, 3, 4, "bool ?dataSetName?"}
1024};
1025static int nPseudoColorOps = NumCmdSpecs(pseudoColorOps);
1026
1027static int
1028PseudoColorCmd(ClientData clientData, Tcl_Interp *interp, int objc,
1029               Tcl_Obj *const *objv)
1030{
1031    Tcl_ObjCmdProc *proc;
1032
1033    proc = Rappture::GetOpFromObj(interp, nPseudoColorOps, pseudoColorOps,
1034                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
1035    if (proc == NULL) {
1036        return TCL_ERROR;
1037    }
1038    return (*proc) (clientData, interp, objc, objv);
1039}
1040
1041static int
1042PolyDataAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
1043              Tcl_Obj *const *objv)
1044{
1045    if (objc == 3) {
1046        const char *name = Tcl_GetString(objv[2]);
1047        g_renderer->addPolyData(name);
1048    } else {
1049        g_renderer->addPolyData("all");
1050    }
1051    return TCL_OK;
1052}
1053
1054static int
1055PolyDataDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
1056                 Tcl_Obj *const *objv)
1057{
1058    if (objc == 3) {
1059        const char *name = Tcl_GetString(objv[2]);
1060        g_renderer->deletePolyData(name);
1061    } else {
1062        g_renderer->deletePolyData("all");
1063    }
1064    return TCL_OK;
1065}
1066
1067static int
1068PolyDataColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
1069                Tcl_Obj *const *objv)
1070{
1071    float color[3];
1072    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
1073        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
1074        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
1075        return TCL_ERROR;
1076    }
1077    if (objc == 6) {
1078        const char *name = Tcl_GetString(objv[5]);
1079        g_renderer->setPolyDataColor(name, color);
1080    } else {
1081        g_renderer->setPolyDataColor("all", color);
1082    }
1083    return TCL_OK;
1084}
1085
1086static int
1087PolyDataEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc,
1088                         Tcl_Obj *const *objv)
1089{
1090    bool state;
1091    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1092        return TCL_ERROR;
1093    }
1094    if (objc == 4) {
1095        const char *name = Tcl_GetString(objv[3]);
1096        g_renderer->setPolyDataEdgeVisibility(name, state);
1097    } else {
1098        g_renderer->setPolyDataEdgeVisibility("all", state);
1099    }
1100    return TCL_OK;
1101}
1102
1103static int
1104PolyDataLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,
1105                   Tcl_Obj *const *objv)
1106{
1107    bool state;
1108    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1109        return TCL_ERROR;
1110    }
1111    if (objc == 4) {
1112        const char *name = Tcl_GetString(objv[3]);
1113        g_renderer->setPolyDataLighting(name, state);
1114    } else {
1115        g_renderer->setPolyDataLighting("all", state);
1116    }
1117    return TCL_OK;
1118}
1119
1120static int
1121PolyDataLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
1122                    Tcl_Obj *const *objv)
1123{
1124    float color[3];
1125    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
1126        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
1127        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
1128        return TCL_ERROR;
1129    }
1130    if (objc == 6) {
1131        const char *name = Tcl_GetString(objv[5]);
1132        g_renderer->setPolyDataEdgeColor(name, color);
1133    } else {
1134        g_renderer->setPolyDataEdgeColor("all", color);
1135    }
1136    return TCL_OK;
1137}
1138
1139static int
1140PolyDataLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
1141                    Tcl_Obj *const *objv)
1142{
1143    float width;
1144    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
1145        return TCL_ERROR;
1146    }
1147    if (objc == 4) {
1148        const char *name = Tcl_GetString(objv[3]);
1149        g_renderer->setPolyDataEdgeWidth(name, width);
1150    } else {
1151        g_renderer->setPolyDataEdgeWidth("all", width);
1152    }
1153    return TCL_OK;
1154}
1155
1156static int
1157PolyDataOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
1158                  Tcl_Obj *const *objv)
1159{
1160    double opacity;
1161    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
1162        return TCL_ERROR;
1163    }
1164    if (objc == 4) {
1165        const char *name = Tcl_GetString(objv[3]);
1166        g_renderer->setPolyDataOpacity(name, opacity);
1167    } else {
1168        g_renderer->setPolyDataOpacity("all", opacity);
1169    }
1170    return TCL_OK;
1171}
1172
1173static int
1174PolyDataVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
1175                  Tcl_Obj *const *objv)
1176{
1177    bool state;
1178    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1179        return TCL_ERROR;
1180    }
1181    if (objc == 4) {
1182        const char *name = Tcl_GetString(objv[3]);
1183        g_renderer->setPolyDataVisibility(name, state);
1184    } else {
1185        g_renderer->setPolyDataVisibility("all", state);
1186    }
1187    return TCL_OK;
1188}
1189
1190static int
1191PolyDataWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc,
1192                    Tcl_Obj *const *objv)
1193{
1194    bool state;
1195    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
1196        return TCL_ERROR;
1197    }
1198    if (objc == 4) {
1199        const char *name = Tcl_GetString(objv[3]);
1200        g_renderer->setPolyDataWireframe(name, state);
1201    } else {
1202        g_renderer->setPolyDataWireframe("all", state);
1203    }
1204    return TCL_OK;
1205}
1206
1207static Rappture::CmdSpec polyDataOps[] = {
1208    {"add", 1, PolyDataAddOp, 2, 3, "?dataSetName?"},
1209    {"color", 1, PolyDataColorOp, 5, 6, "r g b ?dataSetName?"},
1210    {"delete", 1, PolyDataDeleteOp, 2, 3, "?dataSetName?"},
1211    {"edges", 1, PolyDataEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
1212    {"lighting", 3, PolyDataLightingOp, 3, 4, "bool ?dataSetName?"},
1213    {"linecolor", 5, PolyDataLineColorOp, 5, 6, "r g b ?dataSetName?"},
1214    {"linewidth", 5, PolyDataLineWidthOp, 3, 4, "width ?dataSetName?"},
1215    {"opacity", 1, PolyDataOpacityOp, 3, 4, "value ?dataSetName?"},
1216    {"visible", 1, PolyDataVisibleOp, 3, 4, "bool ?dataSetName?"},
1217    {"wireframe", 1, PolyDataWireframeOp, 3, 4, "bool ?dataSetName?"}
1218};
1219static int nPolyDataOps = NumCmdSpecs(polyDataOps);
1220
1221static int
1222PolyDataCmd(ClientData clientData, Tcl_Interp *interp, int objc,
1223            Tcl_Obj *const *objv)
1224{
1225    Tcl_ObjCmdProc *proc;
1226
1227    proc = Rappture::GetOpFromObj(interp, nPolyDataOps, polyDataOps,
1228                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
1229    if (proc == NULL) {
1230        return TCL_ERROR;
1231    }
1232    return (*proc) (clientData, interp, objc, objv);
1233}
1234
1235static int
1236ScreenBgColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
1237                Tcl_Obj *const *objv)
1238{
1239    float color[3];
1240
1241    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
1242        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
1243        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
1244        return TCL_ERROR;
1245    }
1246
1247    g_renderer->setBackgroundColor(color);
1248    return TCL_OK;
1249}
1250
1251static int
1252ScreenSizeOp(ClientData clientData, Tcl_Interp *interp, int objc,
1253             Tcl_Obj *const *objv)
1254{
1255    int width, height;
1256
1257    if (Tcl_GetIntFromObj(interp, objv[2], &width) != TCL_OK ||
1258        Tcl_GetIntFromObj(interp, objv[3], &height) != TCL_OK) {
1259        return TCL_ERROR;
1260    }
1261
1262    g_renderer->setWindowSize(width, height);
1263    return TCL_OK;
1264}
1265
1266static Rappture::CmdSpec screenOps[] = {
1267    {"bgcolor", 1, ScreenBgColorOp, 5, 5, "r g b"},
1268    {"size", 1, ScreenSizeOp, 4, 4, "width height"}
1269};
1270static int nScreenOps = NumCmdSpecs(screenOps);
1271
1272static int
1273ScreenCmd(ClientData clientData, Tcl_Interp *interp, int objc,
1274          Tcl_Obj *const *objv)
1275{
1276    Tcl_ObjCmdProc *proc;
1277
1278    proc = Rappture::GetOpFromObj(interp, nScreenOps, screenOps,
1279                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
1280    if (proc == NULL) {
1281        return TCL_ERROR;
1282    }
1283    return (*proc) (clientData, interp, objc, objv);
1284}
1285
1286/**
1287 * \brief Execute commands from client in Tcl interpreter
1288 */
1289int
1290Rappture::VtkVis::processCommands(Tcl_Interp *interp, FILE *fin, FILE *fout)
1291{
1292    Tcl_DString cmdbuffer;
1293    Tcl_DStringInit(&cmdbuffer);
1294
1295    int fdIn = fileno(fin);
1296    int fdOut = fileno(fout);
1297    int flags = fcntl(fdIn, F_GETFL, 0);
1298    fcntl(fdIn, F_SETFL, flags & ~O_NONBLOCK);
1299
1300    int status = TCL_OK;
1301    int nCommands = 0;
1302    bool isComplete = false;
1303    while ((!feof(fin)) && (status == TCL_OK)) {
1304        while (!feof(fin)) {
1305            int c = fgetc(fin);
1306            if (c <= 0) {
1307                if (errno == EWOULDBLOCK) {
1308                    break;
1309                }
1310                if (feof(fin))
1311                    return 1;
1312                else
1313                    return c;
1314            }
1315            char ch = (char)c;
1316            Tcl_DStringAppend(&cmdbuffer, &ch, 1);
1317            if (ch == '\n') {
1318                isComplete = Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer));
1319                if (isComplete) {
1320                    break;
1321                }
1322            }
1323        }
1324        // no command? then we're done for now
1325        if (Tcl_DStringLength(&cmdbuffer) == 0) {
1326            break;
1327        }
1328        if (isComplete) {
1329            // back to original flags during command evaluation...
1330            fcntl(fdIn, F_SETFL, flags & ~O_NONBLOCK);
1331            TRACE("command: '%s'", Tcl_DStringValue(&cmdbuffer));
1332            status = ExecuteCommand(interp, &cmdbuffer);
1333            // non-blocking for next read -- we might not get anything
1334            fcntl(fdIn, F_SETFL, flags | O_NONBLOCK);
1335            isComplete = false;
1336            nCommands++;
1337        }
1338    }
1339    fcntl(fdIn, F_SETFL, flags);
1340
1341    if (status != TCL_OK) {
1342        const char *string;
1343        int nBytes;
1344
1345        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
1346        TRACE("ERROR errorInfo=(%s)", string);
1347
1348        nBytes = strlen(string);
1349        struct iovec iov[3];
1350        iov[0].iov_base = (char *)"VtkVis Server Error: ";
1351        iov[0].iov_len = strlen((char *)iov[0].iov_base);
1352        iov[1].iov_base = (char *)string;
1353        iov[1].iov_len = nBytes;
1354        iov[2].iov_base = (char *)"\n";
1355        iov[2].iov_len = 1;
1356        if (writev(fdOut, iov, 3) < 0) {
1357            ERROR("write failed: %s", strerror(errno));
1358        }
1359        return 0;
1360    }
1361
1362    return 1;
1363}
1364
1365/**
1366 * \brief Create Tcl interpreter and add commands
1367 *
1368 * \return The initialized Tcl interpreter
1369 */
1370Tcl_Interp *
1371Rappture::VtkVis::initTcl()
1372{
1373    Tcl_Interp *interp;
1374    interp = Tcl_CreateInterp();
1375    /*
1376    Tcl_MakeSafe(interp);
1377    */
1378    Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        NULL, NULL);
1379    Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      NULL, NULL);
1380    Tcl_CreateObjCommand(interp, "colormap",    ColorMapCmd,    NULL, NULL);
1381    Tcl_CreateObjCommand(interp, "contour2d",   Contour2DCmd,   NULL, NULL);
1382    Tcl_CreateObjCommand(interp, "dataset",     DataSetCmd,     NULL, NULL);
1383    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      NULL, NULL);
1384    Tcl_CreateObjCommand(interp, "polydata",    PolyDataCmd,    NULL, NULL);
1385    Tcl_CreateObjCommand(interp, "pseudocolor", PseudoColorCmd, NULL, NULL);
1386    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      NULL, NULL);
1387    return interp;
1388}
Note: See TracBrowser for help on using the repository browser.