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

Last change on this file since 806 was 806, checked in by vrinside, 17 years ago

Add a macro for dubugging

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