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

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