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

Last change on this file since 617 was 617, checked in by vrinside, 18 years ago

Added new zinc blende renderer - It is still needed to compare with unicell based simulation data.
Removed tentatively used class, NvVolQDVolumeShader,NvVolQDVolume
Moved Font.bmp into resources directory

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