source: trunk/packages/vizservers/nanovis/FlowCmds.cpp @ 1380

Last change on this file since 1380 was 1380, checked in by gah, 15 years ago
File size: 35.3 KB
Line 
1
2/*
3 * ----------------------------------------------------------------------
4 * Command.cpp
5 *
6 *      This modules creates the Tcl interface to the nanovis server.  The
7 *      communication protocol of the server is the Tcl language.  Commands
8 *      given to the server by clients are executed in a safe interpreter and
9 *      the resulting image rendered offscreen is returned as BMP-formatted
10 *      image data.
11 *
12 * ======================================================================
13 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
14 *           Michael McLennan <mmclennan@purdue.edu>
15 *           Purdue Rendering and Perceptualization Lab (PURPL)
16 *
17 *  Copyright (c) 2004-2006  Purdue Research Foundation
18 *
19 *  See the file "license.terms" for information on usage and
20 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
21 * ======================================================================
22 */
23
24/*
25 * TODO:  In no particular order...
26 *        x Convert to Tcl_CmdObj interface. (done)
27 *        o Use Tcl command option parser to reduce size of procedures, remove
28 *          lots of extra error checking code. (almost there)
29 *        o Convert GetVolumeIndices to GetVolumes.  Goal is to remove
30 *          all references of Nanovis::volume[] from this file.  Don't
31 *          want to know how volumes are stored. Same for heightmaps.
32 *        o Rationalize volume id scheme. Right now it's the index in
33 *          the vector. 1) Use a list instead of a vector. 2) carry
34 *          an id field that's a number that gets incremented each new volume.
35 *        x Create R2, matrix, etc. libraries. (done)
36 *        o Add bookkeeping for volumes, heightmaps, flows, etc. to track
37 *          1) id #  2) simulation # 3) include/exclude.  The include/exclude
38 *          is to indicate whether the item should contribute to the overall
39 *          limits of the axes.
40 */
41
42#include <assert.h>
43#include <stdlib.h>
44#include <tcl.h>
45#include "Switch.h"
46#include <RpField1D.h>
47#include <RpFieldRect3D.h>
48#include <RpFieldPrism3D.h>
49#include <RpEncode.h>
50#include <RpOutcome.h>
51#include <RpBuffer.h>
52#include <RpAVTranslate.h>
53
54#include "Trace.h"
55#include "Command.h"
56#include "nanovis.h"
57#include "CmdProc.h"
58#include "Nv.h"
59#include "PointSetRenderer.h"
60#include "PointSet.h"
61#include "ZincBlendeVolume.h"
62#include "NvLoadFile.h"
63#include "NvColorTableRenderer.h"
64#include "NvEventLog.h"
65#include "NvZincBlendeReconstructor.h"
66#include "VolumeInterpolator.h"
67#include "HeightMap.h"
68#include "Grid.h"
69#include "NvCamera.h"
70#include "RenderContext.h"
71#include "NvLIC.h"
72#include "Unirect.h"
73#include "FlowCmd.h"
74
75static Tcl_HashTable flowTable;
76
77static int
78GetFlowFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, FlowCmd **flowPtrPtr)
79{
80    Tcl_HashEntry *hPtr;
81    hPtr = Tcl_FindHashEntry(&flowTable, Tcl_GetString(objPtr));
82    if (hPtr == NULL) {
83        if (interp != NULL) {
84            Tcl_AppendResult(interp, "can't find a flow \"",
85                             Tcl_GetString(objPtr), "\"", (char *)NULL);
86        }
87        return TCL_ERROR;
88    }
89    *flowPtrPtr = (FlowCmd *)Tcl_GetHashValue(hPtr);
90    return TCL_OK;
91}
92
93static int
94FlowDataFileOp(ClientData clientData, Tcl_Interp *interp, int objc,
95               Tcl_Obj *const *objv)
96{
97    Rappture::Outcome context;
98
99    const char *fileName;
100    fileName = Tcl_GetString(objv[3]);
101    Trace("Flow loading data from file %s\n", fileName);
102
103    int extents;
104    if (Tcl_GetIntFromObj(interp, objv[4], &extents) != TCL_OK) {
105        return TCL_ERROR;
106    }
107    Rappture::Buffer buf;
108    if (!buf.load(context, fileName)) {
109        Tcl_AppendResult(interp, "can't load data from \"", fileName, "\": ",
110                         context.remark(), (char *)NULL);
111        return TCL_ERROR;
112    }
113
114    FlowCmd *flowPtr = (FlowCmd *)clientData;
115    if (strncmp(buf.bytes(), "<DX>", 4) == 0) {
116        Rappture::Unirect3d data;
117        if (!load_vector_stream2(context, buf.size(), (char *)buf.bytes(),
118                                 data)) {
119            Tcl_AppendResult(interp, context.remark(), (char *)NULL);
120            return TCL_ERROR;
121        }
122        flowPtr->dataPtr = &data;
123    } else if (strncmp(buf.bytes(), "<unirect3d>", 4) == 0) {
124        Rappture::Unirect3d data;
125        Tcl_CmdInfo cmdInfo;
126
127        /* Set the clientdata field of the unirect3d command to contain
128         * the local data structure. */
129        if (!Tcl_GetCommandInfo(interp, "unirect3d", &cmdInfo)) {
130            return TCL_ERROR;
131        }
132        data.extents(extents);
133        cmdInfo.objClientData = (ClientData)&data;     
134        Tcl_SetCommandInfo(interp, "unirect3d", &cmdInfo);
135        if (Tcl_Eval(interp, (const char *)buf.bytes()) != TCL_OK) {
136            return TCL_ERROR;
137        }
138        if (!data.isInitialized()) {
139            return TCL_ERROR;
140        }
141        flowPtr->dataPtr = &data;
142    }
143
144#ifdef notdef
145    flowPtr->volPtr = NanoVis::volume[NanoVis::n_volumes];
146    //
147    // BE CAREFUL:  Set the number of slices to something
148    //   slightly different for each volume.  If we have
149    //   identical volumes at exactly the same position
150    //   with exactly the same number of slices, the second
151    //   volume will overwrite the first, so the first won't
152    //   appear at all.
153    //
154    flowPtr->volPtr->set_n_slice(256-n);
155    // volPtr->set_n_slice(512-n);
156    flowPtr->volPtr->disable_cutplane(0);
157    flowPtr->volPtr->disable_cutplane(1);
158    flowPtr->volPtr->disable_cutplane(2);
159   
160    NanoVis::vol_renderer->add_volume(flowPtr->volPtr,
161        NanoVis::get_transfunc("default"));
162   
163    Trace("Flow Data move\n");
164    float dx0 = -0.5;
165    float dy0 = -0.5*flowPtr->volPtr->height/flowPtr->volPtr->width;
166    float dz0 = -0.5*flowPtr->volPtr->depth/flowPtr->volPtr->width;
167    flowPtr->volPtr->move(Vector3(dx0, dy0, dz0));
168#endif
169    return TCL_OK;
170}
171
172static int
173FlowDataFollowsOp(ClientData clientData, Tcl_Interp *interp, int objc,
174                    Tcl_Obj *const *objv)
175{
176    Rappture::Outcome context;
177
178    Trace("Flow Data Loading\n");
179
180    int nbytes;
181    if (Tcl_GetIntFromObj(interp, objv[3], &nbytes) != TCL_OK) {
182        return TCL_ERROR;
183    }
184    int extents;
185    if (Tcl_GetIntFromObj(interp, objv[4], &extents) != TCL_OK) {
186        return TCL_ERROR;
187    }
188    Rappture::Buffer buf;
189    if (GetDataStream(interp, buf, nbytes) != TCL_OK) {
190        return TCL_ERROR;
191    }
192    FlowCmd *flowPtr = (FlowCmd *)clientData;
193    if (strncmp(buf.bytes(), "<DX>", 4) == 0) {
194        if (!load_vector_stream2(context, buf.size(), (char *)buf.bytes(),
195                flowPtr)) {
196            Tcl_AppendResult(interp, context.remark(), (char *)NULL);
197            return TCL_ERROR;
198        }
199    } else if (strncmp(buf.bytes(), "<unirect3d>", 4) == 0) {
200        Rappture::Unirect3d data;
201        Tcl_CmdInfo cmdInfo;
202
203        /* Set the clientdata field of the unirect3d command to contain
204         * the local data structure. */
205        if (!Tcl_GetCommandInfo(interp, "unirect3d", &cmdInfo)) {
206            return TCL_ERROR;
207        }
208        data.extents(extents);
209        cmdInfo.objClientData = (ClientData)&data;     
210        Tcl_SetCommandInfo(interp, "unirect3d", &cmdInfo);
211        if (Tcl_Eval(interp, (const char *)buf.bytes()) != TCL_OK) {
212            return TCL_ERROR;
213        }
214        if (!data.isInitialized()) {
215            return TCL_ERROR;
216        }
217        if (!SetVectorFieldDataFromUnirect3d(context, data, flowPtr)) {
218            Tcl_AppendResult(interp, context.remark(), (char *)NULL);
219            return TCL_ERROR;
220        }
221    }
222    if (flowPtr->volPtr != NULL) {
223        delete flowPtr->volPtr;
224    }
225    #ifdef notdef
226    // FIXME: Move this to flow pending routine.
227
228    flowPtr->volPtr = NanoVis::volume[NanoVis::n_volumes];
229    //
230    // BE CAREFUL:  Set the number of slices to something
231    //   slightly different for each volume.  If we have
232    //   identical volumes at exactly the same position
233    //   with exactly the same number of slices, the second
234    //   volume will overwrite the first, so the first won't
235    //   appear at all.
236    //
237    flowPtr->volPtr->set_n_slice(256-n);
238    // volPtr->set_n_slice(512-n);
239    flowPtr->volPtr->disable_cutplane(0);
240    flowPtr->volPtr->disable_cutplane(1);
241    flowPtr->volPtr->disable_cutplane(2);
242   
243    NanoVis::vol_renderer->add_volume(flowPtr->volPtr,
244        NanoVis::get_transfunc("default"));
245   
246    Trace("Flow Data move\n");
247    float dx0 = -0.5;
248    float dy0 = -0.5*flowPtr->volPtr->height/flowPtr->volPtr->width;
249    float dz0 = -0.5*flowPtr->volPtr->depth/flowPtr->volPtr->width;
250    flowPtr->volPtr->move(Vector3(dx0, dy0, dz0));
251    #endif
252    return TCL_OK;
253}
254
255static Rappture::CmdSpec flowDataOps[] = {
256    {"file",    2, FlowDataFileOp,    5, 5, "fileName extents",},
257    {"follows", 2, FlowDataFollowsOp, 5, 5, "size extents",},
258};
259static int nFlowDataOps = NumCmdSpecs(flowDataOps);
260
261static int
262FlowDataOp(ClientData clientData, Tcl_Interp *interp, int objc,
263           Tcl_Obj *const *objv)
264{
265    Tcl_ObjCmdProc *proc;
266
267    proc = Rappture::GetOpFromObj(interp, nFlowDataOps, flowDataOps,
268                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
269    if (proc == NULL) {
270        return TCL_ERROR;
271    }
272    return (*proc) (clientData, interp, objc, objv);
273}
274
275
276static Rappture::SwitchSpec streamSwitches[] =
277{
278    {Rappture::SWITCH_BOOLEAN, "-hide", "boolean",
279        offsetof(Stream, hidden), 0},
280    {Rappture::SWITCH_FLOAT, "-position", "number",
281        offsetof(Stream, position), 0},
282    {Rappture::SWITCH_END}
283};
284
285static int
286FlowStreamConfigureOp(ClientData clientData, Tcl_Interp *interp, int objc,
287                     Tcl_Obj *const *objv)
288{
289    int axis;
290    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
291        return TCL_ERROR;
292    }
293    FlowCmd *flowPtr = (FlowCmd *)clientData;
294    Stream *streamPtr;
295    streamPtr = flowPtr->streams + axis;
296
297    if (Rappture::ParseSwitches(interp, streamSwitches, objc - 3, objv + 3,
298        streamPtr, SWITCH_DEFAULTS) < 0) {
299        return TCL_ERROR;
300    }
301    NanoVis::lic_slice_x = streamPtr->position;
302    NanoVis::licRenderer->set_axis(axis);
303    NanoVis::licRenderer->set_offset(streamPtr->position);
304    return TCL_OK;
305}
306
307static Rappture::CmdSpec flowStreamOps[] = {
308    {"configure", 1, FlowStreamConfigureOp,  5, 5, "axis ?switches?",},
309};
310
311static int nFlowStreamOps = NumCmdSpecs(flowStreamOps);
312
313static int
314FlowStreamOp(ClientData clientData, Tcl_Interp *interp, int objc,
315             Tcl_Obj *const *objv)
316{
317    Tcl_ObjCmdProc *proc;
318
319    proc = Rappture::GetOpFromObj(interp, nFlowStreamOps, flowStreamOps,
320        Rappture::CMDSPEC_ARG2, objc, objv, 0);
321    if (proc == NULL) {
322        return TCL_ERROR;
323    }
324    return (*proc) (clientData, interp, objc, objv);
325}
326
327static int
328FlowParticlesVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc,
329             Tcl_Obj *const *objv)
330{
331    bool state;
332    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
333        return TCL_ERROR;
334    }
335
336    NanoVis::particle_on = state;
337    return TCL_OK;
338}
339
340static Rappture::CmdSpec flowParticlesOps[] = {
341    {"visible",    1, FlowParticlesVisibleOp,  4, 4, "on|off",},
342};
343static int nFlowParticlesOps = NumCmdSpecs(flowParticlesOps);
344
345static int
346FlowParticlesOp(ClientData clientData, Tcl_Interp *interp, int objc,
347             Tcl_Obj *const *objv)
348{
349    Tcl_ObjCmdProc *proc;
350
351    proc = Rappture::GetOpFromObj(interp, nFlowParticlesOps, flowParticlesOps,
352                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
353    if (proc == NULL) {
354        return TCL_ERROR;
355    }
356    return (*proc) (clientData, interp, objc, objv);
357}
358
359
360static int
361FlowVectorIdOp(ClientData clientData, Tcl_Interp *interp, int objc,
362             Tcl_Obj *const *objv)
363{
364    Volume *volPtr;
365    if (GetVolumeFromObj(interp, objv[2], &volPtr) != TCL_OK) {
366        return TCL_ERROR;
367    }
368    if (NanoVis::flowVisRenderer != NULL) {
369        NanoVis::flowVisRenderer->setVectorField(volPtr->id,
370            *(volPtr->get_location()),
371            1.0f,
372            volPtr->height / (float)volPtr->width,
373            volPtr->depth  / (float)volPtr->width,
374            volPtr->wAxis.max());
375        NanoVis::initParticle();
376    }
377    if (NanoVis::licRenderer != NULL) {
378        NanoVis::licRenderer->setVectorField(volPtr->id,
379            *(volPtr->get_location()),
380            1.0f / volPtr->aspect_ratio_width,
381            1.0f / volPtr->aspect_ratio_height,
382            1.0f / volPtr->aspect_ratio_depth,
383            volPtr->wAxis.max());
384        NanoVis::licRenderer->set_offset(NanoVis::lic_slice_z);
385    }
386    return TCL_OK;
387}
388
389static Rappture::SwitchSpec flowSwitches[] =
390{
391    {Rappture::SWITCH_BOOLEAN, "-lic", "boolean",
392        offsetof(FlowCmd, lic), 0},
393    {Rappture::SWITCH_BOOLEAN, "-hide", "boolean",
394        offsetof(FlowCmd, hidden), 0},
395    {Rappture::SWITCH_END}
396};
397
398static int
399FlowConfigureOp(ClientData clientData, Tcl_Interp *interp, int objc,
400                Tcl_Obj *const *objv)
401{
402    int axis;
403    if (GetAxisFromObj(interp, objv[3], &axis) != TCL_OK) {
404        return TCL_ERROR;
405    }
406    FlowCmd *flowPtr = (FlowCmd *)clientData;
407    if (Rappture::ParseSwitches(interp, flowSwitches, objc - 3, objv + 3,
408        flowPtr, SWITCH_DEFAULTS) < 0) {
409        return TCL_ERROR;
410    }
411    return TCL_OK;
412}
413
414static Rappture::SwitchSpec initStreamSwitches[] =
415{
416    {Rappture::SWITCH_BOOLEAN, "-hide", "boolean",
417        offsetof(InitStream, hidden), 0},
418    {Rappture::SWITCH_FLOAT, "-position", "number",
419        offsetof(InitStream, position), 0},
420    {Rappture::SWITCH_END}
421};
422
423static int
424FlowInjectorAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
425                Tcl_Obj *const *objv)
426{
427    FlowCmd *flowPtr = (FlowCmd *)clientData;
428
429    const char *name;
430    name = Tcl_GetString(objv[3]);
431    Tcl_HashEntry *hPtr;
432    int isNew;
433    hPtr = Tcl_CreateHashEntry(&flowPtr->injectTable, name, &isNew);
434    if (!isNew) {
435        Tcl_AppendResult(interp, "flow \"", Tcl_GetString(objv[0]),
436                "\" already has a injection plane named \"", name, "\"",
437                (char *)NULL);
438        return TCL_ERROR;
439    }
440    InitStream *iStreamPtr;
441    iStreamPtr = new InitStream;
442    if (iStreamPtr == NULL) {
443        Tcl_AppendResult(interp, "can't allocate a initstream \"", name,
444                         "\"", (char *)NULL);
445        return TCL_ERROR;
446    }
447    Tcl_SetHashValue(hPtr, iStreamPtr);
448    iStreamPtr->hashPtr = hPtr;
449    iStreamPtr->name = Tcl_GetHashKey(&flowPtr->injectTable, hPtr);
450    if (Rappture::ParseSwitches(interp, initStreamSwitches, objc - 3, objv + 3,
451        iStreamPtr, SWITCH_DEFAULTS) < 0) {
452        return TCL_ERROR;
453    }
454    return TCL_OK;
455}
456
457static int
458FlowInjectorDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
459                   Tcl_Obj *const *objv)
460{
461    FlowCmd *flowPtr = (FlowCmd *)clientData;
462    const char *name;
463    name = Tcl_GetString(objv[3]);
464    Tcl_HashEntry *hPtr;
465    hPtr = Tcl_FindHashEntry(&flowPtr->injectTable, name);
466    if (hPtr == NULL) {
467        Tcl_AppendResult(interp, "can't find a initstream \"", name, "\"",
468                         (char *)NULL);
469        return TCL_ERROR;
470    }
471    InitStream *iStreamPtr = (InitStream *)Tcl_GetHashValue(hPtr);
472    Tcl_DeleteHashEntry(hPtr);
473    delete iStreamPtr;
474    return TCL_OK;
475}
476
477static int
478FlowInjectorNamesOp(ClientData clientData, Tcl_Interp *interp, int objc,
479             Tcl_Obj *const *objv)
480{
481    FlowCmd *flowPtr = (FlowCmd *)clientData;
482    Tcl_HashEntry *hPtr;
483    Tcl_HashSearch iter;
484    Tcl_Obj *listObjPtr;
485    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
486    for (hPtr = Tcl_FirstHashEntry(&flowPtr->injectTable, &iter);
487         hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) {
488        Tcl_Obj *objPtr;
489        const char *name;
490
491        name = Tcl_GetHashKey(&flowPtr->injectTable, hPtr);
492        objPtr = Tcl_NewStringObj(name, -1);
493        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
494    }
495    Tcl_SetObjResult(interp, listObjPtr);
496    return TCL_OK;
497}
498
499static int
500FlowInjectorConfigureOp(ClientData clientData, Tcl_Interp *interp, int objc,
501                        Tcl_Obj *const *objv)
502{
503    FlowCmd *flowPtr = (FlowCmd *)clientData;
504    const char *name;
505    name = Tcl_GetString(objv[3]);
506    Tcl_HashEntry *hPtr;
507    hPtr = Tcl_FindHashEntry(&flowPtr->injectTable, name);
508    if (hPtr == NULL) {
509        Tcl_AppendResult(interp, "can't find a initstream \"", name, "\"",
510                         (char *)NULL);
511        return TCL_ERROR;
512    }
513    InitStream *iStreamPtr = (InitStream *)Tcl_GetHashValue(hPtr);
514    if (Rappture::ParseSwitches(interp, initStreamSwitches, objc - 4, objv + 4,
515        iStreamPtr, SWITCH_DEFAULTS) < 0) {
516        return TCL_ERROR;
517    }
518    return TCL_OK;
519}
520
521
522/*
523 *---------------------------------------------------------------------------
524 *
525 * FlowInjectorObjCmd --
526 *
527 *      This procedure is invoked to process commands on behalf of the flow
528 *      object.
529 *
530 * Results:
531 *      A standard Tcl result.
532 *
533 * Side effects:
534 *      See the user documentation.
535 *
536 *---------------------------------------------------------------------------
537 */
538static Rappture::CmdSpec flowInjectorOps[] = {
539    {"add",        1, FlowInjectorAddOp,        3, 0, "name ?switches?",},
540    {"configure",  1, FlowInjectorConfigureOp,  3, 5, "name ?switches?",},
541    {"delete",     1, FlowInjectorDeleteOp,     3, 0, "?name...?"},
542    {"names",      1, FlowInjectorNamesOp,      3, 4, "?pattern?"},
543};
544
545static int nFlowInjectorOps = NumCmdSpecs(flowInjectorOps);
546
547static int
548FlowInjectorOp(ClientData clientData, Tcl_Interp *interp, int objc,
549               Tcl_Obj *const *objv)
550{
551    Tcl_ObjCmdProc *proc;
552    proc = Rappture::GetOpFromObj(interp, nFlowInjectorOps, flowInjectorOps,
553        Rappture::CMDSPEC_ARG1, objc, objv, 0);
554    if (proc == NULL) {
555        return TCL_ERROR;
556    }
557    FlowCmd *flowPtr = (FlowCmd *)clientData;
558    Tcl_Preserve(flowPtr);
559    int result;
560    result = (*proc) (clientData, interp, objc, objv);
561    Tcl_Release(flowPtr);
562    return result;
563}
564
565/*
566 *---------------------------------------------------------------------------
567 *
568 * FlowShapeOp--
569 *
570 *      This procedure is invoked to process commands on behalf of the flow
571 *      object.
572 *
573 * Results:
574 *      A standard Tcl result.
575 *
576 * Side effects:
577 *      See the user documentation.
578 *
579 *---------------------------------------------------------------------------
580 */
581static Rappture::CmdSpec flowShapeOps[] = {
582    {"add",        1, FlowInjectorAddOp,        3, 0, "name ?switches?",},
583    {"configure",  1, FlowInjectorConfigureOp,  3, 5, "name ?switches?",},
584    {"delete",     1, FlowInjectorDeleteOp,     3, 0, "?name...?"},
585    {"names",      1, FlowInjectorNamesOp,      3, 4, "?pattern?"},
586};
587
588static int nFlowShapeOps = NumCmdSpecs(flowShapeOps);
589
590static int
591FlowShapeOp(ClientData clientData, Tcl_Interp *interp, int objc,
592               Tcl_Obj *const *objv)
593{
594    Tcl_ObjCmdProc *proc;
595    proc = Rappture::GetOpFromObj(interp, nFlowShapeOps, flowShapeOps,
596        Rappture::CMDSPEC_ARG1, objc, objv, 0);
597    if (proc == NULL) {
598        return TCL_ERROR;
599    }
600    FlowCmd *flowPtr = (FlowCmd *)clientData;
601    Tcl_Preserve(flowPtr);
602    int result;
603    result = (*proc) (clientData, interp, objc, objv);
604    Tcl_Release(flowPtr);
605    return result;
606}
607
608/*
609 *---------------------------------------------------------------------------
610 *
611 * FlowInstObjCmd --
612 *
613 *      This procedure is invoked to process commands on behalf of the flow
614 *      object.
615 *
616 * Results:
617 *      A standard Tcl result.
618 *
619 * Side effects:
620 *      See the user documentation.
621 *
622 *---------------------------------------------------------------------------
623 */
624static Rappture::CmdSpec flowInstOps[] = {
625    {"configure",   1, FlowConfigureOp,  3, 5, "?switches?",},
626    {"data",        1, FlowDataOp,       4, 0, "oper ?args?"},
627    {"injector",    1, FlowInjectorOp,   3, 0, "oper ?args?",},
628    {"particles",   1, FlowParticlesOp,  3, 0, "oper ?args?",},
629    {"shape",       2, FlowShapeOp,      3, 0, "oper ?args?",},
630    {"stream",      2, FlowStreamOp,     4, 0, "oper axis ?args?",},
631};
632static int nFlowInstOps = NumCmdSpecs(flowInstOps);
633
634static int
635FlowInstObjCmd(ClientData clientData, Tcl_Interp *interp, int objc,
636               Tcl_Obj *const *objv)
637{
638    Tcl_ObjCmdProc *proc;
639    proc = Rappture::GetOpFromObj(interp, nFlowInstOps, flowInstOps,
640        Rappture::CMDSPEC_ARG1, objc, objv, 0);
641    if (proc == NULL) {
642        return TCL_ERROR;
643    }
644    FlowCmd *flowPtr = (FlowCmd *)clientData;
645    Tcl_Preserve(flowPtr);
646    int result;
647    result = (*proc) (clientData, interp, objc, objv);
648    Tcl_Release(flowPtr);
649    return result;
650}
651
652/*
653 *---------------------------------------------------------------------------
654 *
655 * FlowInstDeleteProc --
656 *
657 *      Deletes the command associated with the tree.  This is called only
658 *      when the command associated with the tree is destroyed.
659 *
660 * Results:
661 *      None.
662 *
663 *---------------------------------------------------------------------------
664 */
665static void
666FlowInstDeleteProc(ClientData clientData)
667{
668    FlowCmd *flowPtr = (FlowCmd *)clientData;
669
670    if (flowPtr->hashPtr != NULL) {
671        Tcl_DeleteHashEntry(flowPtr->hashPtr);
672    }
673    delete flowPtr;
674}
675
676/*
677 *---------------------------------------------------------------------------
678 *
679 * FlowAddOp --
680 *
681 *---------------------------------------------------------------------------
682 */
683/*ARGSUSED*/
684static int
685FlowAddOp(ClientData clientData, Tcl_Interp *interp, int objc,
686          Tcl_Obj *const *objv)
687{
688    const char *name;
689    name = Tcl_GetString(objv[2]);
690
691    Tcl_HashEntry *hPtr;
692    int isNew;
693    hPtr = Tcl_CreateHashEntry(&flowTable, name, &isNew);
694    if (!isNew) {
695        Tcl_AppendResult(interp, "flow \"", name, "\" already exists.",
696                         (char *)NULL);
697        return TCL_ERROR;
698    }
699    Tcl_CmdInfo cmdInfo;
700    if (Tcl_GetCommandInfo(interp, name, &cmdInfo)) {
701        Tcl_AppendResult(interp, "an another command \"", name,
702                         "\" already exists.", (char *)NULL);
703        return TCL_ERROR;
704    }   
705    FlowCmd *flowPtr;
706    flowPtr = new FlowCmd;
707    if (flowPtr == NULL) {
708        Tcl_AppendResult(interp, "can't allocate a flow object \"", name,
709                         "\"", (char *)NULL);
710        return TCL_ERROR;
711    }
712    flowPtr->hashPtr = hPtr;
713    flowPtr->name = Tcl_GetHashKey(&flowTable, hPtr);
714    flowPtr->cmdToken = Tcl_CreateObjCommand(interp, (char *)name,
715        (Tcl_ObjCmdProc *)FlowInstObjCmd, flowPtr, FlowInstDeleteProc);
716    Tcl_SetHashValue(hPtr, flowPtr);
717    flowPtr->volPtr = NULL;
718    return TCL_OK;
719}
720
721/*
722 *---------------------------------------------------------------------------
723 *
724 * FlowDeleteOp --
725 *
726 *---------------------------------------------------------------------------
727 */
728/*ARGSUSED*/
729static int
730FlowDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc,
731             Tcl_Obj *const *objv)
732{
733    int i;
734
735    for (i = 2; i < objc; i++) {
736        FlowCmd *flowPtr;
737
738        if (GetFlowFromObj(interp, objv[i], &flowPtr) != TCL_OK) {
739            return TCL_ERROR;
740        }
741        Tcl_DeleteCommandFromToken(interp, flowPtr->cmdToken);
742#ifdef notdef
743        NanoVis::flowVisRenderer->removeVectorField(flowPtr);
744#endif
745        delete flowPtr;
746    }
747    return TCL_OK;
748}
749
750/*
751 *---------------------------------------------------------------------------
752 *
753 * FlowInitOp --
754 *
755 *---------------------------------------------------------------------------
756 */
757/*ARGSUSED*/
758static int
759FlowInitOp(ClientData clientData, Tcl_Interp *interp, int objc,
760           Tcl_Obj *const *objv)
761{
762    Tcl_Obj *listObjPtr;
763    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
764
765    Tcl_HashEntry *hPtr;
766    Tcl_HashSearch iter;
767    for (hPtr = Tcl_FirstHashEntry(&flowTable, &iter); hPtr != NULL;
768        hPtr = Tcl_NextHashEntry(&iter)) {
769        FlowCmd *flowPtr;
770        flowPtr = (FlowCmd *)Tcl_GetHashValue(hPtr);
771        if (flowPtr->fieldPtr != NULL) {
772            delete flowPtr->fieldPtr; // Remove the vector field.
773            flowPtr->fieldPtr = NULL;
774        }
775    }
776#ifdef notdef
777    // For each flow vector enabled in the table add it to the renderer.
778    for (hPtr = Tcl_FirstHashEntry(&flowTable, &iter); hPtr != NULL;
779        hPtr = Tcl_NextHashEntry(&iter)) {
780        FlowCmd *flowPtr;
781        flowPtr = (FlowCmd *)Tcl_GetHashValue(hPtr);
782        if (flowPtr->hidden) {
783            continue;           // Flow is hidden.
784        }
785        if (flowPtr->volPtr == NULL) {
786            continue;
787        }
788        volPtr->set_n_slice(256-n);
789        // volPtr->set_n_slice(512-n);
790        volPtr->disable_cutplane(0);
791        volPtr->disable_cutplane(1);
792        volPtr->disable_cutplane(2);
793           
794        NanoVis::vol_renderer->add_volume(volPtr,
795                NanoVis::get_transfunc("default"));
796        float dx0 = -0.5;
797        float dy0 = -0.5*volPtr->height/volPtr->width;
798        float dz0 = -0.5*volPtr->depth/volPtr->width;
799        volPtr->move(Vector3(dx0, dy0, dz0));
800        //volPtr->enable_data();
801        volPtr->disable_data();
802        NvVectorField *fieldPtr;
803        fieldPtr = NanoVis::flowVisRenderer->addVectorField(volPtr,
804                *(volPtr->get_location()), 1.0f,
805                volPtr->height / (float)volPtr->width,
806                volPtr->depth  / (float)volPtr->width,
807                1.0f);
808        NanoVis::flowVisRenderer->activateVectorField(fieldPtr);
809           
810        //////////////////////////////////
811        // ADD Particle Injection Plane1
812        NanoVis::flowVisRenderer->addPlane(fieldPtr, plane_name1);
813        NanoVis::flowVisRenderer->setPlaneAxis(fieldPtr, plane_name1, 0);
814        NanoVis::flowVisRenderer->setPlanePos(fieldPtr, plane_name1, 0.9);
815        NanoVis::flowVisRenderer->setParticleColor(fieldPtr, plane_name1,
816                                                   color1);
817        // ADD Particle Injection Plane2
818        NanoVis::flowVisRenderer->addPlane(fieldPtr, plane_name2);
819        NanoVis::flowVisRenderer->setPlaneAxis(fieldPtr, plane_name2, 0);
820        NanoVis::flowVisRenderer->setPlanePos(fieldPtr, plane_name2, 0.2);
821        NanoVis::flowVisRenderer->setParticleColor(fieldPtr, plane_name2,
822                                                   color2);
823        NanoVis::flowVisRenderer->initialize(fieldPtr);
824           
825        NanoVis::flowVisRenderer->activatePlane(fieldPtr, plane_name1);
826        NanoVis::flowVisRenderer->activatePlane(fieldPtr, plane_name2);
827           
828        NanoVis::licRenderer->setVectorField(volPtr->id,
829                                *(volPtr->get_location()),
830                                1.0f / volPtr->aspect_ratio_width,
831                                1.0f / volPtr->aspect_ratio_height,
832                                1.0f / volPtr->aspect_ratio_depth,
833                                volPtr->wAxis.max());
834        }
835    }
836        const char *name;
837        name = Tcl_GetCommandName(interp, flowPtr->cmdToken);
838        Tcl_Obj *objPtr;
839        objPtr = Tcl_NewStringObj(name, -1);
840        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
841    }
842    Tcl_SetObjResult(interp, listObjPtr);
843#endif
844    return TCL_OK;
845}
846
847/*
848 *---------------------------------------------------------------------------
849 *
850 * FlowNamesOp --
851 *
852 *---------------------------------------------------------------------------
853 */
854/*ARGSUSED*/
855static int
856FlowNamesOp(ClientData clientData, Tcl_Interp *interp, int objc,
857            Tcl_Obj *const *objv)
858{
859    Tcl_Obj *listObjPtr;
860    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
861
862    Tcl_HashEntry *hPtr;
863    Tcl_HashSearch iter;
864    for (hPtr = Tcl_FirstHashEntry(&flowTable, &iter); hPtr != NULL;
865        hPtr = Tcl_NextHashEntry(&iter)) {
866        FlowCmd *flowPtr;
867        flowPtr = (FlowCmd *)Tcl_GetHashValue(hPtr);
868        const char *name;
869        name = Tcl_GetCommandName(interp, flowPtr->cmdToken);
870        Tcl_Obj *objPtr;
871        objPtr = Tcl_NewStringObj(name, -1);
872        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
873    }
874    Tcl_SetObjResult(interp, listObjPtr);
875    return TCL_OK;
876}
877
878static int
879FlowNextOp(ClientData clientData, Tcl_Interp *interp, int objc,
880             Tcl_Obj *const *objv)
881{
882    if (!NanoVis::licRenderer->isActivated()) {
883        NanoVis::licRenderer->activate();
884    }
885    if (!NanoVis::flowVisRenderer->isActivated()) {
886        NanoVis::flowVisRenderer->activate();
887    }
888
889    Trace("sending flow playback frame\n");
890
891    // Generate the latest frame and send it back to the client
892    if (NanoVis::licRenderer->isActivated()) {
893        NanoVis::licRenderer->convolve();
894    }
895    NanoVis::flowVisRenderer->advect();
896    NanoVis::offscreen_buffer_capture();  //enable offscreen render
897    NanoVis::display();
898    NanoVis::read_screen();
899
900    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
901
902    // NanoVis::bmp_write_to_file(frame_count, fileName);
903    Trace("FLOW end\n");
904    return TCL_OK;
905}
906
907static int
908FlowResetOp(ClientData clientData, Tcl_Interp *interp, int objc,
909             Tcl_Obj *const *objv)
910{
911    NanoVis::initParticle();
912    return TCL_OK;
913}
914
915static int
916FlowVideoOp(ClientData clientData, Tcl_Interp *interp, int objc,
917            Tcl_Obj *const *objv)
918{
919    int width, height;          // Resolution of video.
920    int numFrames;              // Total number of frames.
921    float frameRate;            // Frame rate of the video.
922    float bitRate;              // Bit rate of the vide.
923
924    if ((Tcl_GetIntFromObj(interp, objv[2], &width) != TCL_OK) ||
925        (Tcl_GetIntFromObj(interp, objv[3], &height) != TCL_OK) ||
926        (Tcl_GetIntFromObj(interp, objv[4], &numFrames) != TCL_OK) ||
927        (GetFloatFromObj(interp, objv[5], &frameRate) != TCL_OK) ||
928        (GetFloatFromObj(interp, objv[6], &bitRate) != TCL_OK)) {
929        return TCL_ERROR;
930    }
931    if ((width<0) || (width>SHRT_MAX) || (height<0) || (height>SHRT_MAX)) {
932        Tcl_AppendResult(interp, "bad dimensions for video", (char *)NULL);
933        return TCL_ERROR;
934    }
935    if ((frameRate < 0.0f) || (frameRate > 30.0f)) {
936        Tcl_AppendResult(interp, "bad frame rate \"", Tcl_GetString(objv[5]),
937                         "\"", (char *)NULL);
938        return TCL_ERROR;
939    }
940    if ((bitRate < 0.0f) || (frameRate > 30.0f)) {
941        Tcl_AppendResult(interp, "bad bit rate \"", Tcl_GetString(objv[6]),
942                         "\"", (char *)NULL);
943        return TCL_ERROR;
944    }
945
946    if (NanoVis::licRenderer) {
947        NanoVis::licRenderer->activate();
948    }
949    if (NanoVis::flowVisRenderer) {
950        NanoVis::flowVisRenderer->activate();
951    }
952
953    // Save the old dimensions of the offscreen buffer.
954    int oldWidth, oldHeight;
955    oldWidth = NanoVis::win_width;
956    oldHeight = NanoVis::win_height;
957
958    if ((width != oldWidth) || (height != oldHeight)) {
959        // Resize to the requested size.
960        NanoVis::resize_offscreen_buffer(width, height);
961    }
962
963    char fileName[128];
964    sprintf(fileName,"/tmp/flow%d.mpeg", getpid());
965
966    Trace("FLOW started\n");
967
968    Rappture::Outcome context;
969    Rappture::AVTranslate movie(width, height, frameRate, bitRate);
970
971    int pad = 0;
972    if ((3*NanoVis::win_width) % 4 > 0) {
973        pad = 4 - ((3*NanoVis::win_width) % 4);
974    }
975
976    movie.init(context, fileName);
977
978    for (int i = 0; i < numFrames; i++) {
979        // Generate the latest frame and send it back to the client
980        if (NanoVis::licRenderer &&
981            NanoVis::licRenderer->isActivated()) {
982            NanoVis::licRenderer->convolve();
983        }
984        if (NanoVis::flowVisRenderer &&
985            NanoVis::flowVisRenderer->isActivated()) {
986            NanoVis::flowVisRenderer->advect();
987        }
988        NanoVis::offscreen_buffer_capture();  //enable offscreen render
989        NanoVis::display();
990
991        NanoVis::read_screen();
992        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
993
994        // This is done before bmp_write_to_file because bmp_write_to_file
995        // turns rgb data to bgr
996        movie.append(context, NanoVis::screen_buffer, pad);
997        // NanoVis::bmp_write_to_file(frame_count, fileName);
998    }
999
1000    movie.done(context);
1001    Trace("FLOW end\n");
1002
1003    if (NanoVis::licRenderer) {
1004        NanoVis::licRenderer->deactivate();
1005    }
1006    if (NanoVis::flowVisRenderer) {
1007        NanoVis::flowVisRenderer->deactivate();
1008    }
1009    NanoVis::initParticle();
1010
1011    // FIXME: find a way to get the data from the movie object as a void*
1012    Rappture::Buffer data;
1013    if (!data.load(context, fileName)) {
1014        Tcl_AppendResult(interp, "can't load data from temporary movie file \"",
1015                fileName, "\": ", context.remark(), (char *)NULL);
1016        return TCL_ERROR;
1017    }
1018    // Build the command string for the client.
1019    char command[200];
1020    sprintf(command,"nv>image -bytes %lu -type movie -token token\n",
1021            (unsigned long)data.size());
1022
1023    NanoVis::sendDataToClient(command, data.bytes(), data.size());
1024    if (unlink(fileName) != 0) {
1025        Tcl_AppendResult(interp, "can't unlink temporary movie file \"",
1026                fileName, "\": ", Tcl_PosixError(interp), (char *)NULL);
1027        return TCL_ERROR;
1028    }
1029    return TCL_OK;
1030}
1031
1032/*
1033 *---------------------------------------------------------------------------
1034 *
1035 * FlowObjCmd --
1036 *
1037 *---------------------------------------------------------------------------
1038 */
1039static Rappture::CmdSpec flowCmdOps[] = {
1040    {"add",      1, FlowAddOp,     2, 3, "?name? ?option value...?",},
1041    {"delete",   1, FlowDeleteOp,  2, 0, "name...",},
1042    {"init",     1, FlowInitOp,    2, 2, "",},
1043    {"names",    1, FlowNamesOp,   2, 3, "?pattern?",},
1044    {"next",     2, FlowNextOp,    2, 2, "",},
1045    {"reset",    1, FlowResetOp,   2, 2, "",},
1046    {"video",    1, FlowVideoOp,   7, 7,       
1047        "width height numFrames frameRate bitRate ",},
1048};
1049static int nFlowCmdOps = NumCmdSpecs(flowCmdOps);
1050
1051/*ARGSUSED*/
1052static int
1053FlowCmdProc(ClientData clientData, Tcl_Interp *interp, int objc,
1054            Tcl_Obj *const *objv)
1055{
1056    Tcl_ObjCmdProc *proc;
1057
1058    proc = Rappture::GetOpFromObj(interp, nFlowCmdOps, flowCmdOps,
1059        Rappture::CMDSPEC_ARG1, objc, objv, 0);
1060    if (proc == NULL) {
1061        return TCL_ERROR;
1062    }
1063    return (*proc) (clientData, interp, objc, objv);
1064}
1065
1066/*
1067 *---------------------------------------------------------------------------
1068 *
1069 * FlowCmdInitProc --
1070 *
1071 *      This procedure is invoked to initialize the "tree" command.
1072 *
1073 * Results:
1074 *      None.
1075 *
1076 * Side effects:
1077 *      Creates the new command and adds a new entry into a global Tcl
1078 *      associative array.
1079 *
1080 *---------------------------------------------------------------------------
1081 */
1082int
1083FlowCmdInitProc(Tcl_Interp *interp)
1084{
1085    Tcl_CreateObjCommand(interp, "flow", FlowCmdProc, NULL, NULL);
1086    Tcl_InitHashTable(&flowTable, TCL_STRING_KEYS);
1087    return TCL_OK;
1088}
1089
1090#ifdef notdef
1091void
1092MapFlowVectors(Tcl_Interp *interp)
1093{
1094    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1095
1096    if (debug_flag) {
1097        fprintf(stderr, "in SetHeightmapRanges\n");
1098    }
1099    xMin = yMin = zMin = wMin = DBL_MAX;
1100    xMax = yMax = zMax = wMax = -DBL_MAX;
1101    Tcl_HashEntry *hPtr;
1102    Tcl_HashSearch iter;
1103    for (hPtr = Tcl_FirstHashEntry(&flowTable, &iter); hPtr != NULL;
1104        hPtr = Tcl_NextHashEntry(&iter)) {
1105        FlowCmd *flowPtr;
1106        flowPtr = (FlowCmd *)Tcl_GetHashValue(hPtr);
1107
1108        flowPtr->
1109
1110    for (unsigned int i = 0; i < heightMap.size(); i++) {
1111        HeightMap *hmPtr;
1112
1113        hmPtr = heightMap[i];
1114        if (hmPtr == NULL) {
1115            continue;
1116        }
1117        if (xMin > hmPtr->xAxis.min()) {
1118            xMin = hmPtr->xAxis.min();
1119        }
1120        if (xMax < hmPtr->xAxis.max()) {
1121            xMax = hmPtr->xAxis.max();
1122        }
1123        if (yMin > hmPtr->yAxis.min()) {
1124            yMin = hmPtr->yAxis.min();
1125        }
1126        if (yMax < hmPtr->yAxis.max()) {
1127            yMax = hmPtr->yAxis.max();
1128        }
1129        if (zMin > hmPtr->zAxis.min()) {
1130            zMin = hmPtr->zAxis.min();
1131        }
1132        if (zMax < hmPtr->zAxis.max()) {
1133            zMax = hmPtr->zAxis.max();
1134        }
1135        if (wMin > hmPtr->wAxis.min()) {
1136            wMin = hmPtr->wAxis.min();
1137        }
1138        if (wMax < hmPtr->wAxis.max()) {
1139            wMax = hmPtr->wAxis.max();
1140        }
1141    }
1142    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1143        grid->xAxis.SetScale(xMin, xMax);
1144    }
1145    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1146        grid->yAxis.SetScale(yMin, yMax);
1147    }
1148    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1149        grid->zAxis.SetScale(zMin, zMax);
1150    }
1151    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1152        HeightMap::valueMin = grid->yAxis.min();
1153        HeightMap::valueMax = grid->yAxis.max();
1154    }
1155    for (unsigned int i = 0; i < heightMap.size(); i++) {
1156        HeightMap *hmPtr;
1157
1158        hmPtr = heightMap[i];
1159        if (hmPtr == NULL) {
1160            continue;
1161        }
1162        hmPtr->MapToGrid(grid);
1163    }
1164    HeightMap::update_pending = false;
1165    if (debug_flag) {
1166        fprintf(stderr, "leaving SetHeightmapRanges\n");
1167    }
1168}
1169
1170    Tcl_Obj *listObjPtr;
1171    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
1172
1173    Tcl_HashEntry *hPtr;
1174    Tcl_HashSearch iter;
1175    for (hPtr = Tcl_FirstHashEntry(&flowTable, &iter); hPtr != NULL;
1176        hPtr = Tcl_NextHashEntry(&iter)) {
1177        FlowCmd *flowPtr;
1178        flowPtr = (FlowCmd *)Tcl_GetHashValue(hPtr);
1179        if (flowPtr->fieldPtr != NULL) {
1180            delete flowPtr->fieldPtr; // Remove the vector field.
1181            flowPtr->fieldPtr = NULL;
1182        }
1183    }
1184
1185
1186            Volume *volPtr;
1187            volPtr = NanoVis::load_volume(index, nx, ny, nz, 4, data,
1188                        field.valueMin(), field.valueMax(), nzero_min);
1189            volPtr->xAxis.SetRange(field.rangeMin(Rappture::xaxis),
1190                   field.rangeMax(Rappture::xaxis));
1191            volPtr->yAxis.SetRange(field.rangeMin(Rappture::yaxis),
1192                   field.rangeMax(Rappture::yaxis));
1193            volPtr->zAxis.SetRange(field.rangeMin(Rappture::zaxis),
1194                   field.rangeMax(Rappture::zaxis));
1195            volPtr->wAxis.SetRange(field.valueMin(), field.valueMax());
1196            volPtr->update_pending = true;
1197            delete [] data;
1198#endif
Note: See TracBrowser for help on using the repository browser.