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

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

Fix crash on deleting dataset (was indexing past end of argument array)

  • Property svn:eol-style set to native
File size: 22.9 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
62AxisCmd(ClientData clientData, Tcl_Interp *interp, int objc,
63        Tcl_Obj *const *objv)
64{
65    if (objc < 3) {
66        Tcl_AppendResult(interp, "wrong # args: should be \"",
67                Tcl_GetString(objv[0]), " visible bool\"", (char*)NULL);
68        return TCL_ERROR;
69    }
70    const char *string = Tcl_GetString(objv[1]);
71    char c = string[0];
72    if ((c == 'v') && (strcmp(string, "visible") == 0)) {
73        bool visible;
74
75        if (GetBooleanFromObj(interp, objv[2], &visible) != TCL_OK) {
76            return TCL_ERROR;
77        }
78
79        g_renderer->setAxesVisibility(visible);
80    } else {
81        Tcl_AppendResult(interp, "bad axis option \"", string,
82                         "\": should be visible", (char*)NULL);
83        return TCL_ERROR;
84    }
85    return TCL_OK;
86}
87
88static int
89CameraCmd(ClientData clientData, Tcl_Interp *interp, int objc,
90          Tcl_Obj *const *objv)
91{
92    if (objc < 6) {
93        Tcl_AppendResult(interp, "wrong # args: should be \"",
94                Tcl_GetString(objv[0]), " ortho x y width height\"", (char*)NULL);
95        return TCL_ERROR;
96    }
97    const char *string = Tcl_GetString(objv[1]);
98    char c = string[0];
99    if ((c == 'o') && (strcmp(string, "ortho") == 0)) {
100        float x, y, width, height;
101
102        if (GetFloatFromObj(interp, objv[2], &x) != TCL_OK ||
103            GetFloatFromObj(interp, objv[3], &y) != TCL_OK ||
104            GetFloatFromObj(interp, objv[4], &width) != TCL_OK ||
105            GetFloatFromObj(interp, objv[5], &height) != TCL_OK) {
106            return TCL_ERROR;
107        }
108
109        g_renderer->setZoomRegion(x, y, width, height);
110    } else {
111        Tcl_AppendResult(interp, "bad camera option \"", string,
112                         "\": should be ortho", (char*)NULL);
113        return TCL_ERROR;
114    }
115    return TCL_OK;
116}
117
118static int
119ColorMapAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
120              Tcl_Obj *const *objv)
121{
122    const char *name = Tcl_GetString(objv[2]);
123    int cmapc;
124    Tcl_Obj **cmapv = NULL;
125
126    if (Tcl_ListObjGetElements(interp, objv[3], &cmapc, &cmapv) != TCL_OK) {
127        return TCL_ERROR;
128    }
129    if ((cmapc % 4) != 0) {
130        Tcl_AppendResult(interp, "wrong # elements is colormap: should be ",
131                         "{ r g b a ... }", (char*)NULL);
132        return TCL_ERROR;
133    }
134    int numEntries = cmapc / 4;
135    vtkLookupTable *lut = vtkLookupTable::New();
136    lut->Allocate(numEntries, numEntries);
137    for (int i = 0; i < cmapc; i += 4) {
138        double val[4];
139        for (int j = 0; j < 4; j++) {
140            if (Tcl_GetDoubleFromObj(interp, cmapv[i+j], &val[j]) != TCL_OK) {
141                return TCL_ERROR;
142            }
143            if ((val[j] < 0.0) || (val[j] > 1.0)) {
144                Tcl_AppendResult(interp, "bad colormap value \"",
145                                 Tcl_GetString(cmapv[i+j]),
146                                 "\": should be in the range [0,1]", (char*)NULL);
147                return TCL_ERROR;
148            }
149        }
150        lut->SetTableValue(i/4, val);
151    }
152    g_renderer->addColorMap(name, lut);
153    return TCL_OK;
154}
155
156static int
157ColorMapDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
158                 Tcl_Obj *const *objv)
159{
160    const char *name = Tcl_GetString(objv[2]);
161    g_renderer->deleteColorMap(name);
162    return TCL_OK;
163}
164
165static Rappture::CmdSpec colorMapOps[] = {
166    {"add", 1, ColorMapAddOp, 4, 4, "colorMapName map"},
167    {"delete", 1, ColorMapDeleteOp, 3, 3, "colorMapName"}
168};
169static int nColorMapOps = NumCmdSpecs(colorMapOps);
170
171static int
172ColorMapCmd(ClientData clientData, Tcl_Interp *interp, int objc,
173            Tcl_Obj *const *objv)
174{
175    Tcl_ObjCmdProc *proc;
176
177    proc = Rappture::GetOpFromObj(interp, nColorMapOps, colorMapOps,
178                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
179    if (proc == NULL) {
180        return TCL_ERROR;
181    }
182    return (*proc) (clientData, interp, objc, objv);
183}
184
185static int
186Contour2DAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc,
187                          Tcl_Obj *const *objv)
188{
189    const char *name = Tcl_GetString(objv[4]);
190    g_renderer->addContour2D(name);
191    std::vector<double> contourList;
192
193    int clistc;
194    Tcl_Obj **clistv;
195
196    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
197        return TCL_ERROR;
198    }
199
200    for (int i = 0; i < clistc; i++) {
201        double val;
202        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
203            return TCL_ERROR;
204        }
205        contourList.push_back(val);
206    }
207
208    g_renderer->setContourList(name, contourList);
209    return TCL_OK;
210}
211
212static int
213Contour2DAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc,
214                          Tcl_Obj *const *objv)
215{
216    const char *name = Tcl_GetString(objv[4]);
217    g_renderer->addContour2D(name);
218    int numContours;
219    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
220        return TCL_ERROR;
221    }
222    g_renderer->setContours(name, numContours);
223    return TCL_OK;
224}
225
226static Rappture::CmdSpec contour2dAddOps[] = {
227    {"contourlist", 1, Contour2DAddContourListOp, 5, 5, "contourList dataSetName"},
228    {"numcontours", 1, Contour2DAddNumContoursOp, 5, 5, "numContours dataSetName"}
229};
230static int nContour2dAddOps = NumCmdSpecs(contour2dAddOps);
231
232static int
233Contour2DAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
234               Tcl_Obj *const *objv)
235{
236    Tcl_ObjCmdProc *proc;
237
238    proc = Rappture::GetOpFromObj(interp, nContour2dAddOps, contour2dAddOps,
239                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
240    if (proc == NULL) {
241        return TCL_ERROR;
242    }
243    return (*proc) (clientData, interp, objc, objv);
244}
245
246static int
247Contour2DDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
248                  Tcl_Obj *const *objv)
249{
250    const char *name = Tcl_GetString(objv[2]);
251    g_renderer->deleteContour2D(name);
252    return TCL_OK;
253}
254
255static int
256Contour2DLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
257                     Tcl_Obj *const *objv)
258{
259    const char *name = Tcl_GetString(objv[5]);
260    float color[3];
261    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
262        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
263        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
264        return TCL_ERROR;
265    }
266    g_renderer->setContourEdgeColor(name, color);
267    return TCL_OK;
268}
269
270static int
271Contour2DLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc,
272                     Tcl_Obj *const *objv)
273{
274    const char *name = Tcl_GetString(objv[3]);
275    float width;
276    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
277        return TCL_ERROR;
278    }
279    g_renderer->setContourEdgeWidth(name, width);
280    return TCL_OK;
281}
282
283static int
284Contour2DVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
285                   Tcl_Obj *const *objv)
286{
287    const char *name = Tcl_GetString(objv[3]);
288    bool state;
289    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
290        return TCL_ERROR;
291    }
292    g_renderer->setContourVisibility(name, state);
293    return TCL_OK;
294}
295
296static Rappture::CmdSpec contour2dOps[] = {
297    {"add", 1, Contour2DAddOp, 5, 5, "oper value dataSetName"},
298    {"delete", 1, Contour2DDeleteOp, 3, 3, "dataSetName"},
299    {"linecolor", 5, Contour2DLineColorOp, 6, 6, "r g b dataSetName"},
300    {"linewidth", 5, Contour2DLineWidthOp, 4, 4, "width dataSetName"},
301    {"visible", 1, Contour2DVisibleOp, 4, 4, "bool dataSetName"},
302};
303static int nContour2dOps = NumCmdSpecs(contour2dOps);
304
305static int
306Contour2DCmd(ClientData clientData, Tcl_Interp *interp, int objc,
307             Tcl_Obj *const *objv)
308{
309    Tcl_ObjCmdProc *proc;
310
311    proc = Rappture::GetOpFromObj(interp, nContour2dOps, contour2dOps,
312                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
313    if (proc == NULL) {
314        return TCL_ERROR;
315    }
316    return (*proc) (clientData, interp, objc, objv);
317}
318
319static int
320DataSetAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
321             Tcl_Obj *const *objv)
322{
323    const char *name = Tcl_GetString(objv[2]);
324    const char *string = Tcl_GetString(objv[3]);
325    char c = string[0];
326    if ((c != 'd') || (strcmp(string, "data") != 0)) {
327        Tcl_AppendResult(interp, "bad dataset option \"", string,
328                         "\": should be data", (char*)NULL);
329        return TCL_ERROR;
330    }
331    string = Tcl_GetString(objv[4]);
332    c = string[0];
333    if ((c != 'f') || (strcmp(string, "follows") != 0)) {
334        Tcl_AppendResult(interp, "bad dataset option \"", string,
335                         "\": should be follows", (char*)NULL);
336        return TCL_ERROR;
337    }
338    int nbytes = 0;
339    if (Tcl_GetIntFromObj(interp, objv[5], &nbytes) != TCL_OK ||
340        nbytes < 0) {
341        return TCL_ERROR;
342    }
343    char *data = (char *)malloc(nbytes);
344#ifdef notdef
345    size_t ofs = 0;
346    ssize_t bytesRead = 0;
347    while ((bytesRead = read(g_fdIn, data + ofs, nbytes - ofs)) > 0) {
348        ofs += bytesRead;
349        if (ofs == nbytes)
350            break;
351    }
352    TRACE("bytesRead: %d", ofs);
353    if (bytesRead < 0) {
354        return TCL_ERROR;
355    }
356#else
357    size_t bytesRead = fread(data, 1, nbytes, g_fIn);
358    TRACE("bytesRead: %d '%c'", bytesRead, data[0]);
359    if (bytesRead < (size_t)nbytes) {
360        return TCL_ERROR;
361    }
362#endif
363    g_renderer->addDataSet(name);
364    g_renderer->setData(name, data, nbytes);
365    free(data);
366    return TCL_OK;
367}
368
369static int
370DataSetDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
371                Tcl_Obj *const *objv)
372{
373    const char *name = Tcl_GetString(objv[2]);
374    g_renderer->deleteDataSet(name);
375    return TCL_OK;
376}
377
378static int
379DataSetGetValuePixelOp(ClientData clientData, Tcl_Interp *interp, int objc,
380                       Tcl_Obj *const *objv)
381{
382    const char *name = Tcl_GetString(objv[5]);
383    int x, y;
384    if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK ||
385        Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
386        return TCL_ERROR;
387    }
388    double value = g_renderer->getDataValueAtPixel(name, x, y);
389    char buf[128];
390    snprintf(buf, sizeof(buf), "nv>dataset value pixel %d %d %.12e", x, y, value);
391    ssize_t bytesWritten;
392    size_t len = strlen(buf);
393    size_t ofs = 0;
394    while ((bytesWritten = write(g_fdOut, buf + ofs, len - ofs)) > 0) {
395        ofs += bytesWritten;
396        if (ofs == len)
397            break;
398    }
399    if (bytesWritten < 0) {
400        return TCL_ERROR;
401    }
402    return TCL_OK;
403}
404
405static int
406DataSetGetValueWorldOp(ClientData clientData, Tcl_Interp *interp, int objc,
407                       Tcl_Obj *const *objv)
408{
409    const char *name = Tcl_GetString(objv[6]);
410    double x, y, z;
411    if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK ||
412        Tcl_GetDoubleFromObj(interp, objv[4], &y) != TCL_OK ||
413        Tcl_GetDoubleFromObj(interp, objv[5], &z) != TCL_OK) {
414        return TCL_ERROR;
415    }
416    double value = g_renderer->getDataValue(name, x, y, z);
417    char buf[128];
418    snprintf(buf, sizeof(buf), "nv>dataset value world %.12e %.12e %.12e %.12e", x, y, z, value);
419    ssize_t bytesWritten;
420    size_t len = strlen(buf);
421    size_t ofs = 0;
422    while ((bytesWritten = write(g_fdOut, buf + ofs, len - ofs)) > 0) {
423        ofs += bytesWritten;
424        if (ofs == len)
425            break;
426    }
427    if (bytesWritten < 0) {
428        return TCL_ERROR;
429    }
430    return TCL_OK;
431}
432
433static Rappture::CmdSpec dataSetGetValueOps[] = {
434    {"pixel", 1, DataSetGetValuePixelOp, 6, 6, "x y dataSetName"},
435    {"world", 1, DataSetGetValueWorldOp, 7, 7, "x y z dataSetName"}
436};
437static int nDataSetGetValueOps = NumCmdSpecs(dataSetGetValueOps);
438
439static int
440DataSetGetValueOp(ClientData clientData, Tcl_Interp *interp, int objc,
441                  Tcl_Obj *const *objv)
442{
443    Tcl_ObjCmdProc *proc;
444
445    proc = Rappture::GetOpFromObj(interp, nDataSetGetValueOps, dataSetGetValueOps,
446                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
447    if (proc == NULL) {
448        return TCL_ERROR;
449    }
450    return (*proc) (clientData, interp, objc, objv);
451}
452
453static int
454DataSetOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc,
455                 Tcl_Obj *const *objv)
456{
457    const char *name = Tcl_GetString(objv[3]);
458    double opacity;
459    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
460        return TCL_ERROR;
461    }
462    g_renderer->setOpacity(name, opacity);
463    return TCL_OK;
464}
465
466static int
467DataSetVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
468                 Tcl_Obj *const *objv)
469{
470    const char *name = Tcl_GetString(objv[3]);
471    bool state;
472    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
473        return TCL_ERROR;
474    }
475    g_renderer->setVisibility(name, state);
476    return TCL_OK;
477}
478
479static Rappture::CmdSpec dataSetOps[] = {
480    {"add", 1, DataSetAddOp, 6, 6, "name data follows nBytes"},
481    {"delete", 1, DataSetDeleteOp, 3, 3, "name"},
482    {"getvalue", 1, DataSetGetValueOp, 6, 7, "oper x y ?z? name"},
483    {"opacity", 1, DataSetOpacityOp, 4, 4, "value name"},
484    {"visible", 1, DataSetVisibleOp, 4, 4, "bool name"}
485};
486static int nDataSetOps = NumCmdSpecs(dataSetOps);
487
488static int
489DataSetCmd(ClientData clientData, Tcl_Interp *interp, int objc,
490           Tcl_Obj *const *objv)
491{
492    Tcl_ObjCmdProc *proc;
493
494    proc = Rappture::GetOpFromObj(interp, nDataSetOps, dataSetOps,
495                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
496    if (proc == NULL) {
497        return TCL_ERROR;
498    }
499    return (*proc) (clientData, interp, objc, objv);
500}
501
502static int
503GridCmd(ClientData clientData, Tcl_Interp *interp, int objc,
504        Tcl_Obj *const *objv)
505{
506    if (objc < 3) {
507        Tcl_AppendResult(interp, "wrong # args: should be \"",
508                Tcl_GetString(objv[0]), " visible bool\"", (char*)NULL);
509        return TCL_ERROR;
510    }
511    const char *string = Tcl_GetString(objv[1]);
512    char c = string[0];
513    if ((c == 'v') && (strcmp(string, "visible") == 0)) {
514        bool visible;
515
516        if (GetBooleanFromObj(interp, objv[2], &visible) != TCL_OK) {
517            return TCL_ERROR;
518        }
519        Tcl_AppendResult(interp, "Command not yet implemented", (char*)NULL);
520        return TCL_ERROR; // TODO: handle command
521    } else {
522        Tcl_AppendResult(interp, "bad grid option \"", string,
523                         "\": should be visible", (char*)NULL);
524        return TCL_ERROR;
525    }
526    return TCL_OK;
527}
528
529static int
530LegendCmd(ClientData clientData, Tcl_Interp *interp, int objc,
531          Tcl_Obj *const *objv)
532{
533    if (objc < 4) {
534        Tcl_AppendResult(interp, "wrong # args: should be \"",
535                Tcl_GetString(objv[0]), " colormapName title width height\"", (char*)NULL);
536        return TCL_ERROR;
537    }
538    const char *name = Tcl_GetString(objv[1]);
539    const char *title = Tcl_GetString(objv[2]);
540    int width, height;
541
542    if (Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK ||
543        Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK) {
544        return TCL_ERROR;
545    }
546
547    vtkSmartPointer<vtkUnsignedCharArray> imgData =
548        vtkSmartPointer<vtkUnsignedCharArray>::New();
549
550    g_renderer->renderColorMap(name, title, width, height, imgData);
551
552#ifdef DEBUG
553    writeTGAFile("/tmp/legend.tga", imgData->GetPointer(0), width, height);
554#else
555    char cmd[256];
556    snprintf(cmd, sizeof(cmd), "nv>legend %s", name);
557    writePPM(g_fdOut, cmd, imgData->GetPointer(0), width, height);
558#endif
559
560    return TCL_OK;
561}
562
563static int
564PseudoColorAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
565               Tcl_Obj *const *objv)
566{
567    const char *name = Tcl_GetString(objv[2]);
568    g_renderer->addPseudoColor(name);
569    return TCL_OK;
570}
571
572static int
573PseudoColorColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc,
574                      Tcl_Obj *const *objv)
575{
576    const char *colorMapName = Tcl_GetString(objv[2]);
577    const char *dataSetName = Tcl_GetString(objv[3]);
578    g_renderer->setPseudoColorColorMap(dataSetName, colorMapName);
579    return TCL_OK;
580}
581
582static int
583PseudoColorDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
584                  Tcl_Obj *const *objv)
585{
586    const char *name = Tcl_GetString(objv[2]);
587    g_renderer->deletePseudoColor(name);
588    return TCL_OK;
589}
590
591static int
592PseudoColorVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
593                     Tcl_Obj *const *objv)
594{
595    const char *name = Tcl_GetString(objv[3]);
596    bool state;
597    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
598        return TCL_ERROR;
599    }
600    g_renderer->setPseudoColorVisibility(name, state);
601    return TCL_OK;
602}
603
604static Rappture::CmdSpec pseudoColorOps[] = {
605    {"add", 1, PseudoColorAddOp, 3, 3, "dataSetName"},
606    {"colormap", 1, PseudoColorColorMapOp, 4, 4, "colorMapName dataSetName"},
607    {"delete", 1, PseudoColorDeleteOp, 3, 3, "dataSetName"},
608    {"visible", 1, PseudoColorVisibleOp, 4, 4, "bool dataSetName"}
609};
610static int nPseudoColorOps = NumCmdSpecs(pseudoColorOps);
611
612static int
613PseudoColorCmd(ClientData clientData, Tcl_Interp *interp, int objc,
614               Tcl_Obj *const *objv)
615{
616    Tcl_ObjCmdProc *proc;
617
618    proc = Rappture::GetOpFromObj(interp, nPseudoColorOps, pseudoColorOps,
619                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
620    if (proc == NULL) {
621        return TCL_ERROR;
622    }
623    return (*proc) (clientData, interp, objc, objv);
624}
625
626static int
627ScreenBgColorOp(ClientData clientData, Tcl_Interp *interp, int objc,
628                Tcl_Obj *const *objv)
629{
630    float color[3];
631
632    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
633        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
634        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
635        return TCL_ERROR;
636    }
637
638    g_renderer->setBackgroundColor(color);
639    return TCL_OK;
640}
641
642static int
643ScreenSizeOp(ClientData clientData, Tcl_Interp *interp, int objc,
644             Tcl_Obj *const *objv)
645{
646    int width, height;
647
648    if (Tcl_GetIntFromObj(interp, objv[2], &width) != TCL_OK ||
649        Tcl_GetIntFromObj(interp, objv[3], &height) != TCL_OK) {
650        return TCL_ERROR;
651    }
652
653    g_renderer->setWindowSize(width, height);
654    return TCL_OK;
655}
656
657static Rappture::CmdSpec screenOps[] = {
658    {"bgcolor", 1, ScreenBgColorOp, 5, 5, "r g b"},
659    {"size", 1, ScreenSizeOp, 4, 4, "width height"}
660};
661static int nScreenOps = NumCmdSpecs(screenOps);
662
663static int
664ScreenCmd(ClientData clientData, Tcl_Interp *interp, int objc,
665          Tcl_Obj *const *objv)
666{
667    Tcl_ObjCmdProc *proc;
668
669    proc = Rappture::GetOpFromObj(interp, nScreenOps, screenOps,
670                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
671    if (proc == NULL) {
672        return TCL_ERROR;
673    }
674    return (*proc) (clientData, interp, objc, objv);
675}
676
677/**
678 * \brief Execute commands from client in Tcl interpreter
679 */
680int
681Rappture::VtkVis::processCommands(Tcl_Interp *interp, FILE *fin, FILE *fout)
682{
683    Tcl_DString cmdbuffer;
684    Tcl_DStringInit(&cmdbuffer);
685
686    int fdIn = fileno(fin);
687    int fdOut = fileno(fout);
688    int flags = fcntl(fdIn, F_GETFL, 0);
689    fcntl(fdIn, F_SETFL, flags & ~O_NONBLOCK);
690
691    int status = TCL_OK;
692    int nCommands = 0;
693    bool isComplete = false;
694    while ((!feof(fin)) && (status == TCL_OK)) {
695        while (!feof(fin)) {
696            int c = fgetc(fin);
697            if (c <= 0) {
698                if (errno == EWOULDBLOCK) {
699                    break;
700                }
701                if (feof(fin))
702                    return 1;
703                else
704                    return c;
705            }
706            char ch = (char)c;
707            Tcl_DStringAppend(&cmdbuffer, &ch, 1);
708            if (ch == '\n') {
709                isComplete = Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer));
710                if (isComplete) {
711                    break;
712                }
713            }
714        }
715        // no command? then we're done for now
716        if (Tcl_DStringLength(&cmdbuffer) == 0) {
717            break;
718        }
719        if (isComplete) {
720            // back to original flags during command evaluation...
721            fcntl(fdIn, F_SETFL, flags & ~O_NONBLOCK);
722            TRACE("command: '%s'", Tcl_DStringValue(&cmdbuffer));
723            status = ExecuteCommand(interp, &cmdbuffer);
724            // non-blocking for next read -- we might not get anything
725            fcntl(fdIn, F_SETFL, flags | O_NONBLOCK);
726            isComplete = false;
727            nCommands++;
728        }
729    }
730    fcntl(fdIn, F_SETFL, flags);
731
732    if (status != TCL_OK) {
733        const char *string;
734        int nBytes;
735
736        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
737        TRACE("ERROR errorInfo=(%s)", string);
738
739        nBytes = strlen(string);
740        struct iovec iov[3];
741        iov[0].iov_base = (char *)"NanoVis Server Error: ";
742        iov[0].iov_len = strlen((char *)iov[0].iov_base);
743        iov[1].iov_base = (char *)string;
744        iov[1].iov_len = nBytes;
745        iov[2].iov_base = (char *)"\n";
746        iov[2].iov_len = 1;
747        if (writev(fdOut, iov, 3) < 0) {
748            ERROR("write failed: %s", strerror(errno));
749        }
750        return 0;
751    }
752
753    return 1;
754}
755
756/**
757 * \brief Create Tcl interpreter and add commands
758 *
759 * \return The initialized Tcl interpreter
760 */
761Tcl_Interp *
762Rappture::VtkVis::initTcl()
763{
764    Tcl_Interp *interp;
765    interp = Tcl_CreateInterp();
766    /*
767    Tcl_MakeSafe(interp);
768    */
769    Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        NULL, NULL);
770    Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      NULL, NULL);
771    Tcl_CreateObjCommand(interp, "colormap",    ColorMapCmd,    NULL, NULL);
772    Tcl_CreateObjCommand(interp, "contour2d",   Contour2DCmd,   NULL, NULL);
773    Tcl_CreateObjCommand(interp, "dataset",     DataSetCmd,     NULL, NULL);
774    Tcl_CreateObjCommand(interp, "grid",        GridCmd,        NULL, NULL);
775    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      NULL, NULL);
776    Tcl_CreateObjCommand(interp, "pseudocolor", PseudoColorCmd, NULL, NULL);
777    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      NULL, NULL);
778    return interp;
779}
Note: See TracBrowser for help on using the repository browser.