source: trunk/vizservers/nanovis/nanovis.cpp @ 750

Last change on this file since 750 was 720, checked in by nkissebe, 17 years ago

ignore SIGPIPE signals (which would occur if nanoscale terminated)

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