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

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

Added EventPlayer? back. It will connect with nanovis and display the render result.

File size: 49.5 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, 1.,  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
802  //alternatively, a default transfer function also works.
803  memset(data, 0, 4*256*sizeof(float));
804
805  tf[0] = new TransferFunction(256, data);
806}
807
808
809//init line integral convolution
810void init_lic(){
811  lic = new Lic(NMESH, win_width, win_height, 0.3, g_context, volume[0]->id,
812                  volume[0]->aspect_ratio_width,
813                  volume[0]->aspect_ratio_height,
814                  volume[0]->aspect_ratio_depth);
815}
816
817/*----------------------------------------------------*/
818void initGL(void)
819{
820   system_info();
821   init_glew();
822
823   //create the camera with default setting
824   cam = new Camera(win_width, win_height,
825                   live_obj_x, live_obj_y, live_obj_z,
826                   0., 0., 100.,
827                   live_rot_x, live_rot_y, live_rot_z);
828
829   glEnable(GL_TEXTURE_2D);
830   glShadeModel(GL_FLAT);
831   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
832   glClearColor(0,0,0,1);
833   glClear(GL_COLOR_BUFFER_BIT);
834
835   //initialize lighting
836   GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
837   GLfloat mat_shininess[] = {30.0};
838   GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
839   GLfloat green_light[] = {0.1, 0.5, 0.1, 1.0};
840
841   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
842   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
843   glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
844   glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);     
845   glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light);
846   glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);     
847
848   //init volume and colormap arrays
849   for(int i=0; i<MAX_N_VOLUMES; i++){
850     volume[i] = 0;
851     tf[i] = 0;
852   }
853
854   //check if performance query is supported
855   if(check_query_support()){
856     //create queries to count number of rendered pixels
857     perf = new PerfQuery();
858   }
859
860   //load_volume_file(0, "./data/A-apbs-2-out-potential-PE0.dx");
861   //load_volume_file(0, "./data/nw-AB-Vg=0.000-Vd=1.000-potential.dx");
862   //load_volume_file(0, "./data/test2.dx");
863
864   load_vector_file(0, "./data/J-wire-vec.dx");
865   load_volume_file(1, "./data/mu-wire-3d.dx");
866   load_volume_file(2, "./data/mu-wire-3d.dx");
867   //load_volume_file(3, "./data/mu-wire-3d.dx");
868
869   init_tf();   //initialize transfer function
870   init_fbo();  //frame buffer objects
871   init_cg();   //init cg shaders
872   init_lic();  //init line integral convolution
873
874   //create volume renderer and add volumes to it
875   vol_render = new VolumeRenderer(g_context);
876   vol_render->add_volume(volume[1], tf[0]);
877
878   volume[2]->move(Vector3(0.42, 0.1, 0.1));
879   vol_render->add_volume(volume[2], tf[0]);
880
881   //volume[3]->move(Vector3(0.2, -0.1, -0.1));
882   //vol_render->add_volume(volume[3], tf[0]);
883
884   
885   psys = new ParticleSystem(NMESH, NMESH, g_context, volume[0]->id,
886                   1./volume[0]->aspect_ratio_width,
887                   1./volume[0]->aspect_ratio_height,
888                   1./volume[0]->aspect_ratio_depth);
889   
890   //psys = new ParticleSystem(NMESH, NMESH, g_context, volume[0]->id, 0.25, 1., 1.);
891
892   init_particles();    //fill initial particles
893}
894
895
896
897void initTcl(){
898  interp = Tcl_CreateInterp();
899  Tcl_MakeSafe(interp);
900
901  Tcl_CreateCommand(interp, "camera", CameraCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
902  //Tcl_CreateCommand(interp, "size", SizeCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
903  //Tcl_CreateCommand(interp, "clear", ClearCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
904  //Tcl_CreateCommand(interp, "cut", CutCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
905  //Tcl_CreateCommand(interp, "outline", OutlineCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
906  Tcl_CreateCommand(interp, "hello", HelloCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
907  Tcl_CreateCommand(interp, "move", MoveCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
908  Tcl_CreateCommand(interp, "refresh", RefreshCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
909  //Tcl_CreateCommand(interp, "load", LoadCmd, (ClientData)0, (Tcl_CmdDeleteProc*)NULL);
910}
911
912
913void read_screen(){
914  //glBindTexture(GL_TEXTURE_2D, 0);
915  //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
916  glReadPixels(0, 0, win_width, win_height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
917  assert(glGetError()==0);
918 
919  for(int i=0; i<win_width*win_height; i++){
920    if(screen_buffer[3*i]!=0 || screen_buffer[3*i+1]!=0 || screen_buffer[3*i+2]!=0)
921      fprintf(stderr, "(%d %d %d) ", screen_buffer[3*i], screen_buffer[3*i+1],  screen_buffer[3*i+2]);
922  }
923 
924}
925
926void display();
927
928
929char rle[512*512*3];
930int rle_size;
931
932short offsets[512*512*3];
933int offsets_size;
934
935void do_rle(){
936  int len = win_width*win_height*3;
937  rle_size = 0;
938  offsets_size = 0;
939
940  int i=0;
941  while(i<len){
942    if (screen_buffer[i] == 0) {
943      int pos = i+1;
944      while ( (pos<len) && (screen_buffer[pos] == 0)) {
945        pos++;
946      }
947      offsets[offsets_size++] = -(pos - i);
948      i = pos;
949    }
950
951    else {
952      int pos;
953      for (pos = i; (pos<len) && (screen_buffer[pos] != 0); pos++) {
954        rle[rle_size++] = screen_buffer[pos];
955      }
956      offsets[offsets_size++] = (pos - i);
957      i = pos;
958    }
959
960  }
961}
962
963// used internally to build up the BMP file header
964// writes an integer value into the header data structure at pos
965void
966bmp_header_add_int(unsigned char* header, int& pos, int data)
967{
968    header[pos++] = data & 0xff;
969    header[pos++] = (data >> 8) & 0xff;
970    header[pos++] = (data >> 16) & 0xff;
971    header[pos++] = (data >> 24) & 0xff;
972}
973
974
975void xinetd_listen(){
976    //command:
977    // 0. load data
978    // 1. flip on/off screen
979    // 2. rotation
980    // 3. zoom
981    // 4. more slices
982    // 5. less sleces
983
984    std::string data;
985    char tmp[256];
986    bzero(tmp, 256);
987    int status = read(0, tmp, 256);
988    if (status <= 0) {
989      exit(0);
990    }
991    fprintf(stderr, "read %d\n", status);
992    data = tmp;
993
994    if(Tcl_Eval(interp, (char*)data.c_str()) != TCL_OK) {
995      //error to log file...
996      fprintf(stderr, "Tcl error: parser\n");
997      return;
998    }
999
1000    display();
1001
1002#if DO_RLE
1003    do_rle();
1004    int sizes[2] = {  offsets_size*sizeof(offsets[0]), rle_size };
1005    fprintf(stderr, "Writing %d,%d\n", sizes[0], sizes[1]); fflush(stderr);
1006    write(0, &sizes, sizeof(sizes));
1007    write(0, offsets, offsets_size*sizeof(offsets[0]));
1008    write(0, rle, rle_size);    //unsigned byte
1009#else
1010    unsigned char header[54];
1011    int pos = 0;
1012    header[pos++] = 'B';
1013    header[pos++] = 'M';
1014
1015    // file size in bytes
1016    bmp_header_add_int(header, pos, win_width*win_height*3 + sizeof(header));
1017
1018    // reserved value (must be 0)
1019    bmp_header_add_int(header, pos, 0);
1020
1021    // offset in bytes to start of bitmap data
1022    bmp_header_add_int(header, pos, sizeof(header));
1023
1024    // size of the BITMAPINFOHEADER
1025    bmp_header_add_int(header, pos, 40);
1026
1027    // width of the image in pixels
1028    bmp_header_add_int(header, pos, win_width);
1029
1030    // height of the image in pixels
1031    bmp_header_add_int(header, pos, win_height);
1032
1033    // 1 plane + 24 bits/pixel << 16
1034    bmp_header_add_int(header, pos, 1572865);
1035
1036    // no compression
1037    // size of image for compression
1038    bmp_header_add_int(header, pos, 0);
1039    bmp_header_add_int(header, pos, 0);
1040
1041    // x pixels per meter
1042    // y pixels per meter
1043    bmp_header_add_int(header, pos, 0);
1044    bmp_header_add_int(header, pos, 0);
1045
1046    // number of colors used (0 = compute from bits/pixel)
1047    // number of important colors (0 = all colors important)
1048    bmp_header_add_int(header, pos, 0);
1049    bmp_header_add_int(header, pos, 0);
1050
1051    write(0, header, sizeof(header));
1052    write(0, screen_buffer, win_width * win_height * 3);
1053#endif
1054
1055    cerr << "server: serve() image sent" << endl;
1056}
1057
1058
1059/*
1060//draw vectors
1061void draw_arrows(){
1062  glColor4f(0.,0.,1.,1.);
1063  for(int i=0; i<NMESH; i++){
1064    for(int j=0; j<NMESH; j++){
1065      Vector2 v = grid.get(i, j);
1066
1067      int x1 = i*DM;
1068      int y1 = j*DM;
1069
1070      int x2 = x1 + v.x;
1071      int y2 = y1 + v.y;
1072
1073      glBegin(GL_LINES);
1074        glVertex2d(x1, y1);
1075        glVertex2d(x2, y2);
1076      glEnd();
1077    }
1078  }
1079}
1080*/
1081
1082
1083/*----------------------------------------------------*/
1084void idle(){
1085  glutSetWindow(render_window);
1086
1087 
1088  /*
1089  struct timespec ts;
1090  ts.tv_sec = 0;
1091  ts.tv_nsec = 300000000;
1092  nanosleep(&ts, 0);
1093  */
1094 
1095
1096#ifdef XINETD
1097  xinetd_listen();
1098#else
1099  glutPostRedisplay();
1100#endif
1101}
1102
1103
1104void display_final_fbo(){
1105   glEnable(GL_TEXTURE_2D);
1106   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1107   glBindTexture(GL_TEXTURE_2D, final_color_tex);
1108
1109   glMatrixMode(GL_PROJECTION);
1110   glLoadIdentity();
1111   gluOrtho2D(-1, 1, -1, 1);
1112   glMatrixMode(GL_MODELVIEW);
1113   glLoadIdentity();
1114
1115   //glColor3f(1.,1.,1.);               //MUST HAVE THIS LINE!!!
1116   glBegin(GL_QUADS);
1117   glTexCoord2f(0, 0); glVertex2f(-1, -1);
1118   glTexCoord2f(1, 0); glVertex2f(1, -1);
1119   glTexCoord2f(1, 1); glVertex2f(1, 1);
1120   glTexCoord2f(0, 1); glVertex2f(-1, 1);
1121   glEnd();
1122}
1123
1124void final_fbo_capture(){
1125   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
1126}
1127
1128void draw_bounding_box(float x0, float y0, float z0,
1129                float x1, float y1, float z1,
1130                float r, float g, float b, float line_width)
1131{
1132        glDisable(GL_TEXTURE_2D);
1133
1134        glColor4d(r, g, b, 1.0);
1135        glLineWidth(line_width);
1136       
1137        glBegin(GL_LINE_LOOP);
1138
1139                glVertex3d(x0, y0, z0);
1140                glVertex3d(x1, y0, z0);
1141                glVertex3d(x1, y1, z0);
1142                glVertex3d(x0, y1, z0);
1143               
1144        glEnd();
1145
1146        glBegin(GL_LINE_LOOP);
1147
1148                glVertex3d(x0, y0, z1);
1149                glVertex3d(x1, y0, z1);
1150                glVertex3d(x1, y1, z1);
1151                glVertex3d(x0, y1, z1);
1152               
1153        glEnd();
1154
1155
1156        glBegin(GL_LINE_LOOP);
1157
1158                glVertex3d(x0, y0, z0);
1159                glVertex3d(x0, y0, z1);
1160                glVertex3d(x0, y1, z1);
1161                glVertex3d(x0, y1, z0);
1162               
1163        glEnd();
1164
1165        glBegin(GL_LINE_LOOP);
1166
1167                glVertex3d(x1, y0, z0);
1168                glVertex3d(x1, y0, z1);
1169                glVertex3d(x1, y1, z1);
1170                glVertex3d(x1, y1, z0);
1171               
1172        glEnd();
1173
1174        glEnable(GL_TEXTURE_2D);
1175}
1176
1177
1178
1179int particle_distance_sort(const void* a, const void* b){
1180  if((*((Particle*)a)).aux > (*((Particle*)b)).aux)
1181    return -1;
1182  else
1183    return 1;
1184}
1185
1186
1187void soft_read_verts(){
1188  glReadPixels(0, 0, psys->psys_width, psys->psys_height, GL_RGB, GL_FLOAT, vert);
1189  //fprintf(stderr, "soft_read_vert");
1190
1191  //cpu sort the distance 
1192  Particle* p = (Particle*) malloc(sizeof(Particle)* psys->psys_width * psys->psys_height);
1193  for(int i=0; i<psys->psys_width * psys->psys_height; i++){
1194    float x = vert[3*i];
1195    float y = vert[3*i+1];
1196    float z = vert[3*i+2];
1197
1198    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);
1199    p[i].x = x;
1200    p[i].y = y;
1201    p[i].z = z;
1202    p[i].aux = dis;
1203  }
1204
1205  qsort(p, psys->psys_width * psys->psys_height, sizeof(Particle), particle_distance_sort);
1206
1207  for(int i=0; i<psys->psys_width * psys->psys_height; i++){
1208    vert[3*i] = p[i].x;
1209    vert[3*i+1] = p[i].y;
1210    vert[3*i+2] = p[i].z;
1211  }
1212
1213  free(p);
1214}
1215
1216
1217//display the content of a texture as a screen aligned quad
1218void display_texture(NVISid tex, int width, int height){
1219   glPushMatrix();
1220
1221   glEnable(GL_TEXTURE_2D);
1222   glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex);
1223
1224   glViewport(0, 0, width, height);
1225   glMatrixMode(GL_PROJECTION);
1226   glLoadIdentity();
1227   gluOrtho2D(0, width, 0, height);
1228   glMatrixMode(GL_MODELVIEW);
1229   glLoadIdentity();
1230
1231   cgGLBindProgram(m_passthru_fprog);
1232   cgGLEnableProfile(CG_PROFILE_FP30);
1233
1234   cgGLSetParameter4f(m_passthru_scale_param, 1.0, 1.0, 1.0, 1.0);
1235   cgGLSetParameter4f(m_passthru_bias_param, 0.0, 0.0, 0.0, 0.0);
1236   
1237   draw_quad(width, height, width, height);
1238   cgGLDisableProfile(CG_PROFILE_FP30);
1239
1240   glPopMatrix();
1241
1242   assert(glGetError()==0);
1243}
1244
1245
1246//draw vertices in the main memory
1247void soft_display_verts(){
1248  glDisable(GL_TEXTURE_2D);
1249  glEnable(GL_BLEND);
1250
1251  glPointSize(0.5);
1252  glColor4f(0,0.8,0.8,0.6);
1253  glBegin(GL_POINTS);
1254  for(int i=0; i<psys->psys_width * psys->psys_height; i++){
1255    glVertex3f(vert[3*i], vert[3*i+1], vert[3*i+2]);
1256  }
1257  glEnd();
1258  //fprintf(stderr, "soft_display_vert");
1259}
1260
1261
1262#if 0
1263
1264//oddeven sort on GPU
1265void sortstep()
1266{
1267    // perform one step of the current sorting algorithm
1268
1269        /*
1270    // swap buffers
1271    int sourceBuffer = targetBuffer;
1272    targetBuffer = (targetBuffer+1)%2;   
1273    int pstage = (1<<stage);
1274    int ppass  = (1<<pass);
1275    int activeBitonicShader = 0;
1276
1277#ifdef _WIN32
1278    buffer->BindBuffer(wglTargets[sourceBuffer]);
1279#else
1280    buffer->BindBuffer(glTargets[sourceBuffer]);
1281#endif
1282    if (buffer->IsDoubleBuffered()) glDrawBuffer(glTargets[targetBuffer]);
1283    */
1284
1285    checkGLError("after db");
1286
1287    int pstage = (1<<stage);
1288    int ppass  = (1<<pass);
1289    //int activeBitonicShader = 0;
1290
1291    // switch on correct sorting shader
1292    oddevenMergeSort.bind();
1293    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param1"), float(pstage+pstage),
1294                   float(ppass%pstage), float((pstage+pstage)-(ppass%pstage)-1));
1295    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param2"), float(psys_width), float(psys_height), float(ppass));
1296    glUniform1iARB(oddevenMergeSort.getUniformLocation("Data"), 0);
1297    staticdebugmsg("sort","stage "<<pstage<<" pass "<<ppass);
1298
1299    // This clear is not necessary for sort to function. But if we are in interactive mode
1300    // unused parts of the texture that are visible will look bad.
1301    //if (!perfTest) glClear(GL_COLOR_BUFFER_BIT);
1302
1303    //buffer->Bind();
1304    //buffer->EnableTextureTarget();
1305
1306    // initiate the sorting step on the GPU
1307    // a full-screen quad
1308    glBegin(GL_QUADS);
1309    /*
1310    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f); glVertex2f(-1.0f,-1.0f);
1311    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f); glVertex2f(1.0f,-1.0f);
1312    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f); glVertex2f(1.0f,1.0f);       
1313    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f); glVertex2f(-1.0f,1.0f);   
1314    */
1315    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f); glVertex2f(0.,0.);       
1316    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f); glVertex2f(float(psys_width), 0.);
1317    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f); glVertex2f(float(psys_width), float(psys_height));   
1318    glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f); glVertex2f(0., float(psys_height));       
1319    glEnd();
1320
1321
1322    // switch off sorting shader
1323    oddevenMergeSort.release();
1324
1325    //buffer->DisableTextureTarget();
1326
1327    assert(glGetError()==0);
1328}
1329
1330#endif
1331
1332
1333void draw_3d_axis(){
1334  glDisable(GL_TEXTURE_2D);
1335  glEnable(GL_DEPTH_TEST);
1336
1337        //draw axes
1338        GLUquadric *obj;
1339        obj = gluNewQuadric();
1340       
1341        glDepthFunc(GL_LESS);
1342        glEnable(GL_DEPTH_TEST);
1343        glDisable(GL_BLEND);
1344
1345        int segments = 50;
1346
1347        glColor3f(0.8, 0.8, 0.8);
1348        glPushMatrix();
1349        glTranslatef(0.4, 0., 0.);
1350        glScalef(0.0005, 0.0005, 0.0005);
1351        glutStrokeCharacter(GLUT_STROKE_ROMAN, 'x');
1352        glPopMatrix(); 
1353
1354        glPushMatrix();
1355        glTranslatef(0., 0.4, 0.);
1356        glScalef(0.0005, 0.0005, 0.0005);
1357        glutStrokeCharacter(GLUT_STROKE_ROMAN, 'y');
1358        glPopMatrix(); 
1359
1360        glPushMatrix();
1361        glTranslatef(0., 0., 0.4);
1362        glScalef(0.0005, 0.0005, 0.0005);
1363        glutStrokeCharacter(GLUT_STROKE_ROMAN, 'z');
1364        glPopMatrix(); 
1365
1366        glEnable(GL_LIGHTING);
1367        glEnable(GL_LIGHT0);
1368
1369        glColor3f(0.2, 0.2, 0.8);
1370        glPushMatrix();
1371        glutSolidSphere(0.02, segments, segments );
1372        glPopMatrix();
1373
1374        glPushMatrix();
1375        glRotatef(-90, 1, 0, 0);       
1376        gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1377        glPopMatrix(); 
1378
1379        glPushMatrix();
1380        glTranslatef(0., 0.3, 0.);
1381        glRotatef(-90, 1, 0, 0);       
1382        gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1383        glPopMatrix(); 
1384
1385        glPushMatrix();
1386        glRotatef(90, 0, 1, 0);
1387        gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1388        glPopMatrix(); 
1389
1390        glPushMatrix();
1391        glTranslatef(0.3, 0., 0.);
1392        glRotatef(90, 0, 1, 0);
1393        gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1394        glPopMatrix(); 
1395
1396        glPushMatrix();
1397        gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1398        glPopMatrix(); 
1399
1400        glPushMatrix();
1401        glTranslatef(0., 0., 0.3);
1402        gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1403        glPopMatrix(); 
1404
1405        glDisable(GL_LIGHTING);
1406        glDisable(GL_DEPTH_TEST);
1407        gluDeleteQuadric(obj);
1408
1409  glEnable(GL_TEXTURE_2D);
1410  glDisable(GL_DEPTH_TEST);
1411}
1412
1413
1414void draw_axis(){
1415
1416  glDisable(GL_TEXTURE_2D);
1417  glEnable(GL_DEPTH_TEST);
1418
1419  //red x
1420  glColor3f(1,0,0);
1421  glBegin(GL_LINES);
1422    glVertex3f(0,0,0);
1423    glVertex3f(1.5,0,0);
1424  glEnd();
1425
1426  //blue y
1427  glColor3f(0,0,1);
1428  glBegin(GL_LINES);
1429    glVertex3f(0,0,0);
1430    glVertex3f(0,1.5,0);
1431  glEnd();
1432
1433  //green z
1434  glColor3f(0,1,0);
1435  glBegin(GL_LINES);
1436    glVertex3f(0,0,0);
1437    glVertex3f(0,0,1.5);
1438  glEnd();
1439
1440  glEnable(GL_TEXTURE_2D);
1441  glDisable(GL_DEPTH_TEST);
1442}
1443
1444
1445
1446/*----------------------------------------------------*/
1447void display()
1448{
1449
1450   assert(glGetError()==0);
1451
1452   lic->convolve(); //flow line integral convolution
1453
1454   psys->advect(); //advect particles
1455
1456   final_fbo_capture();
1457   //display_texture(slice_vector_tex, NMESH, NMESH);
1458
1459#if 1
1460   //start final rendering
1461   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
1462
1463   glEnable(GL_TEXTURE_2D);
1464   glEnable(GL_DEPTH_TEST);
1465
1466   //camera setting activated
1467   cam->activate();
1468
1469   //now render things in the scene
1470   //
1471   draw_3d_axis();
1472   
1473   lic->render();       //display the line integral convolution result
1474   
1475   //soft_display_verts();
1476   perf->enable();
1477     psys->render();
1478   perf->disable();
1479   //fprintf(stderr, "particle pixels: %d\n", perf->get_pixel_count());
1480   perf->reset();
1481
1482
1483   perf->enable();
1484     //vol_render->render(0);
1485     vol_render->render_all();
1486
1487     //fprintf(stderr, "%lf\n", get_time_interval());
1488   perf->disable();
1489   //fprintf(stderr, "volume pixels: %d\n", perf->get_pixel_count());
1490 
1491#ifdef XINETD
1492   float cost  = perf->get_pixel_count();
1493   write(3, &cost, sizeof(cost));
1494#endif
1495   perf->reset();
1496
1497#endif
1498
1499   display_final_fbo(); //display the final rendering on screen
1500
1501#ifdef XINETD
1502   read_screen();
1503#else
1504   //read_screen();
1505#endif   
1506
1507   glutSwapBuffers();
1508}
1509
1510
1511void mouse(int button, int state, int x, int y){
1512  if(button==GLUT_LEFT_BUTTON){
1513
1514    if(state==GLUT_DOWN){
1515      left_last_x = x;
1516      left_last_y = y;
1517      left_down = true;
1518      right_down = false;
1519    }
1520    else{
1521      left_down = false;
1522      right_down = false;
1523    }
1524  }
1525  else{
1526    //fprintf(stderr, "right mouse\n");
1527
1528    if(state==GLUT_DOWN){
1529      //fprintf(stderr, "right mouse down\n");
1530      right_last_x = x;
1531      right_last_y = y;
1532      left_down = false;
1533      right_down = true;
1534    }
1535    else{
1536      //fprintf(stderr, "right mouse up\n");
1537      left_down = false;
1538      right_down = false;
1539    }
1540  }
1541}
1542
1543
1544void update_rot(int delta_x, int delta_y){
1545        live_rot_x += delta_x;
1546        live_rot_y += delta_y;
1547
1548        if(live_rot_x > 360.0)
1549                live_rot_x -= 360.0;   
1550        else if(live_rot_x < -360.0)
1551                live_rot_x += 360.0;
1552
1553        if(live_rot_y > 360.0)
1554                live_rot_y -= 360.0;   
1555        else if(live_rot_y < -360.0)
1556                live_rot_y += 360.0;
1557
1558        cam->rotate(live_rot_x, live_rot_y, live_rot_z);
1559}
1560
1561
1562void update_trans(int delta_x, int delta_y, int delta_z){
1563        live_obj_x += delta_x*0.03;
1564        live_obj_y += delta_y*0.03;
1565        live_obj_z += delta_z*0.03;
1566}
1567
1568void end_service();
1569
1570void keyboard(unsigned char key, int x, int y){
1571 
1572   bool log = false;
1573
1574   switch (key){
1575        case 'q':
1576#ifdef XINETD
1577                end_service();
1578#endif
1579                exit(0);
1580                break;
1581        case '+':
1582                lic_slice_z+=0.05;
1583                lic->set_offset(lic_slice_z);
1584                break;
1585        case '-':
1586                lic_slice_z-=0.05;
1587                lic->set_offset(lic_slice_z);
1588                break;
1589        case ',':
1590                lic_slice_x+=0.05;
1591                init_particles();
1592                break;
1593        case '.':
1594                lic_slice_x-=0.05;
1595                init_particles();
1596                break;
1597        case '1':
1598                advect = true;
1599                break;
1600        case '2':
1601                psys_x+=0.05;
1602                break;
1603        case '3':
1604                psys_x-=0.05;
1605                break;
1606        case 'w': //zoom out
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 's': //zoom in
1612                live_obj_z+=0.05;
1613                log = true;
1614                cam->move(live_obj_x, live_obj_y, live_obj_z);
1615                break;
1616        case 'a': //left
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 'd': //right
1622                live_obj_x+=0.05;
1623                log = true;
1624                cam->move(live_obj_x, live_obj_y, live_obj_z);
1625                break;
1626        case 'i':
1627                init_particles();
1628                break;
1629        case 'o':
1630                live_specular+=1;
1631                fprintf(stderr, "specular: %f\n", live_specular);
1632                vol_render->set_specular(live_specular);
1633                break;
1634        case 'p':
1635                live_specular-=1;
1636                fprintf(stderr, "specular: %f\n", live_specular);
1637                vol_render->set_specular(live_specular);
1638                break;
1639        case '[':
1640                live_diffuse+=0.5;
1641                vol_render->set_diffuse(live_diffuse);
1642                break;
1643        case ']':
1644                live_diffuse-=0.5;
1645                vol_render->set_diffuse(live_diffuse);
1646                break;
1647        case 'v':
1648                vol_render->switch_volume_mode();
1649                break;
1650        case 'b':
1651                vol_render->switch_slice_mode();
1652                break;
1653
1654        default:
1655                break;
1656    }   
1657
1658#ifdef EVENTLOG
1659   if(log){
1660     float param[3] = {live_obj_x, live_obj_y, live_obj_z};
1661     Event* tmp = new Event(EVENT_MOVE, param, get_time_interval());
1662     tmp->write(event_log);
1663     delete tmp;
1664   }
1665#endif
1666}
1667
1668void motion(int x, int y){
1669
1670    int old_x, old_y;   
1671
1672    if(left_down){
1673      old_x = left_last_x;
1674      old_y = left_last_y;   
1675    }
1676    else if(right_down){
1677      old_x = right_last_x;
1678      old_y = right_last_y;   
1679    }
1680
1681    int delta_x = x - old_x;
1682    int delta_y = y - old_y;
1683
1684    //more coarse event handling
1685    //if(abs(delta_x)<10 && abs(delta_y)<10)
1686      //return;
1687
1688    if(left_down){
1689      left_last_x = x;
1690      left_last_y = y;
1691
1692      update_rot(-delta_y, -delta_x);
1693    }
1694    else if (right_down){
1695      //fprintf(stderr, "right mouse motion (%d,%d)\n", x, y);
1696
1697      right_last_x = x;
1698      right_last_y = y;
1699
1700      update_trans(0, 0, delta_x);
1701    }
1702
1703#ifdef EVENTLOG
1704    float param[3] = {live_rot_x, live_rot_y, live_rot_z};
1705    Event* tmp = new Event(EVENT_ROTATE, param, get_time_interval());
1706    tmp->write(event_log);
1707    delete tmp;
1708#endif
1709
1710    glutPostRedisplay();
1711}
1712
1713#ifdef XINETD
1714void init_service(){
1715  //open log and map stderr to log file
1716  xinetd_log = fopen("log.txt", "w");
1717  close(2);
1718  dup2(fileno(xinetd_log), 2);
1719  dup2(2,1);
1720
1721  //flush junk
1722  fflush(stdout);
1723  fflush(stderr);
1724}
1725
1726void end_service(){
1727  //close log file
1728  fclose(xinetd_log);
1729}
1730#endif
1731
1732void init_event_log(){
1733  event_log = fopen("event.txt", "w");
1734  assert(event_log!=0);
1735
1736  struct timeval time;
1737  gettimeofday(&time, NULL);
1738  cur_time = time.tv_sec*1000. + time.tv_usec/1000.;
1739}
1740
1741void end_event_log(){
1742  fclose(event_log);
1743}
1744
1745double get_time_interval(){
1746  struct timeval time;
1747  gettimeofday(&time, NULL);
1748  double new_time = time.tv_sec*1000. + time.tv_usec/1000.;
1749
1750  double interval = new_time - cur_time;
1751  cur_time = new_time;
1752  return interval;
1753}
1754
1755
1756/*----------------------------------------------------*/
1757int main(int argc, char** argv)
1758{
1759#ifdef XINETD
1760   init_service();
1761#endif
1762
1763   glutInit(&argc, argv);
1764   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
1765
1766   MainTransferFunctionWindow * tf_window;
1767   tf_window = new MainTransferFunctionWindow();
1768   tf_window->mainInit();
1769   
1770   glutInitWindowSize(NPIX, NPIX);
1771   glutInitWindowPosition(10, 10);
1772   render_window = glutCreateWindow(argv[0]);
1773
1774   glutDisplayFunc(display);
1775   glutMouseFunc(mouse);
1776   glutMotionFunc(motion);
1777   glutKeyboardFunc(keyboard);
1778   glutIdleFunc(idle);
1779
1780   initGL();
1781   initTcl();
1782
1783#ifdef EVENTLOG
1784   init_event_log();
1785#endif
1786   //event loop
1787   glutMainLoop();
1788#ifdef EVENTLOG
1789   end_event_log();
1790#endif
1791
1792#ifdef XINETD
1793   end_service();
1794#endif
1795
1796   return 0;
1797}
Note: See TracBrowser for help on using the repository browser.