source: trunk/gui/vizservers/nanovis/nanovis.cpp @ 467

Last change on this file since 467 was 467, checked in by mmc, 18 years ago

Last minute fixes so we can deploy the nanoVIS server:

  • Added monitor.tcl script which monitors nanoscale and restarts as needed.
  • Fixed relative paths for shaders and fonts. All shaders and fonts are

taken from /opt/nanovis/lib

  • Fixed the ordering of data for the nanowire simulator
File size: 92.0 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 * Nanovis: Visualization of Nanoelectronics Data
4 *
5 * ======================================================================
6 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
7 *           Michael McLennan <mmclennan@purdue.edu>
8 *           Purdue Rendering and Perceptualization Lab (PURPL)
9 *
10 *  Copyright (c) 2004-2006  Purdue Research Foundation
11 *
12 *  See the file "license.terms" for information on usage and
13 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 * ======================================================================
15 */
16
17#include <stdio.h>
18#include <math.h>
19#include <fstream>
20#include <iostream>
21#include <sstream>
22#include <string>
23#include <sys/time.h>
24#include <sys/types.h>
25#include <unistd.h>
26#include <fcntl.h>
27
28#include "nanovis.h"
29#include "RpField1D.h"
30#include "RpFieldRect3D.h"
31#include "RpFieldPrism3D.h"
32
33//transfer function headers
34#include "transfer-function/TransferFunctionMain.h"
35#include "transfer-function/ControlPoint.h"
36#include "transfer-function/TransferFunctionGLUTWindow.h"
37#include "transfer-function/ColorGradientGLUTWindow.h"
38#include "transfer-function/ColorPaletteWindow.h"
39#include "transfer-function/MainWindow.h"
40
41//render server
42
43VolumeRenderer* vol_render;
44PlaneRenderer* plane_render;
45Camera* cam;
46
47//if true nanovis renders volumes in 3D, if not renders 2D plane
48bool volume_mode = true;
49
50// color table for built-in transfer function editor
51float color_table[256][4];     
52
53// default transfer function
54char *def_transfunc = "transfunc define default {\n\
55  0.0  1 1 1\n\
56  0.2  1 1 0\n\
57  0.4  0 1 0\n\
58  0.6  0 1 1\n\
59  0.8  0 0 1\n\
60  1.0  1 0 1\n\
61} {\n\
62  0.00  1.0\n\
63  0.05  0.0\n\
64  0.15  0.0\n\
65  0.20  1.0\n\
66  0.25  0.0\n\
67  0.35  0.0\n\
68  0.40  1.0\n\
69  0.45  0.0\n\
70  0.55  0.0\n\
71  0.60  1.0\n\
72  0.65  0.0\n\
73  0.75  0.0\n\
74  0.80  1.0\n\
75  0.85  0.0\n\
76  0.95  0.0\n\
77  1.00  1.0\n\
78}";
79
80#ifdef XINETD
81FILE* xinetd_log;
82#endif
83
84FILE* event_log;
85//log
86void init_event_log();
87void end_event_log();
88double cur_time;        //in seconds
89double get_time_interval();
90
91int render_window;              //the handle of the render window;
92// forward declarations
93void init_particles();
94void get_slice_vectors();
95Rappture::Outcome load_volume_file(int index, char *fname);
96void load_volume(int index, int width, int height, int depth, int n_component, float* data, double vmin, double vmax);
97TransferFunction* get_transfunc(char *name);
98void resize_offscreen_buffer(int w, int h);
99void offscreen_buffer_capture();
100void bmp_header_add_int(unsigned char* header, int& pos, int data);
101void bmp_write(const char* cmd);
102
103ParticleSystem* psys;
104float psys_x=0.4, psys_y=0, psys_z=0;
105
106Lic* lic;
107
108//frame buffer for final rendering
109unsigned char* screen_buffer = NULL;
110NVISid final_fbo, final_color_tex, final_depth_rb;
111
112bool advect=false;
113float vert[NMESH*NMESH*3];              //particle positions in main memory
114float slice_vector[NMESH*NMESH*4];      //per slice vectors in main memory
115
116int n_volumes = 0;
117// pointers to volumes, currently handle up to 10 volumes
118vector<Volume*> volume;
119
120// maps transfunc name to TransferFunction object
121Tcl_HashTable tftable;
122
123// pointers to 2D planes, currently handle up 10
124Texture2D* plane[10];
125
126// value indicates "up" axis:  x=1, y=2, z=3, -x=-1, -y=-2, -z=-3
127int updir = 2;
128
129PerfQuery* perf;                        //perfromance counter
130
131//Nvidia CG shaders and their parameters
132CGcontext g_context;
133
134CGprogram m_passthru_fprog;
135CGparameter m_passthru_scale_param, m_passthru_bias_param;
136
137CGprogram m_copy_texcoord_fprog;
138
139CGprogram m_one_volume_fprog;
140CGparameter m_vol_one_volume_param;
141CGparameter m_tf_one_volume_param;
142CGparameter m_mvi_one_volume_param;
143CGparameter m_mv_one_volume_param;
144CGparameter m_render_param_one_volume_param;
145
146CGprogram m_vert_std_vprog;
147CGparameter m_mvp_vert_std_param;
148CGparameter m_mvi_vert_std_param;
149
150using namespace std;
151
152
153// Tcl interpreter for incoming messages
154static Tcl_Interp *interp;
155static Tcl_DString cmdbuffer;
156
157static int CameraCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
158static int CutplaneCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
159static int LegendCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
160static int ScreenCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
161static int TransfuncCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
162static int UpCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
163static int VolumeCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
164
165static int PlaneNewCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
166static int PlaneLinkCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
167static int PlaneEnableCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
168
169static int GetVolumeIndices _ANSI_ARGS_((Tcl_Interp *interp, int argc, CONST84 char *argv[], vector<int>* vectorPtr));
170static int GetAxis _ANSI_ARGS_((Tcl_Interp *interp, char *str, int *valPtr));
171static int GetColor _ANSI_ARGS_((Tcl_Interp *interp, char *str, float *rgbPtr));
172
173/*
174 * ----------------------------------------------------------------------
175 * CLIENT COMMAND:
176 *   camera aim <x0> <y0> <z0>
177 *   camera angle <xAngle> <yAngle> <zAngle>
178 *   camera zoom <factor>
179 *
180 * Clients send these commands to manipulate the camera.  The "angle"
181 * operation controls the angle of the camera around the focal point.
182 * The "zoom" operation sets the zoom factor, moving the camera in
183 * and out.
184 * ----------------------------------------------------------------------
185 */
186static int
187CameraCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
188{
189        if (argc < 2) {
190                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
191                        " option arg arg...\"", (char*)NULL);
192                return TCL_ERROR;
193    }
194
195    char c = *argv[1];
196        if (c == 'a' && strcmp(argv[1],"angle") == 0) {
197        if (argc != 5) {
198                    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
199                            " angle xangle yangle zangle\"", (char*)NULL);
200                    return TCL_ERROR;
201        }
202
203        double xangle, yangle, zangle;
204            if (Tcl_GetDouble(interp, argv[2], &xangle) != TCL_OK) {
205                    return TCL_ERROR;
206            }
207            if (Tcl_GetDouble(interp, argv[3], &yangle) != TCL_OK) {
208                    return TCL_ERROR;
209            }
210            if (Tcl_GetDouble(interp, argv[4], &zangle) != TCL_OK) {
211                    return TCL_ERROR;
212            }
213            cam->rotate(xangle, yangle, zangle);
214
215            return TCL_OK;
216        }
217        else if (c == 'a' && strcmp(argv[1],"aim") == 0) {
218        if (argc != 5) {
219                    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
220                            " aim x y z\"", (char*)NULL);
221                    return TCL_ERROR;
222        }
223
224        double x0, y0, z0;
225            if (Tcl_GetDouble(interp, argv[2], &x0) != TCL_OK) {
226                    return TCL_ERROR;
227            }
228            if (Tcl_GetDouble(interp, argv[3], &y0) != TCL_OK) {
229                    return TCL_ERROR;
230            }
231            if (Tcl_GetDouble(interp, argv[4], &z0) != TCL_OK) {
232                    return TCL_ERROR;
233            }
234            cam->aim(x0, y0, z0);
235
236            return TCL_OK;
237        }
238        else if (c == 'z' && strcmp(argv[1],"zoom") == 0) {
239        if (argc != 3) {
240                    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
241                            " zoom factor\"", (char*)NULL);
242                    return TCL_ERROR;
243        }
244
245        double zoom;
246            if (Tcl_GetDouble(interp, argv[2], &zoom) != TCL_OK) {
247                    return TCL_ERROR;
248            }
249
250        live_obj_z = -2.5/zoom;
251                cam->move(live_obj_x, live_obj_y, live_obj_z);
252
253            return TCL_OK;
254    }
255
256        Tcl_AppendResult(interp, "bad option \"", argv[1],
257                "\": should be aim, angle, or zoom", (char*)NULL);
258        return TCL_ERROR;
259}
260
261/*
262 * ----------------------------------------------------------------------
263 * CLIENT COMMAND:
264 *   cutplane state on|off <axis> ?<volume>...?
265 *   cutplane position <relvalue> <axis> ?<volume>...?
266 *
267 * Clients send these commands to manipulate the cutplanes in one or
268 * more data volumes.  The "state" command turns a cutplane on or
269 * off.  The "position" command changes the position to a relative
270 * value in the range 0-1.  The <axis> can be x, y, or z.  These
271 * operations are applied to the volumes represented by one or more
272 * <volume> indices.  If no volumes are specified, then all volumes
273 * are updated.
274 * ----------------------------------------------------------------------
275 */
276static int
277CutplaneCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
278{
279    if (argc < 2) {
280        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
281            " option ?arg arg...?\"", (char*)NULL);
282        return TCL_ERROR;
283    }
284
285    char c = *argv[1];
286    if (c == 's' && strcmp(argv[1],"state") == 0) {
287        if (argc < 4) {
288            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
289                " state on|off axis ?volume ...? \"", (char*)NULL);
290            return TCL_ERROR;
291        }
292
293        int state;
294        if (Tcl_GetBoolean(interp, argv[2], &state) != TCL_OK) {
295            return TCL_ERROR;
296        }
297
298        int axis;
299        if (GetAxis(interp, (char*) argv[3], &axis) != TCL_OK) {
300            return TCL_ERROR;
301        }
302
303        vector<int> ivol;
304        if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) {
305            return TCL_ERROR;
306        }
307
308        vector<int>::iterator iter = ivol.begin();
309        while (iter != ivol.end()) {
310            if (state) {
311                volume[*iter]->enable_cutplane(axis);
312            } else {
313                volume[*iter]->disable_cutplane(axis);
314            }
315            ++iter;
316        }
317        return TCL_OK;
318    }
319    else if (c == 'p' && strcmp(argv[1],"position") == 0) {
320        if (argc < 4) {
321            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
322                " position relval axis ?volume ...? \"", (char*)NULL);
323            return TCL_ERROR;
324        }
325
326        double relval;
327        if (Tcl_GetDouble(interp, argv[2], &relval) != TCL_OK) {
328            return TCL_ERROR;
329        }
330        // keep this just inside the volume so it doesn't disappear
331        if (relval < 0.01) { relval = 0.01; }
332        if (relval > 0.99) { relval = 0.99; }
333
334        int axis;
335        if (GetAxis(interp, (char*) argv[3], &axis) != TCL_OK) {
336            return TCL_ERROR;
337        }
338
339        vector<int> ivol;
340        if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) {
341            return TCL_ERROR;
342        }
343
344        vector<int>::iterator iter = ivol.begin();
345        while (iter != ivol.end()) {
346            volume[*iter]->move_cutplane(axis, (float)relval);
347            ++iter;
348        }
349        return TCL_OK;
350    }
351
352    Tcl_AppendResult(interp, "bad option \"", argv[1],
353        "\": should be position or state", (char*)NULL);
354    return TCL_ERROR;
355}
356
357/*
358 * ----------------------------------------------------------------------
359 * CLIENT COMMAND:
360 *   legend <volumeIndex> <width> <height>
361 *
362 * Clients use this to generate a legend image for the specified
363 * transfer function.  The legend image is a color gradient from 0
364 * to one, drawn in the given transfer function.  The resulting image
365 * is returned in the size <width> x <height>.
366 * ----------------------------------------------------------------------
367 */
368static int
369LegendCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
370{
371    if (argc != 4) {
372        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
373            " transfunc width height\"", (char*)NULL);
374        return TCL_ERROR;
375    }
376
377    TransferFunction *tf = NULL;
378    int ivol;
379    if (Tcl_GetInt(interp, argv[1], &ivol) != TCL_OK) {
380        return TCL_ERROR;
381    }
382    if (ivol < n_volumes) {
383        tf = vol_render->get_volume_shading(volume[ivol]);
384    }
385    if (tf == NULL) {
386        Tcl_AppendResult(interp, "transfer function not defined for volume ", argv[1], (char*)NULL);
387        return TCL_ERROR;
388    }
389
390    int old_width = win_width;
391    int old_height = win_height;
392
393    int width, height;
394    if (Tcl_GetInt(interp, argv[2], &width) != TCL_OK) {
395        return TCL_ERROR;
396    }
397    if (Tcl_GetInt(interp, argv[3], &height) != TCL_OK) {
398        return TCL_ERROR;
399    }
400
401    plane_render->set_screen_size(width, height);
402    resize_offscreen_buffer(width, height);
403
404    // generate data for the legend
405    float data[512];
406    for (int i=0; i < 256; i++) {
407        data[i] = data[i+256] = (float)(i/255.0);
408    }
409    plane[0] = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
410    int index = plane_render->add_plane(plane[0], tf);
411    plane_render->set_active_plane(index);
412
413    offscreen_buffer_capture();
414    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
415    plane_render->render();
416
417    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
418
419    std::ostringstream result;
420    result << "nv>legend " << argv[1];
421    result << " " << volume[ivol]->range_min();
422    result << " " << volume[ivol]->range_max();
423    bmp_write(result.str().c_str());
424    write(0, "\n", 1);
425
426    plane_render->remove_plane(index);
427    resize_offscreen_buffer(old_width, old_height);
428
429    return TCL_OK;
430}
431
432
433
434/*
435 * ----------------------------------------------------------------------
436 * CLIENT COMMAND:
437 *   screen <width> <height>
438 *
439 * Clients send this command to set the size of the rendering area.
440 * Future images are generated at the specified width/height.
441 * ----------------------------------------------------------------------
442 */
443static int
444ScreenCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
445{
446    int w, h;
447
448    if (argc != 3) {
449        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
450            " width height\"", (char*)NULL);
451        return TCL_ERROR;
452    }
453    if (Tcl_GetInt(interp, argv[1], &w) != TCL_OK) {
454        return TCL_ERROR;
455    }
456    if (Tcl_GetInt(interp, argv[2], &h) != TCL_OK) {
457        return TCL_ERROR;
458    }
459    resize_offscreen_buffer(w, h);
460
461    return TCL_OK;
462}
463
464/*
465 * ----------------------------------------------------------------------
466 * CLIENT COMMAND:
467 *   transfunc define <name> <colormap> <alphamap>
468 *     where <colormap> = { <v> <r> <g> <b> ... }
469 *           <alphamap> = { <v> <w> ... }
470 *
471 * Clients send these commands to manipulate the transfer functions.
472 * ----------------------------------------------------------------------
473 */
474static int
475TransfuncCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
476{
477        if (argc < 2) {
478                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
479                        " option arg arg...\"", (char*)NULL);
480                return TCL_ERROR;
481    }
482
483    char c = *argv[1];
484        if (c == 'd' && strcmp(argv[1],"define") == 0) {
485        if (argc != 5) {
486                    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
487                            argv[1], " define name colormap alphamap\"", (char*)NULL);
488            return TCL_ERROR;
489        }
490
491        // decode the data and store in a series of fields
492        Rappture::Field1D rFunc, gFunc, bFunc, wFunc;
493        int cmapc, wmapc, i, j;
494        char **cmapv, **wmapv;
495
496        if (Tcl_SplitList(interp, argv[3], &cmapc, &cmapv) != TCL_OK) {
497            return TCL_ERROR;
498        }
499        if (cmapc % 4 != 0) {
500            Tcl_Free((char*)cmapv);
501                    Tcl_AppendResult(interp, "bad colormap in transfunc: should be ",
502                "{ v r g b ... }", (char*)NULL);
503            return TCL_ERROR;
504        }
505
506        if (Tcl_SplitList(interp, argv[4], &wmapc, &wmapv) != TCL_OK) {
507            return TCL_ERROR;
508        }
509        if (wmapc % 2 != 0) {
510            Tcl_Free((char*)cmapv);
511            Tcl_Free((char*)wmapv);
512                    Tcl_AppendResult(interp, "bad alphamap in transfunc: should be ",
513                "{ v w ... }", (char*)NULL);
514            return TCL_ERROR;
515        }
516
517        for (i=0; i < cmapc; i += 4) {
518            double vals[4];
519            for (j=0; j < 4; j++) {
520                if (Tcl_GetDouble(interp, cmapv[i+j], &vals[j]) != TCL_OK) {
521                    Tcl_Free((char*)cmapv);
522                    Tcl_Free((char*)wmapv);
523                    return TCL_ERROR;
524                }
525                if (vals[j] < 0 || vals[j] > 1) {
526                    Tcl_Free((char*)cmapv);
527                    Tcl_Free((char*)wmapv);
528                            Tcl_AppendResult(interp, "bad value \"", cmapv[i+j],
529                        "\": should be in the range 0-1", (char*)NULL);
530                    return TCL_ERROR;
531                }
532            }
533            rFunc.define(vals[0], vals[1]);
534            gFunc.define(vals[0], vals[2]);
535            bFunc.define(vals[0], vals[3]);
536        }
537
538        for (i=0; i < wmapc; i += 2) {
539            double vals[2];
540            for (j=0; j < 2; j++) {
541                if (Tcl_GetDouble(interp, wmapv[i+j], &vals[j]) != TCL_OK) {
542                    Tcl_Free((char*)cmapv);
543                    Tcl_Free((char*)wmapv);
544                    return TCL_ERROR;
545                }
546                if (vals[j] < 0 || vals[j] > 1) {
547                    Tcl_Free((char*)cmapv);
548                    Tcl_Free((char*)wmapv);
549                            Tcl_AppendResult(interp, "bad value \"", wmapv[i+j],
550                        "\": should be in the range 0-1", (char*)NULL);
551                    return TCL_ERROR;
552                }
553            }
554            wFunc.define(vals[0], vals[1]);
555        }
556        Tcl_Free((char*)cmapv);
557        Tcl_Free((char*)wmapv);
558
559        // sample the given function into discrete slots
560        const int nslots = 256;
561        float data[4*nslots];
562        for (i=0; i < nslots; i++) {
563            double xval = double(i)/(nslots-1);
564            data[4*i]   = rFunc.value(xval);
565            data[4*i+1] = gFunc.value(xval);
566            data[4*i+2] = bFunc.value(xval);
567            data[4*i+3] = wFunc.value(xval);
568        }
569
570        // find or create this transfer function
571        int newEntry;
572        Tcl_HashEntry *entryPtr;
573        TransferFunction *tf;
574
575        entryPtr = Tcl_CreateHashEntry(&tftable, argv[2], &newEntry);
576        if (newEntry) {
577            tf = new TransferFunction(nslots, data);
578            Tcl_SetHashValue(entryPtr, (ClientData)tf);
579        } else {
580            tf = (TransferFunction*)Tcl_GetHashValue(entryPtr);
581            tf->update(data);
582        }
583
584        return TCL_OK;
585    }
586    Tcl_AppendResult(interp, "bad option \"", argv[1],
587        "\": should be define", (char*)NULL);
588    return TCL_ERROR;
589}
590
591/*
592 * ----------------------------------------------------------------------
593 * CLIENT COMMAND:
594 *   up axis
595 *
596 * Clients use this to set the "up" direction for all volumes.  Volumes
597 * are oriented such that this direction points upward.
598 * ----------------------------------------------------------------------
599 */
600static int
601UpCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
602{
603    if (argc != 2) {
604        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
605            " x|y|z|-x|-y|-z\"", (char*)NULL);
606        return TCL_ERROR;
607    }
608
609    int sign = 1;
610    char *axisName = argv[1];
611    if (*axisName == '-') {
612        sign = -1;
613        axisName++;
614    }
615
616    int axis;
617    if (GetAxis(interp, axisName, &axis) != TCL_OK) {
618        return TCL_ERROR;
619    }
620
621    updir = (axis+1)*sign;
622
623    return TCL_OK;
624}
625
626/*
627 * ----------------------------------------------------------------------
628 * CLIENT COMMAND:
629 *   volume axis label x|y|z <value> ?<volumeId> ...?
630 *   volume data state on|off ?<volumeId> ...?
631 *   volume outline state on|off ?<volumeId> ...?
632 *   volume outline color on|off ?<volumeId> ...?
633 *   volume shading transfunc <name> ?<volumeId> ...?
634 *   volume shading diffuse <value> ?<volumeId> ...?
635 *   volume shading specular <value> ?<volumeId> ...?
636 *   volume shading opacity <value> ?<volumeId> ...?
637 *   volume state on|off ?<volumeId> ...?
638 *
639 * Clients send these commands to manipulate the volumes.
640 * ----------------------------------------------------------------------
641 */
642static int
643VolumeCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
644{
645    if (argc < 2) {
646        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
647            " option arg arg...\"", (char*)NULL);
648        return TCL_ERROR;
649    }
650
651    char c = *argv[1];
652    if (c == 'a' && strcmp(argv[1],"axis") == 0) {
653        if (argc < 3) {
654            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
655                argv[1], " option ?arg arg...?\"", (char*)NULL);
656            return TCL_ERROR;
657        }
658        c = *argv[2];
659        if (c == 'l' && strcmp(argv[2],"label") == 0) {
660            if (argc < 4) {
661                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
662                    argv[1], " label x|y|z string ?volume ...?\"", (char*)NULL);
663                return TCL_ERROR;
664            }
665
666            int axis;
667            if (GetAxis(interp, argv[3], &axis) != TCL_OK) {
668                return TCL_ERROR;
669            }
670
671            vector<int> ivol;
672            if (GetVolumeIndices(interp, argc-5, argv+5, &ivol) != TCL_OK) {
673                return TCL_ERROR;
674            }
675
676            vector<int>::iterator iter = ivol.begin();
677            while (iter != ivol.end()) {
678                volume[*iter]->set_label(axis, argv[4]);
679                ++iter;
680            }
681            return TCL_OK;
682        }
683        Tcl_AppendResult(interp, "bad option \"", argv[2],
684            "\": should be label", (char*)NULL);
685        return TCL_ERROR;
686    }
687    else if (c == 'd' && strcmp(argv[1],"data") == 0) {
688        if (argc < 3) {
689            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
690                argv[1], " option ?arg arg...?\"", (char*)NULL);
691            return TCL_ERROR;
692        }
693        c = *argv[2];
694        if (c == 's' && strcmp(argv[2],"state") == 0) {
695            if (argc < 4) {
696                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
697                    argv[1], " state on|off ?volume ...?\"", (char*)NULL);
698                return TCL_ERROR;
699            }
700
701            int state;
702            if (Tcl_GetBoolean(interp, argv[3], &state) != TCL_OK) {
703                return TCL_ERROR;
704            }
705
706            vector<int> ivol;
707            if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) {
708                return TCL_ERROR;
709            }
710
711            vector<int>::iterator iter = ivol.begin();
712            while (iter != ivol.end()) {
713                if (state) {
714                    volume[*iter]->enable_data();
715                } else {
716                    volume[*iter]->disable_data();
717                }
718                ++iter;
719            }
720            return TCL_OK;
721        }
722        else if (c == 'f' && strcmp(argv[2],"follows") == 0) {
723            int nbytes;
724            if (Tcl_GetInt(interp, argv[3], &nbytes) != TCL_OK) {
725                return TCL_ERROR;
726            }
727
728            char fname[64];
729            sprintf(fname,"/tmp/nv%d.dat",getpid());
730            std::ofstream dfile(fname);
731
732            char buffer[8096];
733            while (nbytes > 0) {
734                int chunk = (sizeof(buffer) < nbytes) ? sizeof(buffer) : nbytes;
735                int status = fread(buffer, 1, chunk, stdin);
736                if (status > 0) {
737                    dfile.write(buffer,status);
738                    nbytes -= status;
739                } else {
740                    Tcl_AppendResult(interp, "data unpacking failed in file ",
741                        fname, (char*)NULL);
742                    return TCL_ERROR;
743                }
744            }
745            dfile.close();
746
747            char cmdstr[512];
748            sprintf(cmdstr, "mimedecode %s | gunzip -c > /tmp/nv%d.dx", fname, getpid());
749            if (system(cmdstr) != 0) {
750                Tcl_AppendResult(interp, "data unpacking failed in file ",
751                    fname, (char*)NULL);
752                return TCL_ERROR;
753            }
754
755            sprintf(fname,"/tmp/nv%d.dx",getpid());
756
757            int n = n_volumes;
758            Rappture::Outcome err = load_volume_file(n, fname);
759
760            sprintf(cmdstr, "rm -f /tmp/nv%d.dat /tmp/nv%d.dx", getpid(), getpid());
761            system(cmdstr);
762
763            if (err) {
764                Tcl_AppendResult(interp, err.remark().c_str(), (char*)NULL);
765                return TCL_ERROR;
766            }
767
768            //
769            // BE CAREFUL:  Set the number of slices to something
770            //   slightly different for each volume.  If we have
771            //   identical volumes at exactly the same position
772            //   with exactly the same number of slices, the second
773            //   volume will overwrite the first, so the first won't
774            //   appear at all.
775            //
776            volume[n]->set_n_slice(256-n);
777            volume[n]->disable_cutplane(0);
778            volume[n]->disable_cutplane(1);
779            volume[n]->disable_cutplane(2);
780            vol_render->add_volume(volume[n], get_transfunc("default"));
781
782            return TCL_OK;
783        }
784        Tcl_AppendResult(interp, "bad option \"", argv[2],
785            "\": should be follows or state", (char*)NULL);
786        return TCL_ERROR;
787    }
788    else if (c == 'o' && strcmp(argv[1],"outline") == 0) {
789        if (argc < 3) {
790            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
791                argv[1], " option ?arg arg...?\"", (char*)NULL);
792            return TCL_ERROR;
793        }
794        c = *argv[2];
795        if (c == 's' && strcmp(argv[2],"state") == 0) {
796            if (argc < 3) {
797                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
798                    argv[1], " state on|off ?volume ...? \"", (char*)NULL);
799                return TCL_ERROR;
800            }
801
802            int state;
803            if (Tcl_GetBoolean(interp, argv[3], &state) != TCL_OK) {
804                return TCL_ERROR;
805            }
806
807            vector<int> ivol;
808            if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) {
809                return TCL_ERROR;
810            }
811
812            vector<int>::iterator iter = ivol.begin();
813            while (iter != ivol.end()) {
814                if (state) {
815                    volume[*iter]->enable_outline();
816                } else {
817                    volume[*iter]->disable_outline();
818                }
819                ++iter;
820            }
821            return TCL_OK;
822        }
823        else if (c == 'c' && strcmp(argv[2],"color") == 0) {
824            if (argc < 3) {
825                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
826                    argv[1], " color {R G B} ?volume ...? \"", (char*)NULL);
827                return TCL_ERROR;
828            }
829
830            float rgb[3];
831            if (GetColor(interp, (char*) argv[3], rgb) != TCL_OK) {
832                return TCL_ERROR;
833            }
834
835            vector<int> ivol;
836            if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) {
837                return TCL_ERROR;
838            }
839
840            vector<int>::iterator iter = ivol.begin();
841            while (iter != ivol.end()) {
842                volume[*iter]->set_outline_color(rgb);
843                ++iter;
844            }
845            return TCL_OK;
846        }
847
848        Tcl_AppendResult(interp, "bad option \"", argv[2],
849            "\": should be color or state", (char*)NULL);
850        return TCL_ERROR;
851    }
852    else if (c == 's' && strcmp(argv[1],"shading") == 0) {
853        if (argc < 3) {
854            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
855                argv[1], " option ?arg arg...?\"", (char*)NULL);
856            return TCL_ERROR;
857        }
858        c = *argv[2];
859        if (c == 't' && strcmp(argv[2],"transfunc") == 0) {
860            if (argc < 4) {
861                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
862                    argv[1], " transfunc name ?volume ...?\"", (char*)NULL);
863                return TCL_ERROR;
864            }
865
866            TransferFunction *tf = get_transfunc(argv[3]);
867            if (tf == NULL) {
868                Tcl_AppendResult(interp, "transfer function \"", argv[3],
869                    "\" is not defined", (char*)NULL);
870                return TCL_ERROR;
871            }
872
873            vector<int> ivol;
874            if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) {
875                return TCL_ERROR;
876            }
877
878            vector<int>::iterator iter = ivol.begin();
879            while (iter != ivol.end()) {
880                vol_render->shade_volume(volume[*iter], tf);
881                ++iter;
882            }
883            return TCL_OK;
884        }
885        else if (c == 'd' && strcmp(argv[2],"diffuse") == 0) {
886            if (argc < 4) {
887                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
888                    argv[1], " diffuse value ?volume ...?\"", (char*)NULL);
889                return TCL_ERROR;
890            }
891
892            double dval;
893            if (Tcl_GetDouble(interp, argv[3], &dval) != TCL_OK) {
894                return TCL_ERROR;
895            }
896
897            vector<int> ivol;
898            if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) {
899                return TCL_ERROR;
900            }
901
902            vector<int>::iterator iter = ivol.begin();
903            while (iter != ivol.end()) {
904                volume[*iter]->set_diffuse((float)dval);
905                ++iter;
906            }
907            return TCL_OK;
908        }
909        else if (c == 'o' && strcmp(argv[2],"opacity") == 0) {
910            if (argc < 4) {
911                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
912                    argv[1], " opacity value ?volume ...?\"", (char*)NULL);
913                return TCL_ERROR;
914            }
915
916            double dval;
917            if (Tcl_GetDouble(interp, argv[3], &dval) != TCL_OK) {
918                return TCL_ERROR;
919            }
920
921            vector<int> ivol;
922            if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) {
923                return TCL_ERROR;
924            }
925
926            vector<int>::iterator iter = ivol.begin();
927            while (iter != ivol.end()) {
928                volume[*iter]->set_opacity_scale((float)dval);
929                ++iter;
930            }
931            return TCL_OK;
932        }
933        else if (c == 's' && strcmp(argv[2],"specular") == 0) {
934            if (argc < 4) {
935                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
936                    argv[1], " specular value ?volume ...?\"", (char*)NULL);
937                return TCL_ERROR;
938            }
939
940            double dval;
941            if (Tcl_GetDouble(interp, argv[3], &dval) != TCL_OK) {
942                return TCL_ERROR;
943            }
944
945            vector<int> ivol;
946            if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) {
947                return TCL_ERROR;
948            }
949
950            vector<int>::iterator iter = ivol.begin();
951            while (iter != ivol.end()) {
952                volume[*iter]->set_specular((float)dval);
953                ++iter;
954            }
955            return TCL_OK;
956        }
957        Tcl_AppendResult(interp, "bad option \"", argv[2],
958            "\": should be diffuse, opacity, specular, or transfunc", (char*)NULL);
959        return TCL_ERROR;
960    }
961    else if (c == 's' && strcmp(argv[1],"state") == 0) {
962        if (argc < 3) {
963            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
964                argv[1], " on|off ?volume...?\"", (char*)NULL);
965            return TCL_ERROR;
966        }
967
968        int state;
969        if (Tcl_GetBoolean(interp, argv[2], &state) != TCL_OK) {
970            return TCL_ERROR;
971        }
972
973        vector<int> ivol;
974        if (GetVolumeIndices(interp, argc-3, argv+3, &ivol) != TCL_OK) {
975            return TCL_ERROR;
976        }
977
978        vector<int>::iterator iter = ivol.begin();
979        while (iter != ivol.end()) {
980            if (state) {
981                volume[*iter]->enable();
982            } else {
983                volume[*iter]->disable();
984            }
985            ++iter;
986        }
987        return TCL_OK;
988    }
989
990    Tcl_AppendResult(interp, "bad option \"", argv[1],
991        "\": should be data, outline, shading, or state", (char*)NULL);
992    return TCL_ERROR;
993}
994
995/*
996 * ----------------------------------------------------------------------
997 * FUNCTION: GetVolumeIndices()
998 *
999 * Used internally to decode a series of volume index values and
1000 * store then in the specified vector.  If there are no volume index
1001 * arguments, this means "all volumes" to most commands, so all
1002 * active volume indices are stored in the vector.
1003 *
1004 * Updates pushes index values into the vector.  Returns TCL_OK or
1005 * TCL_ERROR to indicate an error.
1006 * ----------------------------------------------------------------------
1007 */
1008static int
1009GetVolumeIndices(Tcl_Interp *interp, int argc, CONST84 char *argv[],
1010    vector<int>* vectorPtr)
1011{
1012    if (argc == 0) {
1013        for (int n=0; n < volume.size(); n++) {
1014            if (volume[n] != NULL) {
1015                vectorPtr->push_back(n);
1016            }
1017        }
1018    } else {
1019        int ivol;
1020        for (int n=0; n < argc; n++) {
1021            if (Tcl_GetInt(interp, argv[n], &ivol) != TCL_OK) {
1022                return TCL_ERROR;
1023            }
1024            if (ivol < 0 || ivol >= volume.size()) {
1025                Tcl_AppendResult(interp, "bad volume index \"", argv[n],
1026                    "\"", (char*)NULL);
1027                return TCL_ERROR;
1028            }
1029            if (volume[ivol] != NULL) {
1030                vectorPtr->push_back(ivol);
1031            }
1032        }
1033    }
1034    return TCL_OK;
1035}
1036
1037/*
1038 * ----------------------------------------------------------------------
1039 * FUNCTION: GetAxis()
1040 *
1041 * Used internally to decode an axis value from a string ("x", "y",
1042 * or "z") to its index (0, 1, or 2).  Returns TCL_OK if successful,
1043 * along with a value in valPtr.  Otherwise, it returns TCL_ERROR
1044 * and an error message in the interpreter.
1045 * ----------------------------------------------------------------------
1046 */
1047static int
1048GetAxis(Tcl_Interp *interp, char *str, int *valPtr)
1049{
1050    if (strcmp(str,"x") == 0) {
1051        *valPtr = 0;
1052        return TCL_OK;
1053    }
1054    else if (strcmp(str,"y") == 0) {
1055        *valPtr = 1;
1056        return TCL_OK;
1057    }
1058    else if (strcmp(str,"z") == 0) {
1059        *valPtr = 2;
1060        return TCL_OK;
1061    }
1062    Tcl_AppendResult(interp, "bad axis \"", str,
1063        "\": should be x, y, or z", (char*)NULL);
1064    return TCL_ERROR;
1065}
1066
1067/*
1068 * ----------------------------------------------------------------------
1069 * FUNCTION: GetColor()
1070 *
1071 * Used internally to decode a color value from a string ("R G B")
1072 * as a list of three numbers 0-1.  Returns TCL_OK if successful,
1073 * along with RGB values in valPtr.  Otherwise, it returns TCL_ERROR
1074 * and an error message in the interpreter.
1075 * ----------------------------------------------------------------------
1076 */
1077static int
1078GetColor(Tcl_Interp *interp, char *str, float *rgbPtr)
1079{
1080    int rgbc;
1081    char **rgbv;
1082    if (Tcl_SplitList(interp, str, &rgbc, &rgbv) != TCL_OK) {
1083        return TCL_ERROR;
1084    }
1085    if (rgbc != 3) {
1086        Tcl_AppendResult(interp, "bad color \"", str,
1087            "\": should be {R G B} as double values 0-1", (char*)NULL);
1088        return TCL_ERROR;
1089    }
1090
1091    double rval, gval, bval;
1092    if (Tcl_GetDouble(interp, rgbv[0], &rval) != TCL_OK) {
1093        Tcl_Free((char*)rgbv);
1094        return TCL_ERROR;
1095    }
1096    if (Tcl_GetDouble(interp, rgbv[1], &gval) != TCL_OK) {
1097        Tcl_Free((char*)rgbv);
1098        return TCL_ERROR;
1099    }
1100    if (Tcl_GetDouble(interp, rgbv[2], &bval) != TCL_OK) {
1101        Tcl_Free((char*)rgbv);
1102        return TCL_ERROR;
1103    }
1104    Tcl_Free((char*)rgbv);
1105
1106    rgbPtr[0] = (float)rval;
1107    rgbPtr[1] = (float)gval;
1108    rgbPtr[2] = (float)bval;
1109
1110    return TCL_OK;
1111}
1112
1113/*
1114 * ----------------------------------------------------------------------
1115 * USAGE: debug("string", ...)
1116 *
1117 * Use this anywhere within the package to send a debug message
1118 * back to the client.  The string can have % fields as used by
1119 * the printf() package.  Any remaining arguments are treated as
1120 * field substitutions on that.
1121 * ----------------------------------------------------------------------
1122 */
1123void
1124debug(char *str)
1125{
1126    write(0, str, strlen(str));
1127}
1128
1129void
1130debug(char *str, double v1)
1131{
1132    char buffer[512];
1133    sprintf(buffer, str, v1);
1134    write(0, buffer, strlen(buffer));
1135}
1136
1137void
1138debug(char *str, double v1, double v2)
1139{
1140    char buffer[512];
1141    sprintf(buffer, str, v1, v2);
1142    write(0, buffer, strlen(buffer));
1143}
1144
1145void
1146debug(char *str, double v1, double v2, double v3)
1147{
1148    char buffer[512];
1149    sprintf(buffer, str, v1, v2, v3);
1150    write(0, buffer, strlen(buffer));
1151}
1152
1153
1154static int
1155PlaneNewCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])){
1156  fprintf(stderr, "load plane for 2D visualization command\n");
1157
1158  int index, w, h;
1159
1160  if (argc != 4) {
1161    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1162                " plane_index w h \"", (char*)NULL);
1163    return TCL_ERROR;
1164  }
1165  if (Tcl_GetInt(interp, argv[1], &index) != TCL_OK) {
1166        return TCL_ERROR;
1167  }
1168  if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) {
1169        return TCL_ERROR;
1170  }
1171  if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) {
1172        return TCL_ERROR;
1173  }
1174
1175  //Now read w*h*4 bytes. The server expects the plane to be a stream of floats
1176  char* tmp = new char[int(w*h*sizeof(float))];
1177  bzero(tmp, w*h*4);
1178  int status = read(0, tmp, w*h*sizeof(float));
1179  if (status <= 0){
1180    exit(0);
1181  }
1182 
1183  plane[index] = new Texture2D(w, h, GL_FLOAT, GL_LINEAR, 1, (float*)tmp);
1184 
1185  delete[] tmp;
1186  return TCL_OK;
1187}
1188
1189
1190static
1191int PlaneLinkCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])){
1192  fprintf(stderr, "link the plane to the 2D renderer command\n");
1193
1194  int plane_index, tf_index;
1195
1196  if (argc != 3) {
1197    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1198                " plane_index tf_index \"", (char*)NULL);
1199    return TCL_ERROR;
1200  }
1201  if (Tcl_GetInt(interp, argv[1], &plane_index) != TCL_OK) {
1202        return TCL_ERROR;
1203  }
1204  if (Tcl_GetInt(interp, argv[2], &tf_index) != TCL_OK) {
1205        return TCL_ERROR;
1206  }
1207
1208  //plane_render->add_plane(plane[plane_index], tf[tf_index]);
1209
1210  return TCL_OK;
1211}
1212
1213
1214//Enable a 2D plane for render
1215//The plane_index is the index mantained in the 2D plane renderer
1216static
1217int PlaneEnableCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])){
1218  fprintf(stderr, "enable a plane so the 2D renderer can render it command\n");
1219
1220  int plane_index, mode;
1221
1222  if (argc != 3) {
1223    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1224                " plane_index mode \"", (char*)NULL);
1225    return TCL_ERROR;
1226  }
1227  if (Tcl_GetInt(interp, argv[1], &plane_index) != TCL_OK) {
1228        return TCL_ERROR;
1229  }
1230  if (Tcl_GetInt(interp, argv[2], &mode) != TCL_OK) {
1231        return TCL_ERROR;
1232  }
1233
1234  if(mode==0)
1235    plane_render->set_active_plane(-1);
1236  else
1237    plane_render->set_active_plane(plane_index);
1238
1239  return TCL_OK;
1240}
1241
1242
1243//report errors related to CG shaders
1244void cgErrorCallback(void)
1245{
1246    CGerror lastError = cgGetError();
1247    if(lastError) {
1248        const char *listing = cgGetLastListing(g_context);
1249        printf("\n---------------------------------------------------\n");
1250        printf("%s\n\n", cgGetErrorString(lastError));
1251        printf("%s\n", listing);
1252        printf("-----------------------------------------------------\n");
1253        printf("Cg error, exiting...\n");
1254        cgDestroyContext(g_context);
1255        exit(-1);
1256    }
1257}
1258
1259
1260void init_glew(){
1261        GLenum err = glewInit();
1262        if (GLEW_OK != err)
1263        {
1264                //glew init failed, exit.
1265                fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
1266                getchar();
1267                assert(false);
1268        }
1269
1270        fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
1271}
1272
1273
1274
1275/* Load a 3D vector field from a dx-format file
1276 */
1277void
1278load_vector_file(int index, char *fname) {
1279    int dummy, nx, ny, nz, nxy, npts;
1280    double x0, y0, z0, dx, dy, dz, ddx, ddy, ddz;
1281    char line[128], type[128], *start;
1282    std::ifstream fin(fname);
1283
1284    do {
1285        fin.getline(line,sizeof(line)-1);
1286        for (start=&line[0]; *start == ' ' || *start == '\t'; start++)
1287            ;  // skip leading blanks
1288
1289        if (*start != '#') {  // skip comment lines
1290            if (sscanf(start, "object %d class gridpositions counts %d %d %d", &dummy, &nx, &ny, &nz) == 4) {
1291                // found grid size
1292            }
1293            else if (sscanf(start, "origin %lg %lg %lg", &x0, &y0, &z0) == 3) {
1294                // found origin
1295            }
1296            else if (sscanf(start, "delta %lg %lg %lg", &ddx, &ddy, &ddz) == 3) {
1297                // found one of the delta lines
1298                if (ddx != 0.0) { dx = ddx; }
1299                else if (ddy != 0.0) { dy = ddy; }
1300                else if (ddz != 0.0) { dz = ddz; }
1301            }
1302            else if (sscanf(start, "object %d class array type %s shape 3 rank 1 items %d data follows", &dummy, type, &npts) == 3) {
1303                if (npts != nx*ny*nz) {
1304                    std::cerr << "inconsistent data: expected " << nx*ny*nz << " points but found " << npts << " points" << std::endl;
1305                    return;
1306                }
1307                break;
1308            }
1309        }
1310    } while (!fin.eof());
1311
1312    // read data points
1313    if (!fin.eof()) {
1314        Rappture::Mesh1D xgrid(x0, x0+nx*dx, nx);
1315        Rappture::Mesh1D ygrid(y0, y0+ny*dy, ny);
1316        Rappture::Mesh1D zgrid(z0, z0+nz*dz, nz);
1317        Rappture::FieldRect3D xfield(xgrid, ygrid, zgrid);
1318        Rappture::FieldRect3D yfield(xgrid, ygrid, zgrid);
1319        Rappture::FieldRect3D zfield(xgrid, ygrid, zgrid);
1320
1321        double vx, vy, vz;
1322        int nread = 0;
1323        for (int ix=0; ix < nx; ix++) {
1324            for (int iy=0; iy < ny; iy++) {
1325                for (int iz=0; iz < nz; iz++) {
1326                    if (fin.eof() || nread > npts) {
1327                        break;
1328                    }
1329                    fin.getline(line,sizeof(line)-1);
1330                    if (sscanf(line, "%lg %lg %lg", &vx, &vy, &vz) == 3) {
1331                        int nindex = iz*nx*ny + iy*nx + ix;
1332                        xfield.define(nindex, vx);
1333                        yfield.define(nindex, vy);
1334                        zfield.define(nindex, vz);
1335                        nread++;
1336                    }
1337                }
1338            }
1339        }
1340
1341        // make sure that we read all of the expected points
1342        if (nread != nx*ny*nz) {
1343            std::cerr << "inconsistent data: expected " << nx*ny*nz << " points but found " << nread << " points" << std::endl;
1344            return;
1345        }
1346
1347        // figure out a good mesh spacing
1348        int nsample = 30;
1349        dx = xfield.rangeMax(Rappture::xaxis) - xfield.rangeMin(Rappture::xaxis);
1350        dy = xfield.rangeMax(Rappture::yaxis) - xfield.rangeMin(Rappture::yaxis);
1351        dz = xfield.rangeMax(Rappture::zaxis) - xfield.rangeMin(Rappture::zaxis);
1352        double dmin = pow((dx*dy*dz)/(nsample*nsample*nsample), 0.333);
1353
1354        nx = (int)ceil(dx/dmin);
1355        ny = (int)ceil(dy/dmin);
1356        nz = (int)ceil(dz/dmin);
1357
1358#ifndef NV40
1359        // must be an even power of 2 for older cards
1360            nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0)));
1361            ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0)));
1362            nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0)));
1363#endif
1364
1365        float *data = new float[3*nx*ny*nz];
1366
1367        std::cout << "generating " << nx << "x" << ny << "x" << nz << " = " << nx*ny*nz << " points" << std::endl;
1368
1369        // generate the uniformly sampled data that we need for a volume
1370        double vmin = 0.0;
1371        double vmax = 0.0;
1372        int ngen = 0;
1373        for (int iz=0; iz < nz; iz++) {
1374            double zval = z0 + iz*dmin;
1375            for (int iy=0; iy < ny; iy++) {
1376                double yval = y0 + iy*dmin;
1377                for (int ix=0; ix < nx; ix++) {
1378                    double xval = x0 + ix*dmin;
1379
1380                    vx = xfield.value(xval,yval,zval);
1381                    vy = yfield.value(xval,yval,zval);
1382                    vz = zfield.value(xval,yval,zval);
1383                    //vx = 1;
1384                    //vy = 1;
1385                    vz = 0;
1386                    double vm = sqrt(vx*vx + vy*vy + vz*vz);
1387
1388                    if (vm < vmin) { vmin = vm; }
1389                    if (vm > vmax) { vmax = vm; }
1390
1391                    data[ngen++] = vx;
1392                    data[ngen++] = vy;
1393                    data[ngen++] = vz;
1394                }
1395            }
1396        }
1397
1398        ngen = 0;
1399        for (ngen=0; ngen < npts; ngen++) {
1400            data[ngen] = (data[ngen]/(2.0*vmax) + 0.5);
1401        }
1402
1403        load_volume(index, nx, ny, nz, 3, data, vmin, vmax);
1404        delete [] data;
1405    } else {
1406        std::cerr << "WARNING: data not found in file " << fname << std::endl;
1407    }
1408}
1409
1410
1411/* Load a 3D volume from a dx-format file
1412 */
1413Rappture::Outcome
1414load_volume_file(int index, char *fname) {
1415    Rappture::Outcome result;
1416
1417    Rappture::MeshTri2D xymesh;
1418    int dummy, nx, ny, nz, nxy, npts;
1419    double x0, y0, z0, dx, dy, dz, ddx, ddy, ddz;
1420    char line[128], type[128], *start;
1421    std::ifstream fin(fname);
1422
1423    int isrect = 1;
1424
1425    do {
1426        fin.getline(line,sizeof(line)-1);
1427        for (start=&line[0]; *start == ' ' || *start == '\t'; start++)
1428            ;  // skip leading blanks
1429
1430        if (*start != '#') {  // skip comment lines
1431            if (sscanf(start, "object %d class gridpositions counts %d %d %d", &dummy, &nx, &ny, &nz) == 4) {
1432                // found grid size
1433                isrect = 1;
1434            }
1435            else if (sscanf(start, "object %d class array type float rank 1 shape 3 items %d data follows", &dummy, &nxy) == 2) {
1436                isrect = 0;
1437                double xx, yy, zz;
1438                for (int i=0; i < nxy; i++) {
1439                    fin.getline(line,sizeof(line)-1);
1440                    if (sscanf(line, "%lg %lg %lg", &xx, &yy, &zz) == 3) {
1441                        xymesh.addNode( Rappture::Node2D(xx,yy) );
1442                    }
1443                }
1444
1445                char fpts[128];
1446                sprintf(fpts, "/tmp/tmppts%d", getpid());
1447                char fcells[128];
1448                sprintf(fcells, "/tmp/tmpcells%d", getpid());
1449
1450                std::ofstream ftmp(fpts);
1451                // save corners of bounding box first, to work around meshing
1452                // problems in voronoi utility
1453                ftmp << xymesh.rangeMin(Rappture::xaxis) << " "
1454                     << xymesh.rangeMin(Rappture::yaxis) << std::endl;
1455                ftmp << xymesh.rangeMax(Rappture::xaxis) << " "
1456                     << xymesh.rangeMin(Rappture::yaxis) << std::endl;
1457                ftmp << xymesh.rangeMax(Rappture::xaxis) << " "
1458                     << xymesh.rangeMax(Rappture::yaxis) << std::endl;
1459                ftmp << xymesh.rangeMin(Rappture::xaxis) << " "
1460                     << xymesh.rangeMax(Rappture::yaxis) << std::endl;
1461                for (int i=0; i < nxy; i++) {
1462                    ftmp << xymesh.atNode(i).x() << " " << xymesh.atNode(i).y() << std::endl;
1463                }
1464                ftmp.close();
1465
1466                char cmdstr[512];
1467                sprintf(cmdstr, "voronoi -t < %s > %s", fpts, fcells);
1468                if (system(cmdstr) == 0) {
1469                    int cx, cy, cz;
1470                    std::ifstream ftri(fcells);
1471                    while (!ftri.eof()) {
1472                        ftri.getline(line,sizeof(line)-1);
1473                        if (sscanf(line, "%d %d %d", &cx, &cy, &cz) == 3) {
1474                            if (cx >= 4 && cy >= 4 && cz >= 4) {
1475                                // skip first 4 boundary points
1476                                xymesh.addCell(cx-4, cy-4, cz-4);
1477                            }
1478                        }
1479                    }
1480                    ftri.close();
1481                } else {
1482                    return result.error("triangularization failed");
1483                }
1484
1485                sprintf(cmdstr, "rm -f %s %s", fpts, fcells);
1486                system(cmdstr);
1487            }
1488            else if (sscanf(start, "object %d class regulararray count %d", &dummy, &nz) == 2) {
1489                // found z-grid
1490            }
1491            else if (sscanf(start, "origin %lg %lg %lg", &x0, &y0, &z0) == 3) {
1492                // found origin
1493            }
1494            else if (sscanf(start, "delta %lg %lg %lg", &ddx, &ddy, &ddz) == 3) {
1495                // found one of the delta lines
1496                if (ddx != 0.0) { dx = ddx; }
1497                else if (ddy != 0.0) { dy = ddy; }
1498                else if (ddz != 0.0) { dz = ddz; }
1499            }
1500            else if (sscanf(start, "object %d class array type %s rank 0 items %d data follows", &dummy, type, &npts) == 3) {
1501                if (isrect && (npts != nx*ny*nz)) {
1502                    char mesg[256];
1503                    sprintf(mesg,"inconsistent data: expected %d points but found %d points", nx*ny*nz, npts);
1504                    return result.error(mesg);
1505                }
1506                else if (!isrect && (npts != nxy*nz)) {
1507                    char mesg[256];
1508                    sprintf(mesg,"inconsistent data: expected %d points but found %d points", nxy*nz, npts);
1509                    return result.error(mesg);
1510                }
1511                break;
1512            }
1513        }
1514    } while (!fin.eof());
1515
1516    // read data points
1517    if (!fin.eof()) {
1518        if (isrect) {
1519            Rappture::Mesh1D xgrid(x0, x0+nx*dx, nx);
1520            Rappture::Mesh1D ygrid(y0, y0+ny*dy, ny);
1521            Rappture::Mesh1D zgrid(z0, z0+nz*dz, nz);
1522            Rappture::FieldRect3D field(xgrid, ygrid, zgrid);
1523
1524            double dval;
1525            int nread = 0;
1526            for (int ix=0; ix < nx; ix++) {
1527                for (int iy=0; iy < ny; iy++) {
1528                    for (int iz=0; iz < nz; iz++) {
1529                        if (fin.eof() || nread > npts) {
1530                            break;
1531                        }
1532                        fin.getline(line,sizeof(line)-1);
1533                        if (sscanf(line, "%lg", &dval) == 1) {
1534                            int nindex = iz*nx*ny + iy*nx + ix;
1535                            field.define(nindex, dval);
1536                            nread++;
1537                        }
1538                    }
1539                }
1540            }
1541
1542            // make sure that we read all of the expected points
1543            if (nread != nx*ny*nz) {
1544                char mesg[256];
1545                sprintf(mesg,"inconsistent data: expected %d points but found %d points", nx*ny*nz, nread);
1546                result.error(mesg);
1547                return result;
1548            }
1549
1550            // figure out a good mesh spacing
1551            int nsample = 30;
1552            dx = field.rangeMax(Rappture::xaxis) - field.rangeMin(Rappture::xaxis);
1553            dy = field.rangeMax(Rappture::yaxis) - field.rangeMin(Rappture::yaxis);
1554            dz = field.rangeMax(Rappture::zaxis) - field.rangeMin(Rappture::zaxis);
1555            double dmin = pow((dx*dy*dz)/(nsample*nsample*nsample), 0.333);
1556
1557            nx = (int)ceil(dx/dmin);
1558            ny = (int)ceil(dy/dmin);
1559            nz = (int)ceil(dz/dmin);
1560
1561#ifndef NV40
1562            // must be an even power of 2 for older cards
1563                nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0)));
1564                ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0)));
1565                nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0)));
1566#endif
1567
1568            float *data = new float[4*nx*ny*nz];
1569
1570            double vmin = field.valueMin();
1571            double dv = field.valueMax() - field.valueMin();
1572            if (dv == 0.0) { dv = 1.0; }
1573
1574            // generate the uniformly sampled data that we need for a volume
1575            int ngen = 0;
1576            for (int iz=0; iz < nz; iz++) {
1577                double zval = z0 + iz*dmin;
1578                for (int iy=0; iy < ny; iy++) {
1579                    double yval = y0 + iy*dmin;
1580                    for (int ix=0; ix < nx; ix++) {
1581                        double xval = x0 + ix*dmin;
1582                        double v = field.value(xval,yval,zval);
1583
1584                        // scale all values [0-1], -1 => out of bounds
1585                        v = (isnan(v)) ? -1.0 : (v - vmin)/dv;
1586                        data[ngen] = v;
1587                        ngen += 4;
1588                    }
1589                }
1590            }
1591
1592            // Compute the gradient of this data.  BE CAREFUL: center
1593            // calculation on each node to avoid skew in either direction.
1594            ngen = 0;
1595            for (int iz=0; iz < nz; iz++) {
1596                for (int iy=0; iy < ny; iy++) {
1597                    for (int ix=0; ix < nx; ix++) {
1598                        // gradient in x-direction
1599                        double valm1 = (ix == 0) ? 0.0 : data[ngen-1];
1600                        double valp1 = (ix == nx-1) ? 0.0 : data[ngen+1];
1601                        if (valm1 < 0 || valp1 < 0) {
1602                            data[ngen+1] = 0.0;
1603                        } else {
1604                            data[ngen+1] = valp1-valm1; // assume dx=1
1605                        }
1606
1607                        // gradient in y-direction
1608                        valm1 = (iy == 0) ? 0.0 : data[ngen-4*nx];
1609                        valp1 = (iy == ny-1) ? 0.0 : data[ngen+4*nx];
1610                        if (valm1 < 0 || valp1 < 0) {
1611                            data[ngen+2] = 0.0;
1612                        } else {
1613                            data[ngen+2] = valp1-valm1; // assume dy=1
1614                        }
1615
1616                        // gradient in z-direction
1617                        valm1 = (iz == 0) ? 0.0 : data[ngen-4*nx*ny];
1618                        valp1 = (iz == nz-1) ? 0.0 : data[ngen+4*nx*ny];
1619                        if (valm1 < 0 || valp1 < 0) {
1620                            data[ngen+3] = 0.0;
1621                        } else {
1622                            data[ngen+3] = valp1-valm1; // assume dz=1
1623                        }
1624
1625                        ngen += 4;
1626                    }
1627                }
1628            }
1629
1630            load_volume(index, nx, ny, nz, 4, data,
1631                field.valueMin(), field.valueMax());
1632
1633            delete [] data;
1634
1635        } else {
1636            Rappture::Mesh1D zgrid(z0, z0+nz*dz, nz);
1637            Rappture::FieldPrism3D field(xymesh, zgrid);
1638
1639            double dval;
1640            int nread = 0;
1641            int ixy = 0;
1642            int iz = 0;
1643            while (!fin.eof() && nread < npts) {
1644                if (!(fin >> dval).fail()) {
1645                    int nid = nxy*iz + ixy;
1646                    field.define(nid, dval);
1647
1648                    nread++;
1649                    if (++iz >= nz) {
1650                        iz = 0;
1651                        ixy++;
1652                    }
1653                }
1654            }
1655
1656            // make sure that we read all of the expected points
1657            if (nread != nxy*nz) {
1658                char mesg[256];
1659                sprintf(mesg,"inconsistent data: expected %d points but found %d points", nxy*nz, nread);
1660                return result.error(mesg);
1661            }
1662
1663            // figure out a good mesh spacing
1664            int nsample = 30;
1665            x0 = field.rangeMin(Rappture::xaxis);
1666            dx = field.rangeMax(Rappture::xaxis) - field.rangeMin(Rappture::xaxis);
1667            y0 = field.rangeMin(Rappture::yaxis);
1668            dy = field.rangeMax(Rappture::yaxis) - field.rangeMin(Rappture::yaxis);
1669            z0 = field.rangeMin(Rappture::zaxis);
1670            dz = field.rangeMax(Rappture::zaxis) - field.rangeMin(Rappture::zaxis);
1671            double dmin = pow((dx*dy*dz)/(nsample*nsample*nsample), 0.333);
1672
1673            nx = (int)ceil(dx/dmin);
1674            ny = (int)ceil(dy/dmin);
1675            nz = (int)ceil(dz/dmin);
1676#ifndef NV40
1677            // must be an even power of 2 for older cards
1678                nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0)));
1679                ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0)));
1680                nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0)));
1681#endif
1682            float *data = new float[4*nx*ny*nz];
1683
1684            double vmin = field.valueMin();
1685            double dv = field.valueMax() - field.valueMin();
1686            if (dv == 0.0) { dv = 1.0; }
1687
1688            // generate the uniformly sampled data that we need for a volume
1689            int ngen = 0;
1690            for (iz=0; iz < nz; iz++) {
1691                double zval = z0 + iz*dmin;
1692                for (int iy=0; iy < ny; iy++) {
1693                    double yval = y0 + iy*dmin;
1694                    for (int ix=0; ix < nx; ix++) {
1695                        double xval = x0 + ix*dmin;
1696                        double v = field.value(xval,yval,zval);
1697
1698                        // scale all values [0-1], -1 => out of bounds
1699                        v = (isnan(v)) ? -1.0 : (v - vmin)/dv;
1700                        data[ngen] = v;
1701
1702                        ngen += 4;
1703                    }
1704                }
1705            }
1706
1707            // Compute the gradient of this data.  BE CAREFUL: center
1708            // calculation on each node to avoid skew in either direction.
1709            ngen = 0;
1710            for (int iz=0; iz < nz; iz++) {
1711                for (int iy=0; iy < ny; iy++) {
1712                    for (int ix=0; ix < nx; ix++) {
1713                        // gradient in x-direction
1714                        double valm1 = (ix == 0) ? 0.0 : data[ngen-1];
1715                        double valp1 = (ix == nx-1) ? 0.0 : data[ngen+1];
1716                        if (valm1 < 0 || valp1 < 0) {
1717                            data[ngen+1] = 0.0;
1718                        } else {
1719                            data[ngen+1] = valp1-valm1; // assume dx=1
1720                        }
1721
1722                        // gradient in y-direction
1723                        valm1 = (iy == 0) ? 0.0 : data[ngen-4*nx];
1724                        valp1 = (iy == ny-1) ? 0.0 : data[ngen+4*nx];
1725                        if (valm1 < 0 || valp1 < 0) {
1726                            data[ngen+2] = 0.0;
1727                        } else {
1728                            data[ngen+2] = valp1-valm1; // assume dy=1
1729                        }
1730
1731                        // gradient in z-direction
1732                        valm1 = (iz == 0) ? 0.0 : data[ngen-4*nx*ny];
1733                        valp1 = (iz == nz-1) ? 0.0 : data[ngen+4*nx*ny];
1734                        if (valm1 < 0 || valp1 < 0) {
1735                            data[ngen+3] = 0.0;
1736                        } else {
1737                            data[ngen+3] = valp1-valm1; // assume dz=1
1738                        }
1739
1740                        ngen += 4;
1741                    }
1742                }
1743            }
1744
1745            load_volume(index, nx, ny, nz, 4, data,
1746                field.valueMin(), field.valueMax());
1747
1748            delete [] data;
1749        }
1750    } else {
1751        char mesg[256];
1752        sprintf(mesg,"data not found in file %s", fname);
1753        return result.error(mesg);
1754    }
1755
1756    //
1757    // Center this new volume on the origin.
1758    //
1759    float dx0 = -0.5;
1760    float dy0 = -0.5*dy/dx;
1761    float dz0 = -0.5*dz/dx;
1762    volume[index]->move(Vector3(dx0, dy0, dz0));
1763
1764    return result;
1765}
1766
1767/* Load a 3D volume
1768 * index: the index into the volume array, which stores pointers to 3D volume instances
1769 * data: pointer to an array of floats. 
1770 * n_component: the number of scalars for each space point.
1771 *              All component scalars for a point are placed consequtively in data array
1772 * width, height and depth: number of points in each dimension
1773 */
1774void load_volume(int index, int width, int height, int depth,
1775    int n_component, float* data, double vmin, double vmax)
1776{
1777    while (n_volumes <= index) {
1778        volume.push_back(NULL);
1779        n_volumes++;
1780    }
1781
1782    if (volume[index] != NULL) {
1783        delete volume[index];
1784        volume[index] = NULL;
1785    }
1786
1787    volume[index] = new Volume(0.f, 0.f, 0.f, width, height, depth, 1.,
1788                                 n_component, data, vmin, vmax);
1789    assert(volume[index]!=0);
1790}
1791
1792
1793// get a colormap 1D texture by name
1794TransferFunction*
1795get_transfunc(char *name) {
1796    Tcl_HashEntry *entryPtr;
1797    entryPtr = Tcl_FindHashEntry(&tftable, name);
1798    if (entryPtr) {
1799        return (TransferFunction*)Tcl_GetHashValue(entryPtr);
1800    }
1801    return NULL;
1802}
1803
1804
1805//Update the transfer function using local GUI in the non-server mode
1806extern void update_tf_texture(){
1807  glutSetWindow(render_window);
1808
1809  //fprintf(stderr, "tf update\n");
1810  TransferFunction *tf = get_transfunc("default");
1811  if (tf == NULL) return;
1812
1813  float data[256*4];
1814  for(int i=0; i<256; i++){
1815    data[4*i+0] = color_table[i][0];
1816    data[4*i+1] = color_table[i][1];
1817    data[4*i+2] = color_table[i][2];
1818    data[4*i+3] = color_table[i][3];
1819    //fprintf(stderr, "(%f,%f,%f,%f) ", data[4*i+0], data[4*i+1], data[4*i+2], data[4*i+3]);
1820  }
1821
1822  tf->update(data);
1823
1824#ifdef EVENTLOG
1825  float param[3] = {0,0,0};
1826  Event* tmp = new Event(EVENT_ROTATE, param, get_time_interval());
1827  tmp->write(event_log);
1828  delete tmp;
1829#endif
1830}
1831
1832
1833//initialize frame buffer objects for offscreen rendering
1834void init_offscreen_buffer(){
1835
1836  //initialize final fbo for final display
1837  glGenFramebuffersEXT(1, &final_fbo);
1838  glGenTextures(1, &final_color_tex);
1839  glGenRenderbuffersEXT(1, &final_depth_rb);
1840
1841  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
1842
1843  //initialize final color texture
1844  glBindTexture(GL_TEXTURE_2D, final_color_tex);
1845  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1846  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1847#ifdef NV40
1848  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, win_width, win_height, 0,
1849               GL_RGB, GL_INT, NULL);
1850#else
1851  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0,
1852               GL_RGB, GL_INT, NULL);
1853#endif
1854  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
1855                            GL_COLOR_ATTACHMENT0_EXT,
1856                            GL_TEXTURE_2D, final_color_tex, 0);
1857
1858  // initialize final depth renderbuffer
1859  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb);
1860  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
1861                           GL_DEPTH_COMPONENT24, win_width, win_height);
1862  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
1863                               GL_DEPTH_ATTACHMENT_EXT,
1864                               GL_RENDERBUFFER_EXT, final_depth_rb);
1865
1866  // Check framebuffer completeness at the end of initialization.
1867  CHECK_FRAMEBUFFER_STATUS();
1868  assert(glGetError()==0);
1869}
1870
1871
1872//resize the offscreen buffer
1873void resize_offscreen_buffer(int w, int h){
1874  win_width = w;
1875  win_height = h;
1876
1877  //fprintf(stderr, "screen_buffer size: %d\n", sizeof(screen_buffer));
1878
1879  if (screen_buffer) {
1880      delete[] screen_buffer;
1881      screen_buffer = NULL;
1882  }
1883  screen_buffer = new unsigned char[4*win_width*win_height];
1884  assert(screen_buffer != NULL);
1885
1886  //delete the current render buffer resources
1887  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
1888  glDeleteTextures(1, &final_color_tex);
1889  glDeleteFramebuffersEXT(1, &final_fbo);
1890
1891  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb);
1892  glDeleteRenderbuffersEXT(1, &final_depth_rb);
1893fprintf(stdin,"  after glDeleteRenderbuffers\n");
1894
1895  //change the camera setting
1896  cam->set_screen_size(win_width, win_height);
1897  plane_render->set_screen_size(win_width, win_height);
1898
1899  //Reinitialize final fbo for final display
1900  glGenFramebuffersEXT(1, &final_fbo);
1901  glGenTextures(1, &final_color_tex);
1902  glGenRenderbuffersEXT(1, &final_depth_rb);
1903fprintf(stdin,"  after glGenRenderbuffers\n");
1904
1905  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
1906
1907  //initialize final color texture
1908  glBindTexture(GL_TEXTURE_2D, final_color_tex);
1909  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1910  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1911#ifdef NV40
1912  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, win_width, win_height, 0,
1913               GL_RGB, GL_INT, NULL);
1914#else
1915  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0,
1916               GL_RGB, GL_INT, NULL);
1917#endif
1918  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
1919                            GL_COLOR_ATTACHMENT0_EXT,
1920                            GL_TEXTURE_2D, final_color_tex, 0);
1921fprintf(stdin,"  after glFramebufferTexture2DEXT\n");
1922       
1923  // initialize final depth renderbuffer
1924  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb);
1925  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
1926                           GL_DEPTH_COMPONENT24, win_width, win_height);
1927  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
1928                               GL_DEPTH_ATTACHMENT_EXT,
1929                               GL_RENDERBUFFER_EXT, final_depth_rb);
1930fprintf(stdin,"  after glFramebufferRenderEXT\n");
1931
1932  // Check framebuffer completeness at the end of initialization.
1933  CHECK_FRAMEBUFFER_STATUS();
1934  assert(glGetError()==0);
1935fprintf(stdin,"  after assert\n");
1936}
1937
1938
1939void init_cg(){
1940    cgSetErrorCallback(cgErrorCallback);
1941    g_context = cgCreateContext();
1942
1943#ifdef NEW_CG
1944    m_posvel_fprog = loadProgram(g_context, CG_PROFILE_FP40, CG_SOURCE, "/opt/nanovis/lib/shaders/update_pos_vel.cg");
1945    m_posvel_timestep_param  = cgGetNamedParameter(m_posvel_fprog, "timestep");
1946    m_posvel_damping_param   = cgGetNamedParameter(m_posvel_fprog, "damping");
1947    m_posvel_gravity_param   = cgGetNamedParameter(m_posvel_fprog, "gravity");
1948    m_posvel_spherePos_param = cgGetNamedParameter(m_posvel_fprog, "spherePos");
1949    m_posvel_sphereVel_param = cgGetNamedParameter(m_posvel_fprog, "sphereVel");
1950#endif
1951}
1952
1953
1954//switch shader to change render mode
1955void switch_shader(int choice){
1956
1957  switch (choice){
1958    case 0:
1959      break;
1960
1961   case 1:
1962      break;
1963     
1964   default:
1965      break;
1966  }
1967}
1968
1969void init_particles(){
1970  //random placement on a slice
1971  float* data = new float[psys->psys_width * psys->psys_height * 4];
1972  bzero(data, sizeof(float)*4* psys->psys_width * psys->psys_height);
1973
1974  for (int i=0; i<psys->psys_width; i++){
1975    for (int j=0; j<psys->psys_height; j++){
1976      int index = i + psys->psys_height*j;
1977      bool particle = rand() % 256 > 150;
1978      //particle = true;
1979      if(particle) /*&& i/float(psys->psys_width)>0.3 && i/float(psys->psys_width)<0.7
1980                      && j/float(psys->psys_height)>0.1 && j/float(psys->psys_height)<0.4)*/
1981      {
1982        //assign any location (x,y,z) in range [0,1]
1983        data[4*index] = lic_slice_x;
1984        data[4*index+1]= j/float(psys->psys_height);
1985        data[4*index+2]= i/float(psys->psys_width);
1986        data[4*index+3]= 30; //shorter life span, quicker iterations   
1987      }
1988      else
1989      {
1990        data[4*index] = 0;
1991        data[4*index+1]= 0;
1992        data[4*index+2]= 0;
1993        data[4*index+3]= 0;     
1994      }
1995    }
1996   }
1997
1998  psys->initialize((Particle*)data);
1999  delete[] data;
2000}
2001
2002
2003//init line integral convolution
2004void init_lic(){
2005  lic = new Lic(NMESH, win_width, win_height, 0.3, g_context, volume[1]->id,
2006                  volume[1]->aspect_ratio_width,
2007                  volume[1]->aspect_ratio_height,
2008                  volume[1]->aspect_ratio_depth);
2009}
2010
2011//init the particle system using vector field volume->[1]
2012void init_particle_system(){
2013   psys = new ParticleSystem(NMESH, NMESH, g_context, volume[1]->id,
2014                   1./volume[1]->aspect_ratio_width,
2015                   1./volume[1]->aspect_ratio_height,
2016                   1./volume[1]->aspect_ratio_depth);
2017
2018   init_particles();    //fill initial particles
2019}
2020
2021
2022void make_test_2D_data(){
2023
2024  int w = 300;
2025  int h = 200;
2026  float* data = new float[w*h];
2027
2028  //procedurally make a gradient plane
2029  for(int j=0; j<h; j++){
2030    for(int i=0; i<w; i++){
2031      data[w*j+i] = float(i)/float(w);
2032    }
2033  }
2034
2035  plane[0] = new Texture2D(w, h, GL_FLOAT, GL_LINEAR, 1, data);
2036
2037  delete[] data;
2038}
2039
2040
2041/*----------------------------------------------------*/
2042void initGL(void)
2043{
2044   system_info();
2045   init_glew();
2046
2047   //buffer to store data read from the screen
2048   if (screen_buffer) {
2049       delete[] screen_buffer;
2050       screen_buffer = NULL;
2051   }
2052   screen_buffer = new unsigned char[4*win_width*win_height];
2053   assert(screen_buffer != NULL);
2054
2055   //create the camera with default setting
2056   cam = new Camera(win_width, win_height,
2057                   live_obj_x, live_obj_y, live_obj_z,
2058                   0., 0., 100.,
2059                   (int)live_rot_x, (int)live_rot_y, (int)live_rot_z);
2060
2061   glEnable(GL_TEXTURE_2D);
2062   glShadeModel(GL_FLAT);
2063   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2064   glClearColor(0,0,0,1);
2065   glClear(GL_COLOR_BUFFER_BIT);
2066
2067   //initialize lighting
2068   GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
2069   GLfloat mat_shininess[] = {30.0};
2070   GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
2071   GLfloat green_light[] = {0.1, 0.5, 0.1, 1.0};
2072
2073   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
2074   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
2075   glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
2076   glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);     
2077   glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light);
2078   glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);     
2079
2080   // init table of transfer functions
2081   Tcl_InitHashTable(&tftable, TCL_STRING_KEYS);
2082
2083   //check if performance query is supported
2084   if(check_query_support()){
2085     //create queries to count number of rendered pixels
2086     perf = new PerfQuery();
2087   }
2088
2089   //load_volume_file(0, "./data/A-apbs-2-out-potential-PE0.dx");
2090   //load_volume_file(0, "./data/nw-AB-Vg=0.000-Vd=1.000-potential.dx");
2091   //load_volume_file(0, "./data/test2.dx");
2092   //load_volume_file(0, "./data/mu-wire-3d.dx"); //I added this line to debug: Wei
2093   //load_volume_file(0, "./data/input_nd_dx_4"); //take a VERY long time?
2094   //load_vector_file(1, "./data/J-wire-vec.dx");
2095   //load_volume_file(1, "./data/mu-wire-3d.dx");  //I added this line to debug: Wei
2096   //load_volume_file(3, "./data/mu-wire-3d.dx");
2097   //load_volume_file(4, "./data/mu-wire-3d.dx");
2098
2099   init_offscreen_buffer();    //frame buffer object for offscreen rendering
2100   init_cg();   //create cg shader context
2101
2102   //create volume renderer and add volumes to it
2103   vol_render = new VolumeRenderer(g_context);
2104
2105   
2106   /*
2107   //I added this to debug : Wei
2108   float tmp_data[4*124];
2109   memset(tmp_data, 0, 4*4*124);
2110   TransferFunction* tmp_tf = new TransferFunction(124, tmp_data);
2111   vol_render->add_volume(volume[0], tmp_tf);
2112   volume[0]->get_cutplane(0)->enabled = false;
2113   volume[0]->get_cutplane(1)->enabled = false;
2114   volume[0]->get_cutplane(2)->enabled = false;
2115
2116   //volume[1]->move(Vector3(0.5, 0.6, 0.7));
2117   //vol_render->add_volume(volume[1], tmp_tf);
2118   */
2119
2120
2121   //create an 2D plane renderer
2122   plane_render = new PlaneRenderer(g_context, win_width, win_height);
2123   make_test_2D_data();
2124
2125   plane_render->add_plane(plane[0], get_transfunc("default"));
2126
2127   assert(glGetError()==0);
2128
2129   //init_particle_system();
2130   //init_lic();
2131}
2132
2133
2134
2135void initTcl(){
2136    interp = Tcl_CreateInterp();
2137    Tcl_MakeSafe(interp);
2138
2139    Tcl_DStringInit(&cmdbuffer);
2140
2141    // manipulate the viewpoint
2142    Tcl_CreateCommand(interp, "camera", CameraCmd,
2143        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
2144
2145    // turn on/off cut planes in x/y/z directions
2146    Tcl_CreateCommand(interp, "cutplane", CutplaneCmd,
2147        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
2148
2149    // request the legend for a plot (transfer function)
2150    Tcl_CreateCommand(interp, "legend", LegendCmd,
2151        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
2152
2153    // change the size of the screen (size of picture generated)
2154    Tcl_CreateCommand(interp, "screen", ScreenCmd,
2155        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
2156
2157    // manipulate transfer functions
2158    Tcl_CreateCommand(interp, "transfunc", TransfuncCmd,
2159        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
2160
2161    // set the "up" direction for volumes
2162    Tcl_CreateCommand(interp, "up", UpCmd,
2163        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
2164
2165    // manipulate volume data
2166    Tcl_CreateCommand(interp, "volume", VolumeCmd,
2167        (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
2168
2169    // create a default transfer function
2170    if (Tcl_Eval(interp, def_transfunc) != TCL_OK) {
2171        fprintf(stdin, "WARNING: bad default transfer function\n");
2172        fprintf(stdin, Tcl_GetStringResult(interp));
2173    }
2174}
2175
2176
2177void read_screen(){
2178  //glBindTexture(GL_TEXTURE_2D, 0);
2179  //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
2180 
2181  glReadPixels(0, 0, win_width, win_height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
2182  assert(glGetError()==0);
2183}
2184
2185void display();
2186
2187
2188#if DO_RLE
2189char rle[512*512*3];
2190int rle_size;
2191
2192short offsets[512*512*3];
2193int offsets_size;
2194
2195void do_rle(){
2196  int len = win_width*win_height*3;
2197  rle_size = 0;
2198  offsets_size = 0;
2199
2200  int i=0;
2201  while(i<len){
2202    if (screen_buffer[i] == 0) {
2203      int pos = i+1;
2204      while ( (pos<len) && (screen_buffer[pos] == 0)) {
2205        pos++;
2206      }
2207      offsets[offsets_size++] = -(pos - i);
2208      i = pos;
2209    }
2210
2211    else {
2212      int pos;
2213      for (pos = i; (pos<len) && (screen_buffer[pos] != 0); pos++) {
2214        rle[rle_size++] = screen_buffer[pos];
2215      }
2216      offsets[offsets_size++] = (pos - i);
2217      i = pos;
2218    }
2219
2220  }
2221}
2222#endif
2223
2224// used internally to build up the BMP file header
2225// writes an integer value into the header data structure at pos
2226void
2227bmp_header_add_int(unsigned char* header, int& pos, int data)
2228{
2229    header[pos++] = data & 0xff;
2230    header[pos++] = (data >> 8) & 0xff;
2231    header[pos++] = (data >> 16) & 0xff;
2232    header[pos++] = (data >> 24) & 0xff;
2233}
2234
2235void
2236bmp_write(const char* cmd)
2237{
2238    unsigned char header[54];
2239    int pos = 0;
2240    header[pos++] = 'B';
2241    header[pos++] = 'M';
2242
2243    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
2244    // on each scan line.  If need be, we add padding to each line.
2245    int pad = 0;
2246    if ((3*win_width) % 4 > 0) {
2247        pad = 4 - ((3*win_width) % 4);
2248    }
2249
2250    // file size in bytes
2251    int fsize = (3*win_width+pad)*win_height + sizeof(header);
2252    bmp_header_add_int(header, pos, fsize);
2253
2254    // reserved value (must be 0)
2255    bmp_header_add_int(header, pos, 0);
2256
2257    // offset in bytes to start of bitmap data
2258    bmp_header_add_int(header, pos, sizeof(header));
2259
2260    // size of the BITMAPINFOHEADER
2261    bmp_header_add_int(header, pos, 40);
2262
2263    // width of the image in pixels
2264    bmp_header_add_int(header, pos, win_width);
2265
2266    // height of the image in pixels
2267    bmp_header_add_int(header, pos, win_height);
2268
2269    // 1 plane + (24 bits/pixel << 16)
2270    bmp_header_add_int(header, pos, 1572865);
2271
2272    // no compression
2273    // size of image for compression
2274    bmp_header_add_int(header, pos, 0);
2275    bmp_header_add_int(header, pos, 0);
2276
2277    // x pixels per meter
2278    // y pixels per meter
2279    bmp_header_add_int(header, pos, 0);
2280    bmp_header_add_int(header, pos, 0);
2281
2282    // number of colors used (0 = compute from bits/pixel)
2283    // number of important colors (0 = all colors important)
2284    bmp_header_add_int(header, pos, 0);
2285    bmp_header_add_int(header, pos, 0);
2286
2287    // BE CAREFUL: BMP format wants BGR ordering for screen data
2288    unsigned char* scr = screen_buffer;
2289    for (int row=0; row < win_height; row++) {
2290        for (int col=0; col < win_width; col++) {
2291            unsigned char tmp = scr[2];
2292            scr[2] = scr[0];  // B
2293            scr[0] = tmp;     // R
2294            scr += 3;
2295        }
2296        scr += pad;  // skip over padding already in screen data
2297    }
2298
2299    std::ostringstream result;
2300    result << cmd << " " << fsize << "\n";
2301    write(0, result.str().c_str(), result.str().size());
2302
2303    write(0, header, sizeof(header));
2304    write(0, screen_buffer, (3*win_width+pad)*win_height);
2305}
2306
2307
2308void xinetd_listen(){
2309
2310    int flags = fcntl(0, F_GETFL, 0);
2311    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2312
2313    int status = TCL_OK;
2314    int npass = 0;
2315
2316    //
2317    //  Read and execute as many commands as we can from stdin...
2318    //
2319    while (status == TCL_OK) {
2320        //
2321        //  Read the next command from the buffer.  First time through
2322        //  we block here and wait if necessary until a command comes in.
2323        //
2324        //  BE CAREFUL:  Read only one command, up to a newline.
2325        //  The "volume data follows" command needs to be able to read
2326        //  the data immediately following the command, and we shouldn't
2327        //  consume it here.
2328        //
2329        while (1) {
2330            char c = getchar();
2331            if (c <= 0) {
2332                if (npass == 0) {
2333                    exit(0);  // EOF -- we're done!
2334                } else {
2335                    break;
2336                }
2337            }
2338            Tcl_DStringAppend(&cmdbuffer, &c, 1);
2339
2340            if (c=='\n' && Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer))) {
2341                break;
2342            }
2343        }
2344
2345        // no command? then we're done for now
2346        if (Tcl_DStringLength(&cmdbuffer) == 0) {
2347            break;
2348        }
2349
2350        // back to original flags during command evaluation...
2351        fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2352
2353        status = Tcl_Eval(interp, Tcl_DStringValue(&cmdbuffer));
2354        Tcl_DStringSetLength(&cmdbuffer, 0);
2355
2356        // non-blocking for next read -- we might not get anything
2357        fcntl(0, F_SETFL, flags | O_NONBLOCK);
2358        npass++;
2359    }
2360    fcntl(0, F_SETFL, flags);
2361
2362    if (status != TCL_OK) {
2363        std::ostringstream errmsg;
2364        errmsg << "ERROR: " << Tcl_GetStringResult(interp) << std::endl;
2365        write(0, errmsg.str().c_str(), errmsg.str().size());
2366        return;
2367    }
2368
2369    //
2370    //  Generate the latest frame and send it back to the client
2371    //
2372    display();
2373
2374#if DO_RLE
2375    do_rle();
2376    int sizes[2] = {  offsets_size*sizeof(offsets[0]), rle_size };
2377    fprintf(stderr, "Writing %d,%d\n", sizes[0], sizes[1]); fflush(stderr);
2378    write(0, &sizes, sizeof(sizes));
2379    write(0, offsets, offsets_size*sizeof(offsets[0]));
2380    write(0, rle, rle_size);    //unsigned byte
2381#else
2382    bmp_write("nv>image -bytes");
2383#endif
2384}
2385
2386
2387/*
2388//draw vectors
2389void draw_arrows(){
2390  glColor4f(0.,0.,1.,1.);
2391  for(int i=0; i<NMESH; i++){
2392    for(int j=0; j<NMESH; j++){
2393      Vector2 v = grid.get(i, j);
2394
2395      int x1 = i*DM;
2396      int y1 = j*DM;
2397
2398      int x2 = x1 + v.x;
2399      int y2 = y1 + v.y;
2400
2401      glBegin(GL_LINES);
2402        glVertex2d(x1, y1);
2403        glVertex2d(x2, y2);
2404      glEnd();
2405    }
2406  }
2407}
2408*/
2409
2410
2411/*----------------------------------------------------*/
2412void idle(){
2413  glutSetWindow(render_window);
2414
2415 
2416  /*
2417  struct timespec ts;
2418  ts.tv_sec = 0;
2419  ts.tv_nsec = 300000000;
2420  nanosleep(&ts, 0);
2421  */
2422 
2423
2424#ifdef XINETD
2425  xinetd_listen();
2426#else
2427  glutPostRedisplay();
2428#endif
2429}
2430
2431
2432void display_offscreen_buffer(){
2433   glEnable(GL_TEXTURE_2D);
2434   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2435   glBindTexture(GL_TEXTURE_2D, final_color_tex);
2436
2437   glViewport(0, 0, win_width, win_height);
2438   glMatrixMode(GL_PROJECTION);
2439   glLoadIdentity();
2440   gluOrtho2D(0, win_width, 0, win_height);
2441   glMatrixMode(GL_MODELVIEW);
2442   glLoadIdentity();
2443
2444   glColor3f(1.,1.,1.);         //MUST HAVE THIS LINE!!!
2445   glBegin(GL_QUADS);
2446   glTexCoord2f(0, 0); glVertex2f(0, 0);
2447   glTexCoord2f(1, 0); glVertex2f(win_width, 0);
2448   glTexCoord2f(1, 1); glVertex2f(win_width, win_height);
2449   glTexCoord2f(0, 1); glVertex2f(0, win_height);
2450   glEnd();
2451}
2452
2453void offscreen_buffer_capture(){
2454   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
2455}
2456
2457void draw_bounding_box(float x0, float y0, float z0,
2458                float x1, float y1, float z1,
2459                float r, float g, float b, float line_width)
2460{
2461        glDisable(GL_TEXTURE_2D);
2462
2463        glColor4d(r, g, b, 1.0);
2464        glLineWidth(line_width);
2465       
2466        glBegin(GL_LINE_LOOP);
2467
2468                glVertex3d(x0, y0, z0);
2469                glVertex3d(x1, y0, z0);
2470                glVertex3d(x1, y1, z0);
2471                glVertex3d(x0, y1, z0);
2472               
2473        glEnd();
2474
2475        glBegin(GL_LINE_LOOP);
2476
2477                glVertex3d(x0, y0, z1);
2478                glVertex3d(x1, y0, z1);
2479                glVertex3d(x1, y1, z1);
2480                glVertex3d(x0, y1, z1);
2481               
2482        glEnd();
2483
2484
2485        glBegin(GL_LINE_LOOP);
2486
2487                glVertex3d(x0, y0, z0);
2488                glVertex3d(x0, y0, z1);
2489                glVertex3d(x0, y1, z1);
2490                glVertex3d(x0, y1, z0);
2491               
2492        glEnd();
2493
2494        glBegin(GL_LINE_LOOP);
2495
2496                glVertex3d(x1, y0, z0);
2497                glVertex3d(x1, y0, z1);
2498                glVertex3d(x1, y1, z1);
2499                glVertex3d(x1, y1, z0);
2500               
2501        glEnd();
2502
2503        glEnable(GL_TEXTURE_2D);
2504}
2505
2506
2507
2508int particle_distance_sort(const void* a, const void* b){
2509  if((*((Particle*)a)).aux > (*((Particle*)b)).aux)
2510    return -1;
2511  else
2512    return 1;
2513}
2514
2515
2516void soft_read_verts(){
2517  glReadPixels(0, 0, psys->psys_width, psys->psys_height, GL_RGB, GL_FLOAT, vert);
2518  //fprintf(stderr, "soft_read_vert");
2519
2520  //cpu sort the distance 
2521  Particle* p = (Particle*) malloc(sizeof(Particle)* psys->psys_width * psys->psys_height);
2522  for(int i=0; i<psys->psys_width * psys->psys_height; i++){
2523    float x = vert[3*i];
2524    float y = vert[3*i+1];
2525    float z = vert[3*i+2];
2526
2527    float dis = (x-live_obj_x)*(x-live_obj_x) + (y-live_obj_y)*(y-live_obj_y) + (z-live_obj_z)*(z-live_obj_z);
2528    p[i].x = x;
2529    p[i].y = y;
2530    p[i].z = z;
2531    p[i].aux = dis;
2532  }
2533
2534  qsort(p, psys->psys_width * psys->psys_height, sizeof(Particle), particle_distance_sort);
2535
2536  for(int i=0; i<psys->psys_width * psys->psys_height; i++){
2537    vert[3*i] = p[i].x;
2538    vert[3*i+1] = p[i].y;
2539    vert[3*i+2] = p[i].z;
2540  }
2541
2542  free(p);
2543}
2544
2545
2546//display the content of a texture as a screen aligned quad
2547void display_texture(NVISid tex, int width, int height){
2548   glPushMatrix();
2549
2550   glEnable(GL_TEXTURE_2D);
2551   glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex);
2552
2553   glViewport(0, 0, width, height);
2554   glMatrixMode(GL_PROJECTION);
2555   glLoadIdentity();
2556   gluOrtho2D(0, width, 0, height);
2557   glMatrixMode(GL_MODELVIEW);
2558   glLoadIdentity();
2559
2560   cgGLBindProgram(m_passthru_fprog);
2561   cgGLEnableProfile(CG_PROFILE_FP30);
2562
2563   cgGLSetParameter4f(m_passthru_scale_param, 1.0, 1.0, 1.0, 1.0);
2564   cgGLSetParameter4f(m_passthru_bias_param, 0.0, 0.0, 0.0, 0.0);
2565   
2566   draw_quad(width, height, width, height);
2567   cgGLDisableProfile(CG_PROFILE_FP30);
2568
2569   glPopMatrix();
2570
2571   assert(glGetError()==0);
2572}
2573
2574
2575//draw vertices in the main memory
2576void soft_display_verts(){
2577  glDisable(GL_TEXTURE_2D);
2578  glEnable(GL_BLEND);
2579
2580  glPointSize(0.5);
2581  glColor4f(0,0.8,0.8,0.6);
2582  glBegin(GL_POINTS);
2583  for(int i=0; i<psys->psys_width * psys->psys_height; i++){
2584    glVertex3f(vert[3*i], vert[3*i+1], vert[3*i+2]);
2585  }
2586  glEnd();
2587  //fprintf(stderr, "soft_display_vert");
2588}
2589
2590
2591#if 0
2592
2593//oddeven sort on GPU
2594void sortstep()
2595{
2596    // perform one step of the current sorting algorithm
2597
2598        /*
2599    // swap buffers
2600    int sourceBuffer = targetBuffer;
2601    targetBuffer = (targetBuffer+1)%2;   
2602    int pstage = (1<<stage);
2603    int ppass  = (1<<pass);
2604    int activeBitonicShader = 0;
2605
2606#ifdef _WIN32
2607    buffer->BindBuffer(wglTargets[sourceBuffer]);
2608#else
2609    buffer->BindBuffer(glTargets[sourceBuffer]);
2610#endif
2611    if (buffer->IsDoubleBuffered()) glDrawBuffer(glTargets[targetBuffer]);
2612    */
2613
2614    checkGLError("after db");
2615
2616    int pstage = (1<<stage);
2617    int ppass  = (1<<pass);
2618    //int activeBitonicShader = 0;
2619
2620    // switch on correct sorting shader
2621    oddevenMergeSort.bind();
2622    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param1"), float(pstage+pstage),
2623                   float(ppass%pstage), float((pstage+pstage)-(ppass%pstage)-1));
2624    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param2"), float(psys_width), float(psys_height), float(ppass));
2625    glUniform1iARB(oddevenMergeSort.getUniformLocation("Data"), 0);
2626    staticdebugmsg("sort","stage "<<pstage<<" pass "<<ppass);
2627
2628    // This clear is not necessary for sort to function. But if we are in interactive mode
2629    // unused parts of the texture that are visible will look bad.
2630    //if (!perfTest) glClear(GL_COLOR_BUFFER_BIT);
2631
2632    //buffer->Bind();
2633    //buffer->EnableTextureTarget();
2634
2635    // initiate the sorting step on the GPU
2636    // a full-screen quad
2637    glBegin(GL_QUADS);
2638    /*
2639    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f); glVertex2f(-1.0f,-1.0f);
2640    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f); glVertex2f(1.0f,-1.0f);
2641    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f); glVertex2f(1.0f,1.0f);       
2642    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f); glVertex2f(-1.0f,1.0f);   
2643    */
2644    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f); glVertex2f(0.,0.);       
2645    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f); glVertex2f(float(psys_width), 0.);
2646    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f); glVertex2f(float(psys_width), float(psys_height));   
2647    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f); glVertex2f(0., float(psys_height));       
2648    glEnd();
2649
2650
2651    // switch off sorting shader
2652    oddevenMergeSort.release();
2653
2654    //buffer->DisableTextureTarget();
2655
2656    assert(glGetError()==0);
2657}
2658
2659#endif
2660
2661
2662void draw_3d_axis(){
2663  glDisable(GL_TEXTURE_2D);
2664  glEnable(GL_DEPTH_TEST);
2665
2666        //draw axes
2667        GLUquadric *obj;
2668        obj = gluNewQuadric();
2669       
2670        glDepthFunc(GL_LESS);
2671        glEnable(GL_DEPTH_TEST);
2672        glDisable(GL_BLEND);
2673
2674        int segments = 50;
2675
2676        glColor3f(0.8, 0.8, 0.8);
2677        glPushMatrix();
2678        glTranslatef(0.4, 0., 0.);
2679        glRotatef(90, 1, 0, 0);
2680        glRotatef(180, 0, 1, 0);
2681        glScalef(0.0005, 0.0005, 0.0005);
2682        glutStrokeCharacter(GLUT_STROKE_ROMAN, 'x');
2683        glPopMatrix(); 
2684
2685        glPushMatrix();
2686        glTranslatef(0., 0.4, 0.);
2687        glRotatef(90, 1, 0, 0);
2688        glRotatef(180, 0, 1, 0);
2689        glScalef(0.0005, 0.0005, 0.0005);
2690        glutStrokeCharacter(GLUT_STROKE_ROMAN, 'y');
2691        glPopMatrix(); 
2692
2693        glPushMatrix();
2694        glTranslatef(0., 0., 0.4);
2695        glRotatef(90, 1, 0, 0);
2696        glRotatef(180, 0, 1, 0);
2697        glScalef(0.0005, 0.0005, 0.0005);
2698        glutStrokeCharacter(GLUT_STROKE_ROMAN, 'z');
2699        glPopMatrix(); 
2700
2701        glEnable(GL_LIGHTING);
2702        glEnable(GL_LIGHT0);
2703
2704        glColor3f(0.2, 0.2, 0.8);
2705        glPushMatrix();
2706        glutSolidSphere(0.02, segments, segments );
2707        glPopMatrix();
2708
2709        glPushMatrix();
2710        glRotatef(-90, 1, 0, 0);       
2711        gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
2712        glPopMatrix(); 
2713
2714        glPushMatrix();
2715        glTranslatef(0., 0.3, 0.);
2716        glRotatef(-90, 1, 0, 0);       
2717        gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
2718        glPopMatrix(); 
2719
2720        glPushMatrix();
2721        glRotatef(90, 0, 1, 0);
2722        gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
2723        glPopMatrix(); 
2724
2725        glPushMatrix();
2726        glTranslatef(0.3, 0., 0.);
2727        glRotatef(90, 0, 1, 0);
2728        gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
2729        glPopMatrix(); 
2730
2731        glPushMatrix();
2732        gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
2733        glPopMatrix(); 
2734
2735        glPushMatrix();
2736        glTranslatef(0., 0., 0.3);
2737        gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
2738        glPopMatrix(); 
2739
2740        glDisable(GL_LIGHTING);
2741        glDisable(GL_DEPTH_TEST);
2742        gluDeleteQuadric(obj);
2743
2744  glEnable(GL_TEXTURE_2D);
2745  glDisable(GL_DEPTH_TEST);
2746}
2747
2748
2749void draw_axis(){
2750
2751  glDisable(GL_TEXTURE_2D);
2752  glEnable(GL_DEPTH_TEST);
2753
2754  //red x
2755  glColor3f(1,0,0);
2756  glBegin(GL_LINES);
2757    glVertex3f(0,0,0);
2758    glVertex3f(1.5,0,0);
2759  glEnd();
2760
2761  //blue y
2762  glColor3f(0,0,1);
2763  glBegin(GL_LINES);
2764    glVertex3f(0,0,0);
2765    glVertex3f(0,1.5,0);
2766  glEnd();
2767
2768  //green z
2769  glColor3f(0,1,0);
2770  glBegin(GL_LINES);
2771    glVertex3f(0,0,0);
2772    glVertex3f(0,0,1.5);
2773  glEnd();
2774
2775  glEnable(GL_TEXTURE_2D);
2776  glDisable(GL_DEPTH_TEST);
2777}
2778
2779
2780
2781/*----------------------------------------------------*/
2782void display()
2783{
2784
2785   assert(glGetError()==0);
2786
2787   //lic->convolve(); //flow line integral convolution
2788   //psys->advect(); //advect particles
2789
2790   offscreen_buffer_capture();  //enable offscreen render
2791   //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); //enable onscreen render
2792
2793   //start final rendering
2794   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
2795
2796   if (volume_mode) {
2797     //3D rendering mode
2798     glEnable(GL_TEXTURE_2D);
2799     glEnable(GL_DEPTH_TEST);
2800
2801     //camera setting activated
2802     cam->activate();
2803
2804     //set up the orientation of items in the scene.
2805     glPushMatrix();
2806       switch (updir) {
2807         case 1:  // x
2808               glRotatef(90, 0, 0, 1);
2809               glRotatef(90, 1, 0, 0);
2810           break;
2811
2812         case 2:  // y
2813           // this is the default
2814           break;
2815
2816         case 3:  // z
2817               glRotatef(-90, 1, 0, 0);
2818               glRotatef(-90, 0, 0, 1);
2819           break;
2820
2821         case -1:  // -x
2822               glRotatef(-90, 0, 0, 1);
2823           break;
2824
2825         case -2:  // -y
2826               glRotatef(180, 0, 0, 1);
2827               glRotatef(-90, 0, 1, 0);
2828           break;
2829
2830         case -3:  // -z
2831               glRotatef(90, 1, 0, 0);
2832           break;
2833       }
2834
2835       //now render things in the scene
2836       draw_3d_axis();
2837
2838       //lic->render();         //display the line integral convolution result
2839       //soft_display_verts();
2840       //perf->enable();
2841       //  psys->render();
2842       //perf->disable();
2843       //fprintf(stderr, "particle pixels: %d\n", perf->get_pixel_count());
2844       //perf->reset();
2845
2846       perf->enable();
2847         vol_render->render_all();
2848       perf->disable();
2849
2850     glPopMatrix();
2851   }
2852   else{
2853     //2D rendering mode
2854     perf->enable();
2855       plane_render->render();
2856     perf->disable();
2857   }
2858
2859
2860#ifdef XINETD
2861   float cost  = perf->get_pixel_count();
2862   write(3, &cost, sizeof(cost));
2863#endif
2864   perf->reset();
2865
2866   display_offscreen_buffer(); //display the final rendering on screen
2867
2868#ifdef XINETD
2869   read_screen();
2870#else
2871   //read_screen();
2872#endif   
2873
2874   glutSwapBuffers();
2875}
2876
2877
2878void mouse(int button, int state, int x, int y){
2879  if(button==GLUT_LEFT_BUTTON){
2880
2881    if(state==GLUT_DOWN){
2882      left_last_x = x;
2883      left_last_y = y;
2884      left_down = true;
2885      right_down = false;
2886    }
2887    else{
2888      left_down = false;
2889      right_down = false;
2890    }
2891  }
2892  else{
2893    //fprintf(stderr, "right mouse\n");
2894
2895    if(state==GLUT_DOWN){
2896      //fprintf(stderr, "right mouse down\n");
2897      right_last_x = x;
2898      right_last_y = y;
2899      left_down = false;
2900      right_down = true;
2901    }
2902    else{
2903      //fprintf(stderr, "right mouse up\n");
2904      left_down = false;
2905      right_down = false;
2906    }
2907  }
2908}
2909
2910
2911void update_rot(int delta_x, int delta_y){
2912        live_rot_x += delta_x;
2913        live_rot_y += delta_y;
2914
2915        if(live_rot_x > 360.0)
2916                live_rot_x -= 360.0;   
2917        else if(live_rot_x < -360.0)
2918                live_rot_x += 360.0;
2919
2920        if(live_rot_y > 360.0)
2921                live_rot_y -= 360.0;   
2922        else if(live_rot_y < -360.0)
2923                live_rot_y += 360.0;
2924
2925        cam->rotate(live_rot_x, live_rot_y, live_rot_z);
2926}
2927
2928
2929void update_trans(int delta_x, int delta_y, int delta_z){
2930        live_obj_x += delta_x*0.03;
2931        live_obj_y += delta_y*0.03;
2932        live_obj_z += delta_z*0.03;
2933}
2934
2935void end_service();
2936
2937void keyboard(unsigned char key, int x, int y){
2938 
2939   bool log = false;
2940
2941   switch (key){
2942        case 'q':
2943#ifdef XINETD
2944                end_service();
2945#endif
2946                exit(0);
2947                break;
2948        case '+':
2949                lic_slice_z+=0.05;
2950                lic->set_offset(lic_slice_z);
2951                break;
2952        case '-':
2953                lic_slice_z-=0.05;
2954                lic->set_offset(lic_slice_z);
2955                break;
2956        case ',':
2957                lic_slice_x+=0.05;
2958                init_particles();
2959                break;
2960        case '.':
2961                lic_slice_x-=0.05;
2962                init_particles();
2963                break;
2964        case '1':
2965                advect = true;
2966                break;
2967        case '2':
2968                psys_x+=0.05;
2969                break;
2970        case '3':
2971                psys_x-=0.05;
2972                break;
2973        case 'w': //zoom out
2974                live_obj_z-=0.05;
2975                log = true;
2976                cam->move(live_obj_x, live_obj_y, live_obj_z);
2977                break;
2978        case 's': //zoom in
2979                live_obj_z+=0.05;
2980                log = true;
2981                cam->move(live_obj_x, live_obj_y, live_obj_z);
2982                break;
2983        case 'a': //left
2984                live_obj_x-=0.05;
2985                log = true;
2986                cam->move(live_obj_x, live_obj_y, live_obj_z);
2987                break;
2988        case 'd': //right
2989                live_obj_x+=0.05;
2990                log = true;
2991                cam->move(live_obj_x, live_obj_y, live_obj_z);
2992                break;
2993        case 'i':
2994                init_particles();
2995                break;
2996        case 'v':
2997                vol_render->switch_volume_mode();
2998                break;
2999        case 'b':
3000                vol_render->switch_slice_mode();
3001                break;
3002        case 'n':
3003                resize_offscreen_buffer(win_width*2, win_height*2);
3004                break;
3005        case 'm':
3006                resize_offscreen_buffer(win_width/2, win_height/2);
3007                break;
3008
3009        default:
3010                break;
3011    }   
3012
3013#ifdef EVENTLOG
3014   if(log){
3015     float param[3] = {live_obj_x, live_obj_y, live_obj_z};
3016     Event* tmp = new Event(EVENT_MOVE, param, get_time_interval());
3017     tmp->write(event_log);
3018     delete tmp;
3019   }
3020#endif
3021}
3022
3023void motion(int x, int y){
3024
3025    int old_x, old_y;   
3026
3027    if(left_down){
3028      old_x = left_last_x;
3029      old_y = left_last_y;   
3030    }
3031    else if(right_down){
3032      old_x = right_last_x;
3033      old_y = right_last_y;   
3034    }
3035
3036    int delta_x = x - old_x;
3037    int delta_y = y - old_y;
3038
3039    //more coarse event handling
3040    //if(abs(delta_x)<10 && abs(delta_y)<10)
3041      //return;
3042
3043    if(left_down){
3044      left_last_x = x;
3045      left_last_y = y;
3046
3047      update_rot(-delta_y, -delta_x);
3048    }
3049    else if (right_down){
3050      //fprintf(stderr, "right mouse motion (%d,%d)\n", x, y);
3051
3052      right_last_x = x;
3053      right_last_y = y;
3054
3055      update_trans(0, 0, delta_x);
3056    }
3057
3058#ifdef EVENTLOG
3059    float param[3] = {live_rot_x, live_rot_y, live_rot_z};
3060    Event* tmp = new Event(EVENT_ROTATE, param, get_time_interval());
3061    tmp->write(event_log);
3062    delete tmp;
3063#endif
3064
3065    glutPostRedisplay();
3066}
3067
3068#ifdef XINETD
3069void init_service(){
3070  //open log and map stderr to log file
3071  xinetd_log = fopen("log.txt", "w");
3072  close(2);
3073  dup2(fileno(xinetd_log), 2);
3074  dup2(2,1);
3075
3076  //flush junk
3077  fflush(stdout);
3078  fflush(stderr);
3079}
3080
3081void end_service(){
3082  //close log file
3083  fclose(xinetd_log);
3084}
3085#endif
3086
3087void init_event_log(){
3088  event_log = fopen("event.txt", "w");
3089  assert(event_log!=0);
3090
3091  struct timeval time;
3092  gettimeofday(&time, NULL);
3093  cur_time = time.tv_sec*1000. + time.tv_usec/1000.;
3094}
3095
3096void end_event_log(){
3097  fclose(event_log);
3098}
3099
3100double get_time_interval(){
3101  struct timeval time;
3102  gettimeofday(&time, NULL);
3103  double new_time = time.tv_sec*1000. + time.tv_usec/1000.;
3104
3105  double interval = new_time - cur_time;
3106  cur_time = new_time;
3107  return interval;
3108}
3109
3110
3111/*----------------------------------------------------*/
3112int main(int argc, char** argv)
3113{
3114#ifdef XINETD
3115   init_service();
3116#endif
3117
3118   glutInit(&argc, argv);
3119   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
3120   
3121   glutInitWindowSize(win_width, win_height);
3122   glutInitWindowPosition(10, 10);
3123   render_window = glutCreateWindow(argv[0]);
3124   glutDisplayFunc(display);
3125
3126#ifndef XINETD
3127   //MainTransferFunctionWindow * tf_window;
3128   //tf_window = new MainTransferFunctionWindow();
3129   //tf_window->mainInit();
3130
3131   glutMouseFunc(mouse);
3132   glutMotionFunc(motion);
3133   glutKeyboardFunc(keyboard);
3134#endif
3135   glutIdleFunc(idle);
3136   glutReshapeFunc(resize_offscreen_buffer);
3137
3138   initGL();
3139   initTcl();
3140
3141#ifdef EVENTLOG
3142   init_event_log();
3143#endif
3144   //event loop
3145   glutMainLoop();
3146#ifdef EVENTLOG
3147   end_event_log();
3148#endif
3149
3150#ifdef XINETD
3151   end_service();
3152#endif
3153
3154   return 0;
3155}
Note: See TracBrowser for help on using the repository browser.