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

Last change on this file since 415 was 415, checked in by qiaow, 18 years ago

Now can load arbitary number of volumes (16 per application due to hardware limitation). The VolumeRenderer? render them with correct slice order!!

File size: 49.4 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 * Nanovis: Visualization of Nanoelectronics Data
4 *
5 * ======================================================================
6 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
7 *           Purdue Rendering and Perceptualization Lab (PURPL)
8 *
9 *  Copyright (c) 2004-2006  Purdue Research Foundation
10 *
11 *  See the file "license.terms" for information on usage and
12 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * ======================================================================
14 */
15
16#include <stdio.h>
17#include <math.h>
18#include <fstream>
19#include <iostream>
20#include <string>
21#include <sys/time.h>
22
23#include "nanovis.h"
24#include "RpFieldRect3D.h"
25#include "RpFieldPrism3D.h"
26
27//transfer function headers
28#include "transfer-function/TransferFunctionMain.h"
29#include "transfer-function/ControlPoint.h"
30#include "transfer-function/TransferFunctionGLUTWindow.h"
31#include "transfer-function/ColorGradientGLUTWindow.h"
32#include "transfer-function/ColorPaletteWindow.h"
33#include "transfer-function/MainWindow.h"
34
35//render server
36
37VolumeRenderer* vol_render;
38Camera* cam;
39
40float color_table[256][4];     
41
42#ifdef XINETD
43FILE* xinetd_log;
44#endif
45
46FILE* event_log;
47//log
48void init_event_log();
49void end_event_log();
50double cur_time;        //in seconds
51double get_time_interval();
52
53int render_window;              //the handle of the render window;
54// forward declarations
55void init_particles();
56void get_slice_vectors();
57
58ParticleSystem* psys;
59float psys_x=0.4, psys_y=0, psys_z=0;
60
61Lic* lic;
62
63unsigned char* screen_buffer = new unsigned char[3*win_width*win_height+1];     //buffer to store data read from the screen
64NVISid final_fbo, final_color_tex, final_depth_rb;      //frame buffer for final rendering
65NVISid vel_fbo, slice_vector_tex;       //for projecting 3d vector to 2d vector on a plane
66
67bool advect=false;
68float vert[NMESH*NMESH*3];              //particle positions in main memory
69float slice_vector[NMESH*NMESH*4];      //per slice vectors in main memory
70
71int n_volumes = 0;
72Volume* volume[MAX_N_VOLUMES];          //point to volumes, currently handle up to 10 volumes
73TransferFunction* tf[MAX_N_VOLUMES];    //transfer functions, currently handle up to 10 colormaps
74
75PerfQuery* perf;                        //perfromance counter
76
77//Nvidia CG shaders and their parameters
78CGcontext g_context;
79
80CGprogram m_passthru_fprog;
81CGparameter m_passthru_scale_param, m_passthru_bias_param;
82
83CGprogram m_copy_texcoord_fprog;
84
85CGprogram m_one_volume_fprog;
86CGparameter m_vol_one_volume_param;
87CGparameter m_tf_one_volume_param;
88CGparameter m_mvi_one_volume_param;
89CGparameter m_mv_one_volume_param;
90CGparameter m_render_param_one_volume_param;
91
92CGprogram m_vert_std_vprog;
93CGparameter m_mvp_vert_std_param;
94CGparameter m_mvi_vert_std_param;
95
96using namespace std;
97
98static void set_camera(float x_angle, float y_angle, float z_angle){
99  live_rot_x = x_angle;
100  live_rot_y = y_angle;
101  live_rot_z = z_angle;
102}
103
104
105// Tcl interpreter for incoming messages
106static Tcl_Interp *interp;
107
108static int CameraCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
109static int ClearCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
110static int SizeCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
111static int OutlineCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
112static int CutCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
113static int HelloCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
114static int LoadCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
115static int RefreshCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
116static int MoveCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]));
117
118//Tcl callback functions
119static int
120CameraCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
121{
122
123        fprintf(stderr, "camera cmd\n");
124        double x, y, z;
125
126        if (argc != 4) {
127                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
128                        " x_angle y_angle z_angle\"", (char*)NULL);
129                return TCL_ERROR;
130        }
131        if (Tcl_GetDouble(interp, argv[1], &x) != TCL_OK) {
132                return TCL_ERROR;
133        }
134        if (Tcl_GetDouble(interp, argv[2], &y) != TCL_OK) {
135                return TCL_ERROR;
136        }
137        if (Tcl_GetDouble(interp, argv[3], &z) != TCL_OK) {
138                return TCL_ERROR;
139        }
140        set_camera(x, y, z);
141        return TCL_OK;
142}
143
144
145static int
146RefreshCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
147{
148  fprintf(stderr, "refresh cmd\n");
149  return TCL_OK;
150}
151
152void set_object(float x, float y, float z){
153  live_obj_x = x;
154  live_obj_y = y;
155  live_obj_z = z;
156}
157
158
159static int
160MoveCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
161{
162
163        fprintf(stderr, "move cmd\n");
164        double x, y, z;
165
166        if (argc != 4) {
167                Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
168                        " x_angle y_angle z_angle\"", (char*)NULL);
169                return TCL_ERROR;
170        }
171        if (Tcl_GetDouble(interp, argv[1], &x) != TCL_OK) {
172                return TCL_ERROR;
173        }
174        if (Tcl_GetDouble(interp, argv[2], &y) != TCL_OK) {
175                return TCL_ERROR;
176        }
177        if (Tcl_GetDouble(interp, argv[3], &z) != TCL_OK) {
178                return TCL_ERROR;
179        }
180        set_object(x, y, z);
181        return TCL_OK;
182}
183
184
185static int
186HelloCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])
187{
188        //send back 4 bytes as confirmation
189        char ack[4]="ACK";
190        fprintf(stderr, "wrote %d\n", write(fileno(stdout), ack, 4));
191        fflush(stdout);
192        return TCL_OK;
193}
194
195//report errors related to CG shaders
196void cgErrorCallback(void)
197{
198    CGerror lastError = cgGetError();
199    if(lastError) {
200        const char *listing = cgGetLastListing(g_context);
201        printf("\n---------------------------------------------------\n");
202        printf("%s\n\n", cgGetErrorString(lastError));
203        printf("%s\n", listing);
204        printf("-----------------------------------------------------\n");
205        printf("Cg error, exiting...\n");
206        cgDestroyContext(g_context);
207        exit(-1);
208    }
209}
210
211
212void init_glew(){
213        GLenum err = glewInit();
214        if (GLEW_OK != err)
215        {
216                //glew init failed, exit.
217                fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
218                getchar();
219                assert(false);
220        }
221
222        fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
223}
224
225
226void load_volume(int index, int width, int height, int depth, int n_component, float* data);
227
228/* Load a 3D vector field from a dx-format file
229 */
230void
231load_vector_file(int index, char *fname) {
232    int dummy, nx, ny, nz, nxy, npts;
233    double x0, y0, z0, dx, dy, dz, ddx, ddy, ddz;
234    char line[128], type[128], *start;
235    std::ifstream fin(fname);
236
237    do {
238        fin.getline(line,sizeof(line)-1);
239        for (start=&line[0]; *start == ' ' || *start == '\t'; start++)
240            ;  // skip leading blanks
241
242        if (*start != '#') {  // skip comment lines
243            if (sscanf(start, "object %d class gridpositions counts %d %d %d", &dummy, &nx, &ny, &nz) == 4) {
244                // found grid size
245            }
246            else if (sscanf(start, "origin %lg %lg %lg", &x0, &y0, &z0) == 3) {
247                // found origin
248            }
249            else if (sscanf(start, "delta %lg %lg %lg", &ddx, &ddy, &ddz) == 3) {
250                // found one of the delta lines
251                if (ddx != 0.0) { dx = ddx; }
252                else if (ddy != 0.0) { dy = ddy; }
253                else if (ddz != 0.0) { dz = ddz; }
254            }
255            else if (sscanf(start, "object %d class array type %s shape 3 rank 1 items %d data follows", &dummy, type, &npts) == 3) {
256                if (npts != nx*ny*nz) {
257                    std::cerr << "inconsistent data: expected " << nx*ny*nz << " points but found " << npts << " points" << std::endl;
258                    return;
259                }
260                break;
261            }
262        }
263    } while (!fin.eof());
264
265    // read data points
266    if (!fin.eof()) {
267        Rappture::Mesh1D xgrid(x0, x0+nx*dx, nx);
268        Rappture::Mesh1D ygrid(y0, y0+ny*dy, ny);
269        Rappture::Mesh1D zgrid(z0, z0+nz*dz, nz);
270        Rappture::FieldRect3D xfield(xgrid, ygrid, zgrid);
271        Rappture::FieldRect3D yfield(xgrid, ygrid, zgrid);
272        Rappture::FieldRect3D zfield(xgrid, ygrid, zgrid);
273
274        double vx, vy, vz;
275        int nread = 0;
276        for (int ix=0; ix < nx; ix++) {
277            for (int iy=0; iy < ny; iy++) {
278                for (int iz=0; iz < nz; iz++) {
279                    if (fin.eof() || nread > npts) {
280                        break;
281                    }
282                    fin.getline(line,sizeof(line)-1);
283                    if (sscanf(line, "%lg %lg %lg", &vx, &vy, &vz) == 3) {
284                        int nindex = iz*nx*ny + iy*nx + ix;
285                        xfield.define(nindex, vx);
286                        yfield.define(nindex, vy);
287                        zfield.define(nindex, vz);
288                        nread++;
289                    }
290                }
291            }
292        }
293
294        // make sure that we read all of the expected points
295        if (nread != nx*ny*nz) {
296            std::cerr << "inconsistent data: expected " << nx*ny*nz << " points but found " << nread << " points" << std::endl;
297            return;
298        }
299
300        // figure out a good mesh spacing
301        int nsample = 30;
302        dx = xfield.rangeMax(Rappture::xaxis) - xfield.rangeMin(Rappture::xaxis);
303        dy = xfield.rangeMax(Rappture::yaxis) - xfield.rangeMin(Rappture::yaxis);
304        dz = xfield.rangeMax(Rappture::zaxis) - xfield.rangeMin(Rappture::zaxis);
305        double dmin = pow((dx*dy*dz)/(nsample*nsample*nsample), 0.333);
306
307        nx = (int)ceil(dx/dmin);
308        ny = (int)ceil(dy/dmin);
309        nz = (int)ceil(dz/dmin);
310
311#ifndef NV40
312        nx = pow(2.0, ceil(log10((double)nx)/log10(2.0)));  // must be an even power of 2
313        ny = pow(2.0, ceil(log10((double)ny)/log10(2.0)));
314        nz = pow(2.0, ceil(log10((double)nz)/log10(2.0)));
315#endif
316
317        float *data = new float[3*nx*ny*nz];
318
319        std::cout << "generating " << nx << "x" << ny << "x" << nz << " = " << nx*ny*nz << " points" << std::endl;
320
321        // generate the uniformly sampled data that we need for a volume
322        double vmin = 0.0;
323        double vmax = 0.0;
324        int ngen = 0;
325        for (int iz=0; iz < nz; iz++) {
326            double zval = z0 + iz*dmin;
327            for (int iy=0; iy < ny; iy++) {
328                double yval = y0 + iy*dmin;
329                for (int ix=0; ix < nx; ix++) {
330                    double xval = x0 + ix*dmin;
331
332                    vx = xfield.value(xval,yval,zval);
333                    vy = yfield.value(xval,yval,zval);
334                    vz = zfield.value(xval,yval,zval);
335                    //vx = 1;
336                    //vy = 1;
337                    vz = 0;
338                    double vm = sqrt(vx*vx + vy*vy + vz*vz);
339
340                    if (vm < vmin) { vmin = vm; }
341                    if (vm > vmax) { vmax = vm; }
342
343                    data[ngen++] = vx;
344                    data[ngen++] = vy;
345                    data[ngen++] = vz;
346                }
347            }
348        }
349
350        ngen = 0;
351        for (ngen=0; ngen < npts; ngen++) {
352            data[ngen] = (data[ngen]/(2.0*vmax) + 0.5);
353        }
354
355        load_volume(index, nx, ny, nz, 3, data);
356        delete [] data;
357    } else {
358        std::cerr << "WARNING: data not found in file " << fname << std::endl;
359    }
360}
361
362
363/* Load a 3D volume from a dx-format file
364 */
365void
366load_volume_file(int index, char *fname) {
367    Rappture::MeshTri2D xymesh;
368    int dummy, nx, ny, nz, nxy, npts;
369    double x0, y0, z0, dx, dy, dz, ddx, ddy, ddz;
370    char line[128], type[128], *start;
371    std::ifstream fin(fname);
372
373    int isrect = 1;
374
375    do {
376        fin.getline(line,sizeof(line)-1);
377        for (start=&line[0]; *start == ' ' || *start == '\t'; start++)
378            ;  // skip leading blanks
379
380        if (*start != '#') {  // skip comment lines
381            if (sscanf(start, "object %d class gridpositions counts %d %d %d", &dummy, &nx, &ny, &nz) == 4) {
382                // found grid size
383                isrect = 1;
384            }
385            else if (sscanf(start, "object %d class array type float rank 1 shape 3 items %d data follows", &dummy, &nxy) == 2) {
386                isrect = 0;
387                double xx, yy, zz;
388                for (int i=0; i < nxy; i++) {
389                    fin.getline(line,sizeof(line)-1);
390                    if (sscanf(line, "%lg %lg %lg", &xx, &yy, &zz) == 3) {
391                        xymesh.addNode( Rappture::Node2D(xx,yy) );
392                    }
393                }
394
395                std::ofstream ftmp("tmppts");
396                // save corners of bounding box first, to work around meshing
397                // problems in voronoi utility
398                ftmp << xymesh.rangeMin(Rappture::xaxis) << " "
399                     << xymesh.rangeMin(Rappture::yaxis) << std::endl;
400                ftmp << xymesh.rangeMax(Rappture::xaxis) << " "
401                     << xymesh.rangeMin(Rappture::yaxis) << std::endl;
402                ftmp << xymesh.rangeMax(Rappture::xaxis) << " "
403                     << xymesh.rangeMax(Rappture::yaxis) << std::endl;
404                ftmp << xymesh.rangeMin(Rappture::xaxis) << " "
405                     << xymesh.rangeMax(Rappture::yaxis) << std::endl;
406                for (int i=0; i < nxy; i++) {
407                    ftmp << xymesh.atNode(i).x() << " " << xymesh.atNode(i).y() << std::endl;
408                }
409                ftmp.close();
410
411                if (system("voronoi -t < tmppts > tmpcells") == 0) {
412                    int cx, cy, cz;
413                    std::ifstream ftri("tmpcells");
414                    while (!ftri.eof()) {
415                        ftri.getline(line,sizeof(line)-1);
416                        if (sscanf(line, "%d %d %d", &cx, &cy, &cz) == 3) {
417                            if (cx >= 4 && cy >= 4 && cz >= 4) {
418                                // skip first 4 boundary points
419                                xymesh.addCell(cx-4, cy-4, cz-4);
420                            }
421                        }
422                    }
423                    ftri.close();
424                } else {
425                    std::cerr << "WARNING: triangularization failed" << std::endl;
426                }
427            }
428            else if (sscanf(start, "object %d class regulararray count %d", &dummy, &nz) == 2) {
429                // found z-grid
430            }
431            else if (sscanf(start, "origin %lg %lg %lg", &x0, &y0, &z0) == 3) {
432                // found origin
433            }
434            else if (sscanf(start, "delta %lg %lg %lg", &ddx, &ddy, &ddz) == 3) {
435                // found one of the delta lines
436                if (ddx != 0.0) { dx = ddx; }
437                else if (ddy != 0.0) { dy = ddy; }
438                else if (ddz != 0.0) { dz = ddz; }
439            }
440            else if (sscanf(start, "object %d class array type %s rank 0 items %d data follows", &dummy, type, &npts) == 3) {
441                if (isrect && (npts != nx*ny*nz)) {
442                    std::cerr << "inconsistent data: expected " << nx*ny*nz << " points but found " << npts << " points" << std::endl;
443                    return;
444                }
445                else if (!isrect && (npts != nxy*nz)) {
446                    std::cerr << "inconsistent data: expected " << nxy*nz << " points but found " << npts << " points" << std::endl;
447                    return;
448                }
449                break;
450            }
451        }
452    } while (!fin.eof());
453
454    // read data points
455    if (!fin.eof()) {
456        if (isrect) {
457            Rappture::Mesh1D xgrid(x0, x0+nx*dx, nx);
458            Rappture::Mesh1D ygrid(y0, y0+ny*dy, ny);
459            Rappture::Mesh1D zgrid(z0, z0+nz*dz, nz);
460            Rappture::FieldRect3D field(xgrid, ygrid, zgrid);
461
462            double dval;
463            int nread = 0;
464            for (int ix=0; ix < nx; ix++) {
465                for (int iy=0; iy < ny; iy++) {
466                    for (int iz=0; iz < nz; iz++) {
467                        if (fin.eof() || nread > npts) {
468                            break;
469                        }
470                        fin.getline(line,sizeof(line)-1);
471                        if (sscanf(line, "%lg", &dval) == 1) {
472                            int nindex = iz*nx*ny + iy*nx + ix;
473                            field.define(nindex, dval);
474                            nread++;
475                        }
476                    }
477                }
478            }
479
480            // make sure that we read all of the expected points
481            if (nread != nx*ny*nz) {
482                std::cerr << "inconsistent data: expected " << nx*ny*nz << " points but found " << nread << " points" << std::endl;
483                return;
484            }
485
486            // figure out a good mesh spacing
487            int nsample = 30;
488            dx = field.rangeMax(Rappture::xaxis) - field.rangeMin(Rappture::xaxis);
489            dy = field.rangeMax(Rappture::yaxis) - field.rangeMin(Rappture::yaxis);
490            dz = field.rangeMax(Rappture::zaxis) - field.rangeMin(Rappture::zaxis);
491            double dmin = pow((dx*dy*dz)/(nsample*nsample*nsample), 0.333);
492
493            nx = (int)ceil(dx/dmin);
494            ny = (int)ceil(dy/dmin);
495            nz = (int)ceil(dz/dmin);
496
497#ifndef NV40
498            nx = pow(2.0, ceil(log10((double)nx)/log10(2.0)));  // must be an even power of 2
499            ny = pow(2.0, ceil(log10((double)ny)/log10(2.0)));
500            nz = pow(2.0, ceil(log10((double)nz)/log10(2.0)));
501#endif
502
503            float *data = new float[4*nx*ny*nz];
504
505            double vmin = field.valueMin();
506            double dv = field.valueMax() - field.valueMin();
507            if (dv == 0.0) { dv = 1.0; }
508
509            std::cout << "generating " << nx << "x" << ny << "x" << nz << " = " << nx*ny*nz << " points" << std::endl;
510
511            // generate the uniformly sampled data that we need for a volume
512            int ngen = 0;
513            for (int iz=0; iz < nz; iz++) {
514                double zval = z0 + iz*dmin;
515                for (int iy=0; iy < ny; iy++) {
516                    double yval = y0 + iy*dmin;
517                    for (int ix=0; ix < nx; ix++) {
518                        double xval = x0 + ix*dmin;
519                        double v = field.value(xval,yval,zval);
520
521                        // scale all values [0-1], -1 => out of bounds
522                        v = (isnan(v)) ? -1.0 : (v - vmin)/dv;
523                        data[ngen] = v;
524
525                        // gradient in x-direction
526                        double curval = (v < 0) ? 0.0 : v;
527                        double oldval = ((ngen/4) % nx == 0) ? 0.0 : data[ngen-4];
528                        oldval = (oldval < 0) ? 0.0 : oldval;
529                        data[ngen+1] = (curval-oldval)/dmin;
530
531                        // gradient in y-direction
532                        oldval = (ngen-4*nx >= 0) ? data[ngen-4*nx] : 0.0;
533                        oldval = (oldval < 0) ? 0.0 : oldval;
534                        data[ngen+2] = (curval-oldval)/dmin;
535
536                        // gradient in z-direction
537                        oldval = (ngen-4*nx*ny >= 0) ? data[ngen-4*nx*ny] : 0.0;
538                        oldval = (oldval < 0) ? 0.0 : oldval;
539                        data[ngen+3] = (curval-oldval)/dmin;
540                        ngen += 4;
541                    }
542                }
543            }
544
545            /*
546            //hack very first and last yz slice have 0 grad
547            for(int iz=0; iz<nz; iz++){
548              for(int iy=0; iy<ny; iy++){
549                 int index1, index2;
550                 int ix1 = 0;
551                 int ix2 = 3;
552                 index1 = ix1 + iy*nx + iz*nx*ny;
553                 index2 = ix2 + iy*nx + iz*nx*ny;
554                 data[4*index1 + 1] = data[4*index2 + 1];
555                 data[4*index1 + 2] = data[4*index2 + 2];
556                 data[4*index1 + 3] = data[4*index2 + 3];
557
558                 ix1 = nx-1;
559                 ix2 = nx-2;
560                 index1 = ix1 + iy*nx + iz*nx*ny;
561                 index2 = ix2 + iy*nx + iz*nx*ny;
562                 data[4*index1 + 1] = data[4*index2 + 1];
563                 data[4*index1 + 2] = data[4*index2 + 2];
564                 data[4*index1 + 3] = data[4*index2 + 3];
565              }
566            }
567            */
568
569            load_volume(index, nx, ny, nz, 4, data);
570            delete [] data;
571
572        } else {
573            Rappture::Mesh1D zgrid(z0, z0+nz*dz, nz);
574            Rappture::FieldPrism3D field(xymesh, zgrid);
575
576            double dval;
577            int nread = 0;
578            while (!fin.eof() && nread < npts) {
579                if (!(fin >> dval).fail()) {
580                    field.define(nread++, dval);
581                }
582            }
583
584            // make sure that we read all of the expected points
585            if (nread != nxy*nz) {
586                std::cerr << "inconsistent data: expected " << nxy*nz << " points but found " << nread << " points" << std::endl;
587                return;
588            }
589
590            // figure out a good mesh spacing
591            int nsample = 30;
592            x0 = field.rangeMin(Rappture::xaxis);
593            dx = field.rangeMax(Rappture::xaxis) - field.rangeMin(Rappture::xaxis);
594            y0 = field.rangeMin(Rappture::yaxis);
595            dy = field.rangeMax(Rappture::yaxis) - field.rangeMin(Rappture::yaxis);
596            z0 = field.rangeMin(Rappture::zaxis);
597            dz = field.rangeMax(Rappture::zaxis) - field.rangeMin(Rappture::zaxis);
598            double dmin = pow((dx*dy*dz)/(nsample*nsample*nsample), 0.333);
599
600            nx = (int)ceil(dx/dmin);
601            nx = pow(2.0, ceil(log10((double)nx)/log10(2.0)));  // must be an even power of 2
602            ny = (int)ceil(dy/dmin);
603            ny = pow(2.0, ceil(log10((double)ny)/log10(2.0)));
604            nz = (int)ceil(dz/dmin);
605            nz = pow(2.0, ceil(log10((double)nz)/log10(2.0)));
606            float *data = new float[4*nx*ny*nz];
607
608            double vmin = field.valueMin();
609            double dv = field.valueMax() - field.valueMin();
610            if (dv == 0.0) { dv = 1.0; }
611            std::cout << "generating " << nx << "x" << ny << "x" << nz << " = " << nx*ny*nz << " points" << std::endl;
612
613            // generate the uniformly sampled data that we need for a volume
614            int ngen = 0;
615            for (int iz=0; iz < nz; iz++) {
616                double zval = z0 + iz*dmin;
617                for (int iy=0; iy < ny; iy++) {
618                    double yval = y0 + iy*dmin;
619                    for (int ix=0; ix < nx; ix++) {
620                        double xval = x0 + ix*dmin;
621                        double v = field.value(xval,yval,zval);
622                        data[ngen++] = (isnan(v)) ? -1.0 : (v - vmin)/dv;
623                        data[ngen++] = 0.0;
624                        data[ngen++] = 0.0;
625                        data[ngen++] = 0.0;
626                    }
627                }
628            }
629            load_volume(index, nx, ny, nz, 4, data);
630            delete [] data;
631        }
632    } else {
633        std::cerr << "WARNING: data not found in file " << fname << std::endl;
634    }
635}
636
637/* Load a 3D volume
638 * index: the index into the volume array, which stores pointers to 3D volume instances
639 * data: pointer to an array of floats. 
640 * n_component: the number of scalars for each space point.
641 *              All component scalars for a point are placed consequtively in data array
642 * width, height and depth: number of points in each dimension
643 */
644void load_volume(int index, int width, int height, int depth, int n_component, float* data){
645  if(volume[index]!=0){
646    delete volume[index];
647    volume[index]=0;
648  }
649
650  volume[index] = new Volume(0.f, 0.f, 0.f, width, height, depth, NVIS_FLOAT, NVIS_LINEAR_INTERP, n_component, data);
651  assert(volume[index]!=0);
652}
653
654
655//load a colormap 1D texture
656void load_transfer_function(int index, int size, float* data){
657
658  if(tf[index]!=0){
659    delete tf[index];
660    tf[index]=0;
661  }
662
663  tf[index] = new TransferFunction(size, data);
664}
665
666
667//load value from the gui, only one transfer function
668extern void update_tf_texture(){
669  glutSetWindow(render_window);
670
671  //fprintf(stderr, "tf update\n");
672  if(tf[0]==0) return;
673
674  float data[256*4];
675  for(int i=0; i<256; i++){
676    data[4*i+0] = color_table[i][0];
677    data[4*i+1] = color_table[i][1];
678    data[4*i+2] = color_table[i][2];
679    data[4*i+3] = color_table[i][3];
680    //fprintf(stderr, "(%f,%f,%f,%f) ", data[4*i+0], data[4*i+1], data[4*i+2], data[4*i+3]);
681  }
682
683  tf[0]->update(data);
684
685#ifdef EVENTLOG
686  float param[3] = {0,0,0};
687  Event* tmp = new Event(EVENT_ROTATE, param, get_time_interval());
688  tmp->write(event_log);
689  delete tmp;
690#endif
691}
692
693
694
695//initialize frame buffer objects for offscreen rendering
696void init_fbo(){
697
698  //initialize final fbo for final display
699  glGenFramebuffersEXT(1, &final_fbo);
700  glGenTextures(1, &final_color_tex);
701  glGenRenderbuffersEXT(1, &final_depth_rb);
702
703  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
704
705  //initialize final color texture
706  glBindTexture(GL_TEXTURE_2D, final_color_tex);
707  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
708  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
709#ifdef NV40
710  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, win_width, win_height, 0,
711               GL_RGB, GL_INT, NULL);
712#else
713  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0,
714               GL_RGB, GL_INT, NULL);
715#endif
716  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
717                            GL_COLOR_ATTACHMENT0_EXT,
718                            GL_TEXTURE_2D, final_color_tex, 0);
719
720       
721  // initialize final depth renderbuffer
722  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb);
723  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
724                           GL_DEPTH_COMPONENT24, win_width, win_height);
725  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
726                               GL_DEPTH_ATTACHMENT_EXT,
727                               GL_RENDERBUFFER_EXT, final_depth_rb);
728
729  // Check framebuffer completeness at the end of initialization.
730  CHECK_FRAMEBUFFER_STATUS();
731  assert(glGetError()==0);
732}
733
734
735void init_cg(){
736    cgSetErrorCallback(cgErrorCallback);
737    g_context = cgCreateContext();
738
739#ifdef NEW_CG
740    m_posvel_fprog = loadProgram(g_context, CG_PROFILE_FP40, CG_SOURCE, "./shaders/update_pos_vel.cg");
741    m_posvel_timestep_param  = cgGetNamedParameter(m_posvel_fprog, "timestep");
742    m_posvel_damping_param   = cgGetNamedParameter(m_posvel_fprog, "damping");
743    m_posvel_gravity_param   = cgGetNamedParameter(m_posvel_fprog, "gravity");
744    m_posvel_spherePos_param = cgGetNamedParameter(m_posvel_fprog, "spherePos");
745    m_posvel_sphereVel_param = cgGetNamedParameter(m_posvel_fprog, "sphereVel");
746#endif
747}
748
749
750//switch shader to change render mode
751void switch_shader(int choice){
752
753  switch (choice){
754    case 0:
755      break;
756
757   case 1:
758      break;
759     
760   default:
761      break;
762  }
763}
764
765void init_particles(){
766  //random placement on a slice
767  float* data = new float[psys->psys_width * psys->psys_height * 4];
768  bzero(data, sizeof(float)*4* psys->psys_width * psys->psys_height);
769
770  for (int i=0; i<psys->psys_width; i++){
771    for (int j=0; j<psys->psys_height; j++){
772      int index = i + psys->psys_height*j;
773      bool particle = rand() % 256 > 150;
774      //particle = true;
775      if(particle) /*&& i/float(psys->psys_width)>0.3 && i/float(psys->psys_width)<0.7
776                      && j/float(psys->psys_height)>0.1 && j/float(psys->psys_height)<0.4)*/
777      {
778        //assign any location (x,y,z) in range [0,1]
779        data[4*index] = lic_slice_x;
780        data[4*index+1]= j/float(psys->psys_height);
781        data[4*index+2]= i/float(psys->psys_width);
782        data[4*index+3]= 30; //shorter life span, quicker iterations   
783      }
784      else
785      {
786        data[4*index] = 0;
787        data[4*index+1]= 0;
788        data[4*index+2]= 0;
789        data[4*index+3]= 0;     
790      }
791    }
792   }
793
794  psys->initialize((Particle*)data);
795  delete[] data;
796}
797
798
799void init_tf(){
800  float data[256*4];
801  memset(data, 0, 4*256*sizeof(float));
802
803  tf[0] = new TransferFunction(256, data);
804}
805
806
807//init line integral convolution
808void init_lic(){
809  lic = new Lic(NMESH, win_width, win_height, 0.3, g_context, volume[0]->id,
810                  volume[0]->aspect_ratio_width,
811                  volume[0]->aspect_ratio_height,
812                  volume[0]->aspect_ratio_depth);
813}
814
815/*----------------------------------------------------*/
816void initGL(void)
817{
818   system_info();
819   init_glew();
820
821   //create the camera with default setting
822   cam = new Camera(win_width, win_height,
823                   live_obj_x, live_obj_y, live_obj_z,
824                   0., 0., 100.,
825                   live_rot_x, live_rot_y, live_rot_z);
826
827   glEnable(GL_TEXTURE_2D);
828   glShadeModel(GL_FLAT);
829   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
830   glClearColor(0,0,0,1);
831   glClear(GL_COLOR_BUFFER_BIT);
832
833   //initialize lighting
834   GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
835   GLfloat mat_shininess[] = {30.0};
836   GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
837   GLfloat green_light[] = {0.1, 0.5, 0.1, 1.0};
838
839   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
840   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
841   glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
842   glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);     
843   glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light);
844   glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);     
845
846   //init volume and colormap arrays
847   for(int i=0; i<MAX_N_VOLUMES; i++){
848     volume[i] = 0;
849     tf[i] = 0;
850   }
851
852   //check if performance query is supported
853   if(check_query_support()){
854     //create queries to count number of rendered pixels
855     perf = new PerfQuery();
856   }
857
858   //load_volume_file(0, "./data/A-apbs-2-out-potential-PE0.dx");
859   //load_volume_file(0, "./data/nw-AB-Vg=0.000-Vd=1.000-potential.dx");
860   //load_volume_file(0, "./data/test2.dx");
861
862   load_vector_file(0, "./data/J-wire-vec.dx");
863   load_volume_file(1, "./data/mu-wire-3d.dx");
864   load_volume_file(2, "./data/mu-wire-3d.dx");
865   load_volume_file(3, "./data/mu-wire-3d.dx");
866
867   init_tf();   //initialize transfer function
868   init_fbo();  //frame buffer objects
869   init_cg();   //init cg shaders
870   init_lic();  //init line integral convolution
871
872   //create volume renderer
873   vol_render = new VolumeRenderer(cam, volume[1], tf[0], g_context);
874   vol_render->add_volume(volume[2], tf[0], 256);
875   volume[2]->location =Vector3(0.42, 0.1, 0.1);
876   vol_render->add_volume(volume[3], tf[0], 256);
877   volume[3]->location =Vector3(0.2, -0.1, -0.1);
878
879   
880   psys = new ParticleSystem(NMESH, NMESH, g_context, volume[0]->id,
881                   1./volume[0]->aspect_ratio_width,
882                   1./volume[0]->aspect_ratio_height,
883                   1./volume[0]->aspect_ratio_depth);
884   
885   //psys = new ParticleSystem(NMESH, NMESH, g_context, volume[0]->id, 0.25, 1., 1.);
886
887   init_particles();    //fill initial particles
888}
889
890
891
892void initTcl(){
893  interp = Tcl_CreateInterp();
894  Tcl_MakeSafe(interp);
895
896  Tcl_CreateCommand(interp, "camera", CameraCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
897  //Tcl_CreateCommand(interp, "size", SizeCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
898  //Tcl_CreateCommand(interp, "clear", ClearCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
899  //Tcl_CreateCommand(interp, "cut", CutCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
900  //Tcl_CreateCommand(interp, "outline", OutlineCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
901  Tcl_CreateCommand(interp, "hello", HelloCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
902  Tcl_CreateCommand(interp, "move", MoveCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
903  Tcl_CreateCommand(interp, "refresh", RefreshCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
904  //Tcl_CreateCommand(interp, "load", LoadCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
905}
906
907
908void read_screen(){
909  //glBindTexture(GL_TEXTURE_2D, 0);
910  //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
911  glReadPixels(0, 0, win_width, win_height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
912  assert(glGetError()==0);
913 
914  for(int i=0; i<win_width*win_height; i++){
915    if(screen_buffer[3*i]!=0 || screen_buffer[3*i+1]!=0 || screen_buffer[3*i+2]!=0)
916      fprintf(stderr, "(%d %d %d) ", screen_buffer[3*i], screen_buffer[3*i+1],  screen_buffer[3*i+2]);
917  }
918 
919}
920
921void display();
922
923
924char rle[512*512*3];
925int rle_size;
926
927short offsets[512*512*3];
928int offsets_size;
929
930void do_rle(){
931  int len = win_width*win_height*3;
932  rle_size = 0;
933  offsets_size = 0;
934
935  int i=0;
936  while(i<len){
937    if (screen_buffer[i] == 0) {
938      int pos = i+1;
939      while ( (pos<len) && (screen_buffer[pos] == 0)) {
940        pos++;
941      }
942      offsets[offsets_size++] = -(pos - i);
943      i = pos;
944    }
945
946    else {
947      int pos;
948      for (pos = i; (pos<len) && (screen_buffer[pos] != 0); pos++) {
949        rle[rle_size++] = screen_buffer[pos];
950      }
951      offsets[offsets_size++] = (pos - i);
952      i = pos;
953    }
954
955  }
956}
957
958// used internally to build up the BMP file header
959// writes an integer value into the header data structure at pos
960void
961bmp_header_add_int(unsigned char* header, int& pos, int data)
962{
963    header[pos++] = data & 0xff;
964    header[pos++] = (data >> 8) & 0xff;
965    header[pos++] = (data >> 16) & 0xff;
966    header[pos++] = (data >> 24) & 0xff;
967}
968
969
970void xinetd_listen(){
971    //command:
972    // 0. load data
973    // 1. flip on/off screen
974    // 2. rotation
975    // 3. zoom
976    // 4. more slices
977    // 5. less sleces
978
979    std::string data;
980    char tmp[256];
981    bzero(tmp, 256);
982    int status = read(0, tmp, 256);
983    if (status <= 0) {
984      exit(0);
985    }
986    fprintf(stderr, "read %d\n", status);
987    data = tmp;
988
989    if(Tcl_Eval(interp, (char*)data.c_str()) != TCL_OK) {
990      //error to log file...
991      fprintf(stderr, "Tcl error: parser\n");
992      return;
993    }
994
995    display();
996
997#if DO_RLE
998    do_rle();
999    int sizes[2] = {  offsets_size*sizeof(offsets[0]), rle_size };
1000    fprintf(stderr, "Writing %d,%d\n", sizes[0], sizes[1]); fflush(stderr);
1001    write(0, &sizes, sizeof(sizes));
1002    write(0, offsets, offsets_size*sizeof(offsets[0]));
1003    write(0, rle, rle_size);    //unsigned byte
1004#else
1005    unsigned char header[54];
1006    int pos = 0;
1007    header[pos++] = 'B';
1008    header[pos++] = 'M';
1009
1010    // file size in bytes
1011    bmp_header_add_int(header, pos, win_width*win_height*3 + sizeof(header));
1012
1013    // reserved value (must be 0)
1014    bmp_header_add_int(header, pos, 0);
1015
1016    // offset in bytes to start of bitmap data
1017    bmp_header_add_int(header, pos, sizeof(header));
1018
1019    // size of the BITMAPINFOHEADER
1020    bmp_header_add_int(header, pos, 40);
1021
1022    // width of the image in pixels
1023    bmp_header_add_int(header, pos, win_width);
1024
1025    // height of the image in pixels
1026    bmp_header_add_int(header, pos, win_height);
1027
1028    // 1 plane + 24 bits/pixel << 16
1029    bmp_header_add_int(header, pos, 1572865);
1030
1031    // no compression
1032    // size of image for compression
1033    bmp_header_add_int(header, pos, 0);
1034    bmp_header_add_int(header, pos, 0);
1035
1036    // x pixels per meter
1037    // y pixels per meter
1038    bmp_header_add_int(header, pos, 0);
1039    bmp_header_add_int(header, pos, 0);
1040
1041    // number of colors used (0 = compute from bits/pixel)
1042    // number of important colors (0 = all colors important)
1043    bmp_header_add_int(header, pos, 0);
1044    bmp_header_add_int(header, pos, 0);
1045
1046    write(0, header, sizeof(header));
1047    write(0, screen_buffer, win_width * win_height * 3);
1048#endif
1049
1050    cerr << "server: serve() image sent" << endl;
1051}
1052
1053
1054/*
1055//draw vectors
1056void draw_arrows(){
1057  glColor4f(0.,0.,1.,1.);
1058  for(int i=0; i<NMESH; i++){
1059    for(int j=0; j<NMESH; j++){
1060      Vector2 v = grid.get(i, j);
1061
1062      int x1 = i*DM;
1063      int y1 = j*DM;
1064
1065      int x2 = x1 + v.x;
1066      int y2 = y1 + v.y;
1067
1068      glBegin(GL_LINES);
1069        glVertex2d(x1, y1);
1070        glVertex2d(x2, y2);
1071      glEnd();
1072    }
1073  }
1074}
1075*/
1076
1077
1078/*----------------------------------------------------*/
1079void idle(){
1080  glutSetWindow(render_window);
1081
1082 
1083  /*
1084  struct timespec ts;
1085  ts.tv_sec = 0;
1086  ts.tv_nsec = 300000000;
1087  nanosleep(&ts, 0);
1088  */
1089 
1090
1091#ifdef XINETD
1092  xinetd_listen();
1093#else
1094  glutPostRedisplay();
1095#endif
1096}
1097
1098
1099void display_final_fbo(){
1100   glEnable(GL_TEXTURE_2D);
1101   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1102   glBindTexture(GL_TEXTURE_2D, final_color_tex);
1103
1104   glMatrixMode(GL_PROJECTION);
1105   glLoadIdentity();
1106   gluOrtho2D(-1, 1, -1, 1);
1107   glMatrixMode(GL_MODELVIEW);
1108   glLoadIdentity();
1109
1110   //glColor3f(1.,1.,1.);               //MUST HAVE THIS LINE!!!
1111   glBegin(GL_QUADS);
1112   glTexCoord2f(0, 0); glVertex2f(-1, -1);
1113   glTexCoord2f(1, 0); glVertex2f(1, -1);
1114   glTexCoord2f(1, 1); glVertex2f(1, 1);
1115   glTexCoord2f(0, 1); glVertex2f(-1, 1);
1116   glEnd();
1117}
1118
1119void final_fbo_capture(){
1120   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
1121}
1122
1123void draw_bounding_box(float x0, float y0, float z0,
1124                float x1, float y1, float z1,
1125                float r, float g, float b, float line_width)
1126{
1127        glDisable(GL_TEXTURE_2D);
1128
1129        glColor4d(r, g, b, 1.0);
1130        glLineWidth(line_width);
1131       
1132        glBegin(GL_LINE_LOOP);
1133
1134                glVertex3d(x0, y0, z0);
1135                glVertex3d(x1, y0, z0);
1136                glVertex3d(x1, y1, z0);
1137                glVertex3d(x0, y1, z0);
1138               
1139        glEnd();
1140
1141        glBegin(GL_LINE_LOOP);
1142
1143                glVertex3d(x0, y0, z1);
1144                glVertex3d(x1, y0, z1);
1145                glVertex3d(x1, y1, z1);
1146                glVertex3d(x0, y1, z1);
1147               
1148        glEnd();
1149
1150
1151        glBegin(GL_LINE_LOOP);
1152
1153                glVertex3d(x0, y0, z0);
1154                glVertex3d(x0, y0, z1);
1155                glVertex3d(x0, y1, z1);
1156                glVertex3d(x0, y1, z0);
1157               
1158        glEnd();
1159
1160        glBegin(GL_LINE_LOOP);
1161
1162                glVertex3d(x1, y0, z0);
1163                glVertex3d(x1, y0, z1);
1164                glVertex3d(x1, y1, z1);
1165                glVertex3d(x1, y1, z0);
1166               
1167        glEnd();
1168
1169        glEnable(GL_TEXTURE_2D);
1170}
1171
1172
1173
1174int particle_distance_sort(const void* a, const void* b){
1175  if((*((Particle*)a)).aux > (*((Particle*)b)).aux)
1176    return -1;
1177  else
1178    return 1;
1179}
1180
1181
1182void soft_read_verts(){
1183  glReadPixels(0, 0, psys->psys_width, psys->psys_height, GL_RGB, GL_FLOAT, vert);
1184  //fprintf(stderr, "soft_read_vert");
1185
1186  //cpu sort the distance 
1187  Particle* p = (Particle*) malloc(sizeof(Particle)* psys->psys_width * psys->psys_height);
1188  for(int i=0; i<psys->psys_width * psys->psys_height; i++){
1189    float x = vert[3*i];
1190    float y = vert[3*i+1];
1191    float z = vert[3*i+2];
1192
1193    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);
1194    p[i].x = x;
1195    p[i].y = y;
1196    p[i].z = z;
1197    p[i].aux = dis;
1198  }
1199
1200  qsort(p, psys->psys_width * psys->psys_height, sizeof(Particle), particle_distance_sort);
1201
1202  for(int i=0; i<psys->psys_width * psys->psys_height; i++){
1203    vert[3*i] = p[i].x;
1204    vert[3*i+1] = p[i].y;
1205    vert[3*i+2] = p[i].z;
1206  }
1207
1208  free(p);
1209}
1210
1211
1212//display the content of a texture as a screen aligned quad
1213void display_texture(NVISid tex, int width, int height){
1214   glPushMatrix();
1215
1216   glEnable(GL_TEXTURE_2D);
1217   glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex);
1218
1219   glViewport(0, 0, width, height);
1220   glMatrixMode(GL_PROJECTION);
1221   glLoadIdentity();
1222   gluOrtho2D(0, width, 0, height);
1223   glMatrixMode(GL_MODELVIEW);
1224   glLoadIdentity();
1225
1226   cgGLBindProgram(m_passthru_fprog);
1227   cgGLEnableProfile(CG_PROFILE_FP30);
1228
1229   cgGLSetParameter4f(m_passthru_scale_param, 1.0, 1.0, 1.0, 1.0);
1230   cgGLSetParameter4f(m_passthru_bias_param, 0.0, 0.0, 0.0, 0.0);
1231   
1232   draw_quad(width, height, width, height);
1233   cgGLDisableProfile(CG_PROFILE_FP30);
1234
1235   glPopMatrix();
1236
1237   assert(glGetError()==0);
1238}
1239
1240
1241//draw vertices in the main memory
1242void soft_display_verts(){
1243  glDisable(GL_TEXTURE_2D);
1244  glEnable(GL_BLEND);
1245
1246  glPointSize(0.5);
1247  glColor4f(0,0.8,0.8,0.6);
1248  glBegin(GL_POINTS);
1249  for(int i=0; i<psys->psys_width * psys->psys_height; i++){
1250    glVertex3f(vert[3*i], vert[3*i+1], vert[3*i+2]);
1251  }
1252  glEnd();
1253  //fprintf(stderr, "soft_display_vert");
1254}
1255
1256
1257#if 0
1258
1259//oddeven sort on GPU
1260void sortstep()
1261{
1262    // perform one step of the current sorting algorithm
1263
1264        /*
1265    // swap buffers
1266    int sourceBuffer = targetBuffer;
1267    targetBuffer = (targetBuffer+1)%2;   
1268    int pstage = (1<<stage);
1269    int ppass  = (1<<pass);
1270    int activeBitonicShader = 0;
1271
1272#ifdef _WIN32
1273    buffer->BindBuffer(wglTargets[sourceBuffer]);
1274#else
1275    buffer->BindBuffer(glTargets[sourceBuffer]);
1276#endif
1277    if (buffer->IsDoubleBuffered()) glDrawBuffer(glTargets[targetBuffer]);
1278    */
1279
1280    checkGLError("after db");
1281
1282    int pstage = (1<<stage);
1283    int ppass  = (1<<pass);
1284    //int activeBitonicShader = 0;
1285
1286    // switch on correct sorting shader
1287    oddevenMergeSort.bind();
1288    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param1"), float(pstage+pstage),
1289                   float(ppass%pstage), float((pstage+pstage)-(ppass%pstage)-1));
1290    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param2"), float(psys_width), float(psys_height), float(ppass));
1291    glUniform1iARB(oddevenMergeSort.getUniformLocation("Data"), 0);
1292    staticdebugmsg("sort","stage "<<pstage<<" pass "<<ppass);
1293
1294    // This clear is not necessary for sort to function. But if we are in interactive mode
1295    // unused parts of the texture that are visible will look bad.
1296    //if (!perfTest) glClear(GL_COLOR_BUFFER_BIT);
1297
1298    //buffer->Bind();
1299    //buffer->EnableTextureTarget();
1300
1301    // initiate the sorting step on the GPU
1302    // a full-screen quad
1303    glBegin(GL_QUADS);
1304    /*
1305    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f); glVertex2f(-1.0f,-1.0f);
1306    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f); glVertex2f(1.0f,-1.0f);
1307    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f); glVertex2f(1.0f,1.0f);       
1308    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f); glVertex2f(-1.0f,1.0f);   
1309    */
1310    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f); glVertex2f(0.,0.);       
1311    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f); glVertex2f(float(psys_width), 0.);
1312    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f); glVertex2f(float(psys_width), float(psys_height));   
1313    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f); glVertex2f(0., float(psys_height));       
1314    glEnd();
1315
1316
1317    // switch off sorting shader
1318    oddevenMergeSort.release();
1319
1320    //buffer->DisableTextureTarget();
1321
1322    assert(glGetError()==0);
1323}
1324
1325#endif
1326
1327
1328void draw_3d_axis(){
1329  glDisable(GL_TEXTURE_2D);
1330  glEnable(GL_DEPTH_TEST);
1331
1332        //draw axes
1333        GLUquadric *obj;
1334        obj = gluNewQuadric();
1335       
1336        glDepthFunc(GL_LESS);
1337        glEnable(GL_DEPTH_TEST);
1338        glDisable(GL_BLEND);
1339
1340        int segments = 50;
1341
1342        glColor3f(0.8, 0.8, 0.8);
1343        glPushMatrix();
1344        glTranslatef(0.4, 0., 0.);
1345        glScalef(0.0005, 0.0005, 0.0005);
1346        glutStrokeCharacter(GLUT_STROKE_ROMAN, 'x');
1347        glPopMatrix(); 
1348
1349        glPushMatrix();
1350        glTranslatef(0., 0.4, 0.);
1351        glScalef(0.0005, 0.0005, 0.0005);
1352        glutStrokeCharacter(GLUT_STROKE_ROMAN, 'y');
1353        glPopMatrix(); 
1354
1355        glPushMatrix();
1356        glTranslatef(0., 0., 0.4);
1357        glScalef(0.0005, 0.0005, 0.0005);
1358        glutStrokeCharacter(GLUT_STROKE_ROMAN, 'z');
1359        glPopMatrix(); 
1360
1361        glEnable(GL_LIGHTING);
1362        glEnable(GL_LIGHT0);
1363
1364        glColor3f(0.2, 0.2, 0.8);
1365        glPushMatrix();
1366        glutSolidSphere(0.02, segments, segments );
1367        glPopMatrix();
1368
1369        glPushMatrix();
1370        glRotatef(-90, 1, 0, 0);       
1371        gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1372        glPopMatrix(); 
1373
1374        glPushMatrix();
1375        glTranslatef(0., 0.3, 0.);
1376        glRotatef(-90, 1, 0, 0);       
1377        gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1378        glPopMatrix(); 
1379
1380        glPushMatrix();
1381        glRotatef(90, 0, 1, 0);
1382        gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1383        glPopMatrix(); 
1384
1385        glPushMatrix();
1386        glTranslatef(0.3, 0., 0.);
1387        glRotatef(90, 0, 1, 0);
1388        gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1389        glPopMatrix(); 
1390
1391        glPushMatrix();
1392        gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1393        glPopMatrix(); 
1394
1395        glPushMatrix();
1396        glTranslatef(0., 0., 0.3);
1397        gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1398        glPopMatrix(); 
1399
1400        glDisable(GL_LIGHTING);
1401        glDisable(GL_DEPTH_TEST);
1402        gluDeleteQuadric(obj);
1403
1404  glEnable(GL_TEXTURE_2D);
1405  glDisable(GL_DEPTH_TEST);
1406}
1407
1408
1409void draw_axis(){
1410
1411  glDisable(GL_TEXTURE_2D);
1412  glEnable(GL_DEPTH_TEST);
1413
1414  //red x
1415  glColor3f(1,0,0);
1416  glBegin(GL_LINES);
1417    glVertex3f(0,0,0);
1418    glVertex3f(1.5,0,0);
1419  glEnd();
1420
1421  //blue y
1422  glColor3f(0,0,1);
1423  glBegin(GL_LINES);
1424    glVertex3f(0,0,0);
1425    glVertex3f(0,1.5,0);
1426  glEnd();
1427
1428  //green z
1429  glColor3f(0,1,0);
1430  glBegin(GL_LINES);
1431    glVertex3f(0,0,0);
1432    glVertex3f(0,0,1.5);
1433  glEnd();
1434
1435  glEnable(GL_TEXTURE_2D);
1436  glDisable(GL_DEPTH_TEST);
1437}
1438
1439
1440
1441/*----------------------------------------------------*/
1442void display()
1443{
1444
1445   assert(glGetError()==0);
1446
1447   lic->convolve(); //flow line integral convolution
1448
1449   psys->advect(); //advect particles
1450
1451   final_fbo_capture();
1452   //display_texture(slice_vector_tex, NMESH, NMESH);
1453
1454#if 1
1455   //start final rendering
1456   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
1457
1458   glEnable(GL_TEXTURE_2D);
1459   glEnable(GL_DEPTH_TEST);
1460
1461   //camera setting activated
1462   cam->activate();
1463
1464   //now render things in the scene
1465   //
1466   draw_3d_axis();
1467   
1468   lic->render();       //display the line integral convolution result
1469   
1470   //soft_display_verts();
1471   perf->enable();
1472     psys->render();
1473   perf->disable();
1474   //fprintf(stderr, "particle pixels: %d\n", perf->get_pixel_count());
1475   perf->reset();
1476
1477
1478   perf->enable();
1479     //vol_render->render(0);
1480     vol_render->render_all();
1481
1482     //fprintf(stderr, "%lf\n", get_time_interval());
1483   perf->disable();
1484   //fprintf(stderr, "volume pixels: %d\n", perf->get_pixel_count());
1485 
1486#ifdef XINETD
1487   float cost  = perf->get_pixel_count();
1488   write(3, &cost, sizeof(cost));
1489#endif
1490   perf->reset();
1491
1492#endif
1493
1494   display_final_fbo(); //display the final rendering on screen
1495
1496#ifdef XINETD
1497   read_screen();
1498#else
1499   //read_screen();
1500#endif   
1501
1502   glutSwapBuffers();
1503}
1504
1505
1506void mouse(int button, int state, int x, int y){
1507  if(button==GLUT_LEFT_BUTTON){
1508
1509    if(state==GLUT_DOWN){
1510      left_last_x = x;
1511      left_last_y = y;
1512      left_down = true;
1513      right_down = false;
1514    }
1515    else{
1516      left_down = false;
1517      right_down = false;
1518    }
1519  }
1520  else{
1521    //fprintf(stderr, "right mouse\n");
1522
1523    if(state==GLUT_DOWN){
1524      //fprintf(stderr, "right mouse down\n");
1525      right_last_x = x;
1526      right_last_y = y;
1527      left_down = false;
1528      right_down = true;
1529    }
1530    else{
1531      //fprintf(stderr, "right mouse up\n");
1532      left_down = false;
1533      right_down = false;
1534    }
1535  }
1536}
1537
1538
1539void update_rot(int delta_x, int delta_y){
1540        live_rot_x += delta_x;
1541        live_rot_y += delta_y;
1542
1543        if(live_rot_x > 360.0)
1544                live_rot_x -= 360.0;   
1545        else if(live_rot_x < -360.0)
1546                live_rot_x += 360.0;
1547
1548        if(live_rot_y > 360.0)
1549                live_rot_y -= 360.0;   
1550        else if(live_rot_y < -360.0)
1551                live_rot_y += 360.0;
1552
1553        cam->rotate(live_rot_x, live_rot_y, live_rot_z);
1554}
1555
1556
1557void update_trans(int delta_x, int delta_y, int delta_z){
1558        live_obj_x += delta_x*0.03;
1559        live_obj_y += delta_y*0.03;
1560        live_obj_z += delta_z*0.03;
1561}
1562
1563void end_service();
1564
1565void keyboard(unsigned char key, int x, int y){
1566 
1567   bool log = false;
1568
1569   switch (key){
1570        case 'q':
1571#ifdef XINETD
1572                end_service();
1573#endif
1574                exit(0);
1575                break;
1576        case '+':
1577                lic_slice_z+=0.05;
1578                lic->set_offset(lic_slice_z);
1579                break;
1580        case '-':
1581                lic_slice_z-=0.05;
1582                lic->set_offset(lic_slice_z);
1583                break;
1584        case ',':
1585                lic_slice_x+=0.05;
1586                init_particles();
1587                break;
1588        case '.':
1589                lic_slice_x-=0.05;
1590                init_particles();
1591                break;
1592        case '1':
1593                advect = true;
1594                break;
1595        case '2':
1596                psys_x+=0.05;
1597                break;
1598        case '3':
1599                psys_x-=0.05;
1600                break;
1601        case 'w': //zoom out
1602                live_obj_z-=0.05;
1603                log = true;
1604                cam->move(live_obj_x, live_obj_y, live_obj_z);
1605                break;
1606        case 's': //zoom in
1607                live_obj_z+=0.05;
1608                log = true;
1609                cam->move(live_obj_x, live_obj_y, live_obj_z);
1610                break;
1611        case 'a': //left
1612                live_obj_x-=0.05;
1613                log = true;
1614                cam->move(live_obj_x, live_obj_y, live_obj_z);
1615                break;
1616        case 'd': //right
1617                live_obj_x+=0.05;
1618                log = true;
1619                cam->move(live_obj_x, live_obj_y, live_obj_z);
1620                break;
1621        case 'i':
1622                init_particles();
1623                break;
1624        case 'o':
1625                live_specular+=1;
1626                fprintf(stderr, "specular: %f\n", live_specular);
1627                vol_render->set_specular(live_specular);
1628                break;
1629        case 'p':
1630                live_specular-=1;
1631                fprintf(stderr, "specular: %f\n", live_specular);
1632                vol_render->set_specular(live_specular);
1633                break;
1634        case '[':
1635                live_diffuse+=0.5;
1636                vol_render->set_diffuse(live_diffuse);
1637                break;
1638        case ']':
1639                live_diffuse-=0.5;
1640                vol_render->set_diffuse(live_diffuse);
1641                break;
1642        case 'v':
1643                vol_render->switch_volume_mode();
1644                break;
1645        case 'b':
1646                vol_render->switch_slice_mode();
1647                break;
1648
1649        default:
1650                break;
1651    }   
1652
1653#ifdef EVENTLOG
1654   if(log){
1655     float param[3] = {live_obj_x, live_obj_y, live_obj_z};
1656     Event* tmp = new Event(EVENT_MOVE, param, get_time_interval());
1657     tmp->write(event_log);
1658     delete tmp;
1659   }
1660#endif
1661}
1662
1663void motion(int x, int y){
1664
1665    int old_x, old_y;   
1666
1667    if(left_down){
1668      old_x = left_last_x;
1669      old_y = left_last_y;   
1670    }
1671    else if(right_down){
1672      old_x = right_last_x;
1673      old_y = right_last_y;   
1674    }
1675
1676    int delta_x = x - old_x;
1677    int delta_y = y - old_y;
1678
1679    //more coarse event handling
1680    //if(abs(delta_x)<10 && abs(delta_y)<10)
1681      //return;
1682
1683    if(left_down){
1684      left_last_x = x;
1685      left_last_y = y;
1686
1687      update_rot(-delta_y, -delta_x);
1688    }
1689    else if (right_down){
1690      //fprintf(stderr, "right mouse motion (%d,%d)\n", x, y);
1691
1692      right_last_x = x;
1693      right_last_y = y;
1694
1695      update_trans(0, 0, delta_x);
1696    }
1697
1698#ifdef EVENTLOG
1699    float param[3] = {live_rot_x, live_rot_y, live_rot_z};
1700    Event* tmp = new Event(EVENT_ROTATE, param, get_time_interval());
1701    tmp->write(event_log);
1702    delete tmp;
1703#endif
1704
1705    glutPostRedisplay();
1706}
1707
1708#ifdef XINETD
1709void init_service(){
1710  //open log and map stderr to log file
1711  xinetd_log = fopen("log.txt", "w");
1712  close(2);
1713  dup2(fileno(xinetd_log), 2);
1714  dup2(2,1);
1715
1716  //flush junk
1717  fflush(stdout);
1718  fflush(stderr);
1719}
1720
1721void end_service(){
1722  //close log file
1723  fclose(xinetd_log);
1724}
1725#endif
1726
1727void init_event_log(){
1728  event_log = fopen("event.txt", "w");
1729  assert(event_log!=0);
1730
1731  struct timeval time;
1732  gettimeofday(&time, NULL);
1733  cur_time = time.tv_sec*1000. + time.tv_usec/1000.;
1734}
1735
1736void end_event_log(){
1737  fclose(event_log);
1738}
1739
1740double get_time_interval(){
1741  struct timeval time;
1742  gettimeofday(&time, NULL);
1743  double new_time = time.tv_sec*1000. + time.tv_usec/1000.;
1744
1745  double interval = new_time - cur_time;
1746  cur_time = new_time;
1747  return interval;
1748}
1749
1750
1751/*----------------------------------------------------*/
1752int main(int argc, char** argv)
1753{
1754#ifdef XINETD
1755   init_service();
1756#endif
1757
1758   glutInit(&argc, argv);
1759   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
1760
1761   MainTransferFunctionWindow * tf_window;
1762   tf_window = new MainTransferFunctionWindow();
1763   tf_window->mainInit();
1764   
1765   glutInitWindowSize(NPIX, NPIX);
1766   glutInitWindowPosition(10, 10);
1767   render_window = glutCreateWindow(argv[0]);
1768
1769   glutDisplayFunc(display);
1770   glutMouseFunc(mouse);
1771   glutMotionFunc(motion);
1772   glutKeyboardFunc(keyboard);
1773   glutIdleFunc(idle);
1774
1775   initGL();
1776   initTcl();
1777
1778#ifdef EVENTLOG
1779   init_event_log();
1780#endif
1781   //event loop
1782   glutMainLoop();
1783#ifdef EVENTLOG
1784   end_event_log();
1785#endif
1786
1787#ifdef XINETD
1788   end_service();
1789#endif
1790
1791   return 0;
1792}
Note: See TracBrowser for help on using the repository browser.