source: trunk/packages/vizservers/nanovis/nanovis.cpp @ 1380

Last change on this file since 1380 was 1380, checked in by gah, 13 years ago
File size: 65.4 KB
Line 
1
2/*
3 * ----------------------------------------------------------------------
4 * Nanovis: Visualization of Nanoelectronics Data
5 *
6 * ======================================================================
7 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
8 *           Michael McLennan <mmclennan@purdue.edu>
9 *           Purdue Rendering and Perceptualization Lab (PURPL)
10 *
11 *  Copyright (c) 2004-2006  Purdue Research Foundation
12 *
13 *  See the file "license.terms" for information on usage and
14 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 * ======================================================================
16 */
17
18#include <assert.h>
19#include <fcntl.h>
20#include <fstream>
21#include <getopt.h>
22#include <iostream>
23#include <math.h>
24#include <memory.h>
25#include <signal.h>
26#include <sstream>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string>
30#include <sys/resource.h>
31#include <sys/time.h>
32#include <sys/times.h>
33#include <sys/types.h>
34#include <time.h>
35#include <unistd.h>
36
37#include "Nv.h"
38#include "PointSetRenderer.h"
39#include "PointSet.h"
40#include "Util.h"
41#include <NvLIC.h>
42#include <Trace.h>
43
44#include "nanovis.h"
45#include "define.h"
46#include "RpField1D.h"
47#include "RpFieldRect3D.h"
48#include "RpFieldPrism3D.h"
49#include "RpEncode.h"
50
51#include "ZincBlendeVolume.h"
52#include "NvLoadFile.h"
53#include "NvColorTableRenderer.h"
54#include "NvEventLog.h"
55#include "NvZincBlendeReconstructor.h"
56#include "NvFlowVisRenderer.h"
57#include "HeightMap.h"
58#include "Grid.h"
59#include "VolumeInterpolator.h"
60#include <RenderContext.h>
61
62#include <BMPImageLoaderImpl.h>
63#include <ImageLoaderFactory.h>
64
65//#define  _LOCAL_ZINC_TEST_
66
67// R2 headers
68#include <R2/R2FilePath.h>
69#include <R2/R2Fonts.h>
70
71#define SIZEOF_BMP_HEADER   54
72
73extern void NvInitCG(); // in Shader.cpp
74extern bool load_vector_stream2(Rappture::Outcome &result, int index,
75        std::istream& fin);
76
77// Indicates "up" axis:  x=1, y=2, z=3, -x=-1, -y=-2, -z=-3
78enum AxisDirections {
79    X_POS = 1, Y_POS = 2, Z_POS = 3, X_NEG = -1, Y_NEG = -2, Z_NEG = -3
80};
81
82#define KEEPSTATS       1
83
84#define CVT2SECS(x)  ((double)(x).tv_sec) + ((double)(x).tv_usec * 1.0e-6)
85
86#define TRUE    1
87#define FALSE   0
88
89typedef struct {
90    pid_t pid;
91    size_t nFrames;             /* # of frames sent to client. */
92    size_t nBytes;              /* # of bytes for all frames. */
93    size_t nCommands;           /* # of commands executed */
94    double cmdTime;             /* Elasped time spend executing commands. */
95    struct timeval start;       /* Start of elapsed time. */
96} Stats;
97
98static Stats stats;
99
100// STATIC MEMBER DATA
101Grid *NanoVis::grid = NULL;
102int NanoVis::updir = Y_POS;
103NvCamera* NanoVis::cam = NULL;
104int NanoVis::n_volumes = 0;
105vector<Volume*> NanoVis::volume;
106vector<HeightMap*> NanoVis::heightMap;
107VolumeRenderer* NanoVis::vol_renderer = 0;
108PointSetRenderer* NanoVis::pointset_renderer = 0;
109vector<PointSet*> NanoVis::pointSet;
110PlaneRenderer* NanoVis::plane_render = 0;
111Texture2D* NanoVis::plane[10];
112NvColorTableRenderer* NanoVis::color_table_renderer = 0;
113
114#ifndef NEW_FLOW_ENGINE
115NvParticleRenderer* NanoVis::flowVisRenderer = 0;
116#else
117NvFlowVisRenderer* NanoVis::flowVisRenderer = 0;
118#endif
119
120graphics::RenderContext* NanoVis::renderContext = 0;
121NvLIC* NanoVis::licRenderer = 0;
122R2Fonts* NanoVis::fonts;
123
124FILE *NanoVis::stdin = NULL;
125FILE *NanoVis::logfile = NULL;
126FILE *NanoVis::recfile = NULL;
127
128bool NanoVis::lic_on = false;
129bool NanoVis::particle_on = false;
130bool NanoVis::vector_on = false;
131bool NanoVis::axis_on = true;
132bool NanoVis::config_pending = false;
133bool NanoVis::debug_flag = false;
134bool NanoVis::lic_slice_x_visible = false;
135bool NanoVis::lic_slice_y_visible = false;
136bool NanoVis::lic_slice_z_visible = false;
137
138Tcl_Interp *NanoVis::interp;
139Tcl_DString NanoVis::cmdbuffer;
140
141//frame buffer for final rendering
142NVISid NanoVis::final_color_tex = 0;
143NVISid NanoVis::final_depth_rb = 0;
144NVISid NanoVis::final_fbo = 0;
145int NanoVis::render_window = 0;       /* GLUT handle for the render window */
146int NanoVis::win_width = NPIX;        /* Width of the render window */
147int NanoVis::win_height = NPIX;       /* Height of the render window */
148
149unsigned char* NanoVis::screen_buffer = NULL;
150
151/* FIXME: This variable is always true. */
152bool volume_mode = true;
153
154// in Command.cpp
155extern Tcl_Interp *initTcl();
156
157// in dxReader.cpp
158extern void load_vector_stream(int index, std::istream& fin);
159
160float vert[NMESH*NMESH*3];              //particle positions in main memory
161float slice_vector[NMESH*NMESH*4];      //per slice vectors in main memory
162
163// maps transfunc name to TransferFunction object
164static Tcl_HashTable tftable;
165
166// pointers to 2D planes, currently handle up 10
167
168
169PerfQuery* perf;                        //perfromance counter
170
171CGprogram m_passthru_fprog;
172CGparameter m_passthru_scale_param, m_passthru_bias_param;
173
174// Variables for mouse events
175
176// Default camera rotation angles.
177const float def_rot_x = 90.0f;
178const float def_rot_y = 180.0f;
179const float def_rot_z = -135.0f;
180
181// Default camera target.
182const float def_target_x = 0.0f;
183const float def_target_y = 0.0f;
184const float def_target_z = 100.0f;
185
186// Default camera location.
187const float def_eye_x = -0.0f;
188const float def_eye_y = -0.0f;
189const float def_eye_z = -2.5f;
190
191
192#ifndef XINETD
193// Last locations mouse events
194static int left_last_x;
195static int left_last_y;
196static int right_last_x;
197static int right_last_y;
198static bool left_down = false;
199static bool right_down = false;
200#endif /*XINETD*/
201
202// Image based flow visualization slice location
203// FLOW
204float NanoVis::lic_slice_x = 0.5f;
205float NanoVis::lic_slice_y = 0.5f;
206float NanoVis::lic_slice_z = 0.5f;
207int NanoVis::lic_axis = 2; // z axis
208
209using namespace std;
210
211#define RM_VOLUME 1
212#define RM_POINT 2
213
214int renderMode = RM_VOLUME;
215
216/*
217 * ----------------------------------------------------------------------
218 * USAGE: debug("string", ...)
219 *
220 * Use this anywhere within the package to send a debug message
221 * back to the client.  The string can have % fields as used by
222 * the printf() package.  Any remaining arguments are treated as
223 * field substitutions on that.
224 * ----------------------------------------------------------------------
225 */
226void
227debug(char *str)
228{
229    ssize_t nWritten;
230
231    nWritten = write(0, str, strlen(str));
232}
233
234void
235debug(char *str, double v1)
236{
237    char buffer[512];
238    sprintf(buffer, str, v1);
239    debug(buffer);
240}
241
242void
243debug(char *str, double v1, double v2)
244{
245    char buffer[512];
246    sprintf(buffer, str, v1, v2);
247    debug(buffer);
248}
249
250void
251debug(char *str, double v1, double v2, double v3)
252{
253    char buffer[512];
254    sprintf(buffer, str, v1, v2, v3);
255    debug(buffer);
256}
257
258void removeAllData()
259{
260    //
261}
262
263
264#if KEEPSTATS
265
266static int
267WriteStats(const char *who, int code)
268{
269    double start, finish;
270    pid_t pid;
271    char buf[BUFSIZ];
272    Tcl_DString ds;
273
274    {
275        struct timeval tv;
276
277        /* Get ending time.  */
278        gettimeofday(&tv, NULL);
279        finish = CVT2SECS(tv);
280        tv = stats.start;
281        start = CVT2SECS(tv);
282    }
283    pid = getpid();
284    Tcl_DStringInit(&ds);
285
286    sprintf(buf, "<session server=\"%s\" ", who);
287    Tcl_DStringAppend(&ds, buf, -1);
288
289    gethostname(buf, BUFSIZ-1);
290    buf[BUFSIZ-1] = '\0';
291    Tcl_DStringAppend(&ds, "host=\"", -1);
292    Tcl_DStringAppend(&ds, buf, -1);
293    Tcl_DStringAppend(&ds, "\" ", -1);
294
295    strcpy(buf, ctime(&stats.start.tv_sec));
296    buf[strlen(buf) - 1] = '\0';
297    Tcl_DStringAppend(&ds, "date=\"", -1);
298    Tcl_DStringAppend(&ds, buf, -1);
299    Tcl_DStringAppend(&ds, "\" ", -1);
300
301    sprintf(buf, "date_secs=\"%ld\" ", stats.start.tv_sec);
302    Tcl_DStringAppend(&ds, buf, -1);
303
304    sprintf(buf, "pid=\"%d\" ", pid);
305    Tcl_DStringAppend(&ds, buf, -1);
306    sprintf(buf, "num_frames=\"%lu\" ", (unsigned long int)stats.nFrames);
307    Tcl_DStringAppend(&ds, buf, -1);
308    sprintf(buf, "frame_bytes=\"%lu\" ", (unsigned long int)stats.nBytes);
309    Tcl_DStringAppend(&ds, buf, -1);
310    sprintf(buf, "num_commands=\"%lu\" ", (unsigned long int)stats.nCommands);
311    Tcl_DStringAppend(&ds, buf, -1);
312    sprintf(buf, "cmd_time=\"%g\" ", stats.cmdTime);
313    Tcl_DStringAppend(&ds, buf, -1);
314    sprintf(buf, "session_time=\"%g\" ", finish - start);
315    Tcl_DStringAppend(&ds, buf, -1);
316    sprintf(buf, "status=\"%d\" ", code);
317    Tcl_DStringAppend(&ds, buf, -1);
318    {
319        long clocksPerSec = sysconf(_SC_CLK_TCK);
320        double clockRes = 1.0 / clocksPerSec;
321        struct tms tms;
322
323        memset(&tms, 0, sizeof(tms));
324        times(&tms);
325        sprintf(buf, "utime=\"%g\" ", tms.tms_utime * clockRes);
326        Tcl_DStringAppend(&ds, buf, -1);
327        sprintf(buf, "stime=\"%g\" ", tms.tms_stime * clockRes);
328        Tcl_DStringAppend(&ds, buf, -1);
329        sprintf(buf, "cutime=\"%g\" ", tms.tms_cutime * clockRes);
330        Tcl_DStringAppend(&ds, buf, -1);
331        sprintf(buf, "cstime=\"%g\" ", tms.tms_cstime * clockRes);
332        Tcl_DStringAppend(&ds, buf, -1);
333    }
334    Tcl_DStringAppend(&ds, "/>\n", -1);
335
336    {
337        int f;
338        ssize_t length;
339        int result;
340
341#define STATSDIR        "/var/tmp/visservers"
342#define STATSFILE       STATSDIR "/" "data.xml"
343        if (access(STATSDIR, X_OK) != 0) {
344            mkdir(STATSDIR, 0770);
345        }
346        length = Tcl_DStringLength(&ds);
347        f = open(STATSFILE, O_APPEND | O_CREAT | O_WRONLY, 0600);
348        result = FALSE;
349        if (f < 0) {
350            goto error;
351        }
352        if (write(f, Tcl_DStringValue(&ds), length) != length) {
353            goto error;
354        }
355        result = TRUE;
356    error:
357        if (f >= 0) {
358            close(f);
359        }
360        Tcl_DStringFree(&ds);
361        return result;
362    }
363}
364#endif
365
366static void
367DoExit(int code)
368{
369    if (NanoVis::debug_flag) {
370        fprintf(stderr, "in DoExit\n");
371    }
372    removeAllData();
373    NvExit();
374#if KEEPSTATS
375    WriteStats("nanovis", code);
376#endif
377    exit(code);
378}
379
380//report errors related to CG shaders
381void
382cgErrorCallback(void)
383{
384    CGerror lastError = cgGetError();
385    if(lastError) {
386        const char *listing = cgGetLastListing(g_context);
387        Trace("\n---------------------------------------------------\n");
388        Trace("%s\n\n", cgGetErrorString(lastError));
389        Trace("%s\n", listing);
390        Trace("-----------------------------------------------------\n");
391        Trace("Cg error, exiting...\n");
392        cgDestroyContext(g_context);
393        DoExit(-1);
394    }
395}
396
397
398CGprogram
399LoadCgSourceProgram(CGcontext context, const char *fileName, CGprofile profile,
400                    const char *entryPoint)
401{
402    const char *path = R2FilePath::getInstance()->getPath(fileName);
403    if (path == NULL) {
404        fprintf(stderr, "can't find program \"%s\"\n", fileName);
405        assert(path != NULL);
406    }
407    printf("cg program compiling: %s\n", path);
408    fflush(stdout);
409    CGprogram program;
410    program = cgCreateProgramFromFile(context, CG_SOURCE, path, profile,
411                                      entryPoint, NULL);
412    cgGLLoadProgram(program);
413
414    CGerror LastError = cgGetError();
415    if (LastError)
416        {
417            printf("Error message: %s\n", cgGetLastListing(context));
418        }
419
420    delete [] path;
421
422    return program;
423}
424
425static int
426ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr)
427{
428    struct timeval tv;
429    double start, finish;
430    int result;
431
432    if (NanoVis::debug_flag) {
433        fprintf(stderr, "in ExecuteCommand(%s)\n", Tcl_DStringValue(dsPtr));
434    }
435
436    gettimeofday(&tv, NULL);
437    start = CVT2SECS(tv);
438
439    if (NanoVis::logfile != NULL) {
440        fprintf(NanoVis::logfile, "%s", Tcl_DStringValue(dsPtr));
441        fflush(NanoVis::logfile);
442    }
443    if (NanoVis::recfile != NULL) {
444        fprintf(NanoVis::recfile, "%s", Tcl_DStringValue(dsPtr));
445        fflush(NanoVis::recfile);
446    }
447    result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr));
448    Tcl_DStringSetLength(dsPtr, 0);
449
450    gettimeofday(&tv, NULL);
451    finish = CVT2SECS(tv);
452
453    stats.cmdTime += finish - start;
454    stats.nCommands++;
455    if (NanoVis::debug_flag) {
456        fprintf(stderr, "leaving ExecuteCommand status=%d\n", result);
457    }
458    return result;
459}
460
461void
462NanoVis::pan(float dx, float dy)
463{
464    /* Move the camera and its target by equal amounts along the x and y
465     * axes. */
466    fprintf(stderr, "x=%f, y=%f\n", dx, dy);
467
468    cam->x(def_eye_x + dx);
469    cam->y(def_eye_y + dy);
470    fprintf(stderr, "set eye to %f %f\n", cam->x(), cam->y());
471
472    cam->xAim(def_target_x + dx);
473    cam->yAim(def_target_y + dy);
474    fprintf(stderr, "set aim to %f %f\n", cam->xAim(), cam->yAim());
475}
476
477
478/* Load a 3D volume
479 * index:       the index into the volume array, which stores pointers
480 *              to 3D volume instances
481 * data:        pointer to an array of floats.
482 * n_component: the number of scalars for each space point. All component
483 *              scalars for a point are placed consequtively in data array
484 *              width, height and depth: number of points in each dimension
485 */
486Volume *
487NanoVis::load_volume(int index, int width, int height, int depth,
488                     int n_component, float* data, double vmin,
489                     double vmax, double nzero_min)
490{
491    while (n_volumes <= index) {
492        volume.push_back(NULL);
493        n_volumes++;
494    }
495
496    Volume* vol = volume[index];
497    if (vol != NULL) {
498        volume[index] = NULL;
499
500        if (vol->pointsetIndex != -1) {
501            if (((unsigned  int) vol->pointsetIndex) < pointSet.size() &&
502                pointSet[vol->pointsetIndex] != NULL) {
503                delete pointSet[vol->pointsetIndex];
504                pointSet[vol->pointsetIndex] = 0;
505            }
506        }
507        delete vol;
508    }
509    volume[index] = new Volume(0.f, 0.f, 0.f, width, height, depth, 1.,
510                               n_component, data, vmin, vmax, nzero_min);
511    return volume[index];
512}
513
514// Gets a colormap 1D texture by name.
515TransferFunction*
516NanoVis::get_transfunc(const char *name)
517{
518    Tcl_HashEntry *hPtr;
519
520    hPtr = Tcl_FindHashEntry(&tftable, name);
521    if (hPtr == NULL) {
522        return NULL;
523    }
524    return (TransferFunction*)Tcl_GetHashValue(hPtr);
525}
526
527// Creates of updates a colormap 1D texture by name.
528TransferFunction*
529NanoVis::DefineTransferFunction(const char *name, size_t n, float *data)
530{
531    int isNew;
532    Tcl_HashEntry *hPtr;
533    TransferFunction *tf;
534
535    hPtr = Tcl_CreateHashEntry(&tftable, name, &isNew);
536    if (isNew) {
537        tf = new TransferFunction(n, data);
538        Tcl_SetHashValue(hPtr, (ClientData)tf);
539    } else {
540        /*
541         * You can't delete the transfer function because many
542         * objects may be holding its pointer.  We must update it.
543         */
544        tf = (TransferFunction *)Tcl_GetHashValue(hPtr);
545        tf->update(n, data);
546    }
547    return tf;
548}
549
550int
551NanoVis::render_legend(TransferFunction *tf, double min, double max,
552                       int width, int height, const char* volArg)
553{
554    if (debug_flag) {
555        fprintf(stderr, "in render_legend\n");
556    }
557    int old_width = win_width;
558    int old_height = win_height;
559
560    plane_render->set_screen_size(width, height);
561    resize_offscreen_buffer(width, height);
562
563    // generate data for the legend
564    float data[512];
565    for (int i=0; i < 256; i++) {
566        data[i] = data[i+256] = (float)(i/255.0);
567    }
568    plane[0] = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
569    int index = plane_render->add_plane(plane[0], tf);
570    plane_render->set_active_plane(index);
571
572    offscreen_buffer_capture();
573    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
574    plane_render->render();
575
576    // INSOO
577    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
578    //glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, screen_buffer); // INSOO's
579
580    if (debug_flag) {
581        fprintf(stderr, "ppm legend image not written (debug mode)\n");
582    } else {
583        char prefix[200];
584        ssize_t nWritten;
585
586        sprintf(prefix, "nv>legend %s %g %g", volArg, min, max);
587        ppm_write(prefix);
588        nWritten = write(0, "\n", 1);
589        assert(nWritten == 1);
590    }
591    plane_render->remove_plane(index);
592    resize_offscreen_buffer(old_width, old_height);
593
594    if (debug_flag) {
595        fprintf(stderr, "leaving render_legend\n");
596    }
597    return TCL_OK;
598}
599
600//initialize frame buffer objects for offscreen rendering
601void
602NanoVis::init_offscreen_buffer()
603{
604    if (debug_flag) {
605        fprintf(stderr, "in init_offscreen_buffer\n");
606    }
607    // Initialize a fbo for final display.
608    glGenFramebuffersEXT(1, &final_fbo);
609   
610    glGenTextures(1, &final_color_tex);
611    glBindTexture(GL_TEXTURE_2D, final_color_tex);
612   
613    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
614    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
615#ifdef NV40
616    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, win_width, win_height, 0,
617                 GL_RGB, GL_INT, NULL);
618#else
619    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0,
620                 GL_RGB, GL_INT, NULL);
621#endif
622    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
623    glGenRenderbuffersEXT(1, &final_depth_rb);
624    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb);
625    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24,
626                             win_width, win_height);
627    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
628                              GL_TEXTURE_2D, final_color_tex, 0);
629    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
630                                 GL_RENDERBUFFER_EXT, final_depth_rb);
631
632    GLenum status;
633    if (!CheckFBO(&status)) {
634        PrintFBOStatus(status, "final_fbo");
635        DoExit(3);
636    }
637
638    // Check framebuffer completeness at the end of initialization.
639    //CHECK_FRAMEBUFFER_STATUS();
640   
641    //assert(glGetError()==0);
642    if (debug_flag) {
643        fprintf(stderr, "leaving init_offscreen_buffer\n");
644    }
645}
646
647
648//resize the offscreen buffer
649void
650NanoVis::resize_offscreen_buffer(int w, int h)
651{
652    if ((w == win_width) && (h == win_height)) {
653        return;
654    }
655    if (debug_flag) {
656        fprintf(stderr, "in resize_offscreen_buffer(%d, %d)\n", w, h);
657    }
658
659    win_width = w;
660    win_height = h;
661   
662    if (fonts) {
663        fonts->resize(w, h);
664    }
665    //fprintf(stderr, "screen_buffer size: %d\n", sizeof(screen_buffer));
666    if (debug_flag) {
667        fprintf(stderr, "screen_buffer size: %d %d\n", w, h);
668    }
669   
670    if (screen_buffer) {
671        delete[] screen_buffer;
672        screen_buffer = NULL;
673    }
674   
675    screen_buffer = new unsigned char[4*win_width*win_height];
676    assert(screen_buffer != NULL);
677   
678    //delete the current render buffer resources
679    glDeleteTextures(1, &final_color_tex);
680    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb);
681    glDeleteRenderbuffersEXT(1, &final_depth_rb);
682
683    if (debug_flag) {
684        fprintf(stderr, "before deleteframebuffers\n");
685    }
686    glDeleteFramebuffersEXT(1, &final_fbo);
687
688    if (debug_flag) {
689        fprintf(stderr, "reinitialize FBO\n");
690    }
691    //Reinitialize final fbo for final display
692    glGenFramebuffersEXT(1, &final_fbo);
693
694    glGenTextures(1, &final_color_tex);
695    glBindTexture(GL_TEXTURE_2D, final_color_tex);
696
697    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
698    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
699#ifdef NV40
700    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, win_width, win_height, 0,
701                 GL_RGB, GL_INT, NULL);
702#else
703    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0,
704                 GL_RGB, GL_INT, NULL);
705#endif
706    if (debug_flag) {
707        fprintf(stderr, "before bindframebuffer\n");
708    }
709    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo);
710    if (debug_flag) {
711        fprintf(stderr, "after bindframebuffer\n");
712    }
713    glGenRenderbuffersEXT(1, &final_depth_rb);
714    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb);
715    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24,
716                             win_width, win_height);
717    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
718                              GL_TEXTURE_2D, final_color_tex, 0);
719    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
720                                 GL_RENDERBUFFER_EXT, final_depth_rb);
721   
722    GLenum status;
723    if (!CheckFBO(&status)) {
724        PrintFBOStatus(status, "final_fbo");
725        DoExit(3);
726    }
727
728    //CHECK_FRAMEBUFFER_STATUS();
729    if (debug_flag) {
730        fprintf(stderr, "change camera\n");
731    }
732    //change the camera setting
733    cam->set_screen_size(0, 0, win_width, win_height);
734    plane_render->set_screen_size(win_width, win_height);
735
736    if (debug_flag) {
737        fprintf(stderr, "leaving resize_offscreen_buffer(%d, %d)\n", w, h);
738    }
739}
740
741/*
742 * FIXME: This routine is fairly expensive (60000 floating pt divides).
743 *      I've put an ifdef around the call to it so that the released
744 *      builds don't include it.  Define PROTOTYPE to 1 in config.h
745 *      to turn it back on.
746 */
747void
748make_test_2D_data()
749{
750    int w = 300;
751    int h = 200;
752    float* data = new float[w*h];
753
754    //procedurally make a gradient plane
755    for(int j=0; j<h; j++){
756        for(int i=0; i<w; i++){
757            data[w*j+i] = float(i)/float(w);
758        }
759    }
760    NanoVis::plane[0] = new Texture2D(w, h, GL_FLOAT, GL_LINEAR, 1, data);
761    delete[] data;
762}
763
764void NanoVis::initParticle()
765{
766    flowVisRenderer->initialize();
767    licRenderer->make_patterns();
768}
769
770void CgErrorCallback(void)
771{
772    CGerror lastError = cgGetError();
773
774    if(lastError) {
775        const char *listing = cgGetLastListing(g_context);
776        printf("\n---------------------------------------------------\n");
777        printf("%s\n\n", cgGetErrorString(lastError));
778        printf("%s\n", listing);
779        printf("-----------------------------------------------------\n");
780        printf("Cg error, exiting...\n");
781        cgDestroyContext(g_context);
782        fflush(stdout);
783        DoExit(-1);
784    }
785}
786
787void NanoVis::init(const char* path)
788{
789    // print system information
790    fprintf(stderr,
791            "-----------------------------------------------------------\n");
792    fprintf(stderr, "OpenGL driver: %s %s\n", glGetString(GL_VENDOR),
793            glGetString(GL_VERSION));
794    fprintf(stderr, "Graphics hardware: %s\n", glGetString(GL_RENDERER));
795    fprintf(stderr,
796            "-----------------------------------------------------------\n");
797    if (path == NULL) {
798        fprintf(stderr, "No path defined for shaders or resources\n");
799        fflush(stderr);
800        DoExit(1);
801    }
802    GLenum err = glewInit();
803    if (GLEW_OK != err) {
804        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
805        getchar();
806        //assert(false);
807    }
808    fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
809
810    if (!R2FilePath::getInstance()->setPath(path)) {
811        fprintf(stderr, "can't set file path to %s\n", path);
812        fflush(stderr);
813        DoExit(1);
814    }
815   
816    NvInitCG();
817    NvShader::setErrorCallback(CgErrorCallback);
818   
819    fonts = new R2Fonts();
820    fonts->addFont("verdana", "verdana.fnt");
821    fonts->setFont("verdana");
822   
823    color_table_renderer = new NvColorTableRenderer();
824    color_table_renderer->setFonts(fonts);
825#ifndef NEW_FLOW_ENGINE
826    flowVisRenderer = new NvParticleRenderer(NMESH, NMESH, g_context);
827#else
828    flowVisRenderer = new NvFlowVisRenderer(NMESH, NMESH, g_context);
829#endif
830
831
832#if PROTOTYPE
833    licRenderer = new NvLIC(NMESH, NPIX, NPIX, lic_axis, Vector3(lic_slice_x, lic_slice_y, lic_slice_z), g_context);
834#endif
835
836    ImageLoaderFactory::getInstance()->addLoaderImpl("bmp", new BMPImageLoaderImpl());
837    grid = new Grid();
838    grid->setFont(fonts);
839
840    pointset_renderer = new PointSetRenderer();
841}
842
843/*----------------------------------------------------*/
844void
845NanoVis::initGL(void)
846{
847    if (debug_flag) {
848        fprintf(stderr, "in initGL\n");
849    }
850    //buffer to store data read from the screen
851    if (screen_buffer) {
852        delete[] screen_buffer;
853        screen_buffer = NULL;
854    }
855    screen_buffer = new unsigned char[4*win_width*win_height];
856    assert(screen_buffer != NULL);
857
858    //create the camera with default setting
859    cam = new NvCamera(0, 0, win_width, win_height,
860                       def_eye_x, def_eye_y, def_eye_z,          /* location. */
861                       def_target_x, def_target_y, def_target_z, /* target. */
862                       def_rot_x, def_rot_y, def_rot_z);         /* angle. */
863
864    glEnable(GL_TEXTURE_2D);
865    glShadeModel(GL_FLAT);
866    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
867
868    glClearColor(0,0,0,1);
869    //glClearColor(0.7,0.7,0.7,1);
870    glClear(GL_COLOR_BUFFER_BIT);
871
872    //initialize lighting
873    GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
874    GLfloat mat_shininess[] = {30.0};
875    GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
876    GLfloat green_light[] = {0.1, 0.5, 0.1, 1.0};
877
878    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
879    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
880    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
881    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
882    glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light);
883    glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
884
885    // init table of transfer functions
886    Tcl_InitHashTable(&tftable, TCL_STRING_KEYS);
887
888    //check if performance query is supported
889    if(check_query_support()){
890        //create queries to count number of rendered pixels
891        perf = new PerfQuery();
892    }
893
894    init_offscreen_buffer();    //frame buffer object for offscreen rendering
895
896    //create volume renderer and add volumes to it
897    vol_renderer = new VolumeRenderer();
898
899    // create
900    renderContext = new graphics::RenderContext();
901   
902    //create an 2D plane renderer
903    plane_render = new PlaneRenderer(g_context, win_width, win_height);
904#if PROTOTYPE
905    make_test_2D_data();
906#endif  /* PROTOTYPE */
907    plane_render->add_plane(plane[0], get_transfunc("default"));
908
909    //assert(glGetError()==0);
910
911    if (debug_flag) {
912        fprintf(stderr, "leaving initGL\n");
913    }
914}
915
916#if DO_RLE
917char rle[512*512*3];
918int rle_size;
919
920short offsets[512*512*3];
921int offsets_size;
922
923void
924do_rle()
925{
926    int len = NanoVis::win_width*NanoVis::win_height*3;
927    rle_size = 0;
928    offsets_size = 0;
929
930    int i=0;
931    while(i<len){
932        if (NanoVis::screen_buffer[i] == 0) {
933            int pos = i+1;
934            while ( (pos<len) && (NanoVis::screen_buffer[pos] == 0)) {
935                pos++;
936            }
937            offsets[offsets_size++] = -(pos - i);
938            i = pos;
939        }
940
941        else {
942            int pos;
943            for (pos = i; (pos<len) && (NanoVis::screen_buffer[pos] != 0);pos++){
944                rle[rle_size++] = NanoVis::screen_buffer[pos];
945            }
946            offsets[offsets_size++] = (pos - i);
947            i = pos;
948        }
949
950    }
951}
952#endif
953
954// used internally to build up the BMP file header
955// Writes an integer value into the header data structure at pos
956static inline void
957bmp_header_add_int(unsigned char* header, int& pos, int data)
958{
959#ifdef WORDS_BIGENDIAN
960    header[pos++] = (data >> 24) & 0xFF;
961    header[pos++] = (data >> 16) & 0xFF;
962    header[pos++] = (data >> 8)  & 0xFF;
963    header[pos++] = (data)       & 0xFF;
964#else
965    header[pos++] = data & 0xff;
966    header[pos++] = (data >> 8) & 0xff;
967    header[pos++] = (data >> 16) & 0xff;
968    header[pos++] = (data >> 24) & 0xff;
969#endif
970}
971
972// INSOO
973// FOR DEBUGGING
974void
975NanoVis::bmp_write_to_file(int frame_number, const char *directory_name)
976{
977    unsigned char header[SIZEOF_BMP_HEADER];
978    int pos = 0;
979    header[pos++] = 'B';
980    header[pos++] = 'M';
981
982    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
983    // on each scan line.  If need be, we add padding to each line.
984    int pad = 0;
985    if ((3*win_width) % 4 > 0) {
986        pad = 4 - ((3*win_width) % 4);
987    }
988
989    // file size in bytes
990    int fsize = (3*win_width+pad)*win_height + SIZEOF_BMP_HEADER;
991    bmp_header_add_int(header, pos, fsize);
992
993    // reserved value (must be 0)
994    bmp_header_add_int(header, pos, 0);
995
996    // offset in bytes to start of bitmap data
997    bmp_header_add_int(header, pos, SIZEOF_BMP_HEADER);
998
999    // size of the BITMAPINFOHEADER
1000    bmp_header_add_int(header, pos, 40);
1001
1002    // width of the image in pixels
1003    bmp_header_add_int(header, pos, win_width);
1004
1005    // height of the image in pixels
1006    bmp_header_add_int(header, pos, win_height);
1007
1008    // 1 plane + (24 bits/pixel << 16)
1009    bmp_header_add_int(header, pos, 1572865);
1010
1011    // no compression
1012    // size of image for compression
1013    bmp_header_add_int(header, pos, 0);
1014    bmp_header_add_int(header, pos, 0);
1015
1016    // x pixels per meter
1017    // y pixels per meter
1018    bmp_header_add_int(header, pos, 0);
1019    bmp_header_add_int(header, pos, 0);
1020
1021    // number of colors used (0 = compute from bits/pixel)
1022    // number of important colors (0 = all colors important)
1023    bmp_header_add_int(header, pos, 0);
1024    bmp_header_add_int(header, pos, 0);
1025
1026    // BE CAREFUL: BMP format wants BGR ordering for screen data
1027    unsigned char* scr = screen_buffer;
1028    for (int row=0; row < win_height; row++) {
1029        for (int col=0; col < win_width; col++) {
1030            unsigned char tmp = scr[2];
1031            scr[2] = scr[0];  // B
1032            scr[0] = tmp;     // R
1033            scr += 3;
1034        }
1035        scr += pad;  // skip over padding already in screen data
1036    }
1037
1038    FILE* f;
1039    char filename[100];
1040    if (frame_number >= 0) {
1041        if (directory_name)
1042            sprintf(filename, "%s/image%03d.bmp", directory_name, frame_number);
1043        else
1044            sprintf(filename, "/tmp/flow_animation/image%03d.bmp", frame_number);
1045
1046        printf("Writing %s\n", filename);
1047        f = fopen(filename, "wb");
1048        if (f == 0) {
1049            Trace("cannot create file\n");
1050        }
1051    } else {
1052        f = fopen("/tmp/image.bmp", "wb");
1053        if (f == 0) {
1054            Trace("cannot create file\n");
1055        }
1056    }
1057    ssize_t nWritten;
1058    nWritten = fwrite(header, SIZEOF_BMP_HEADER, 1, f);
1059    assert(nWritten == SIZEOF_BMP_HEADER);
1060    nWritten = fwrite(screen_buffer, (3*win_width+pad)*win_height, 1, f);
1061    assert(nWritten == (3*win_width+pad)*win_height);
1062    fclose(f);
1063}
1064
1065void
1066NanoVis::bmp_write(const char *prefix)
1067{
1068    unsigned char header[SIZEOF_BMP_HEADER];
1069    ssize_t nWritten;
1070    int pos = 0;
1071
1072    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
1073    // on each scan line.  If need be, we add padding to each line.
1074    int pad = 0;
1075    if ((3*win_width) % 4 > 0) {
1076        pad = 4 - ((3*win_width) % 4);
1077    }
1078    pad = 0;
1079    int fsize = (3*win_width+pad)*win_height + sizeof(header);
1080
1081    char string[200];
1082    sprintf(string, "%s %d\n", prefix, fsize);
1083    nWritten = write(0, string, strlen(string));
1084    assert(nWritten == (ssize_t)strlen(string));
1085    header[pos++] = 'B';
1086    header[pos++] = 'M';
1087
1088    // file size in bytes
1089    bmp_header_add_int(header, pos, fsize);
1090
1091    // reserved value (must be 0)
1092    bmp_header_add_int(header, pos, 0);
1093
1094    // offset in bytes to start of bitmap data
1095    bmp_header_add_int(header, pos, SIZEOF_BMP_HEADER);
1096
1097    // size of the BITMAPINFOHEADER
1098    bmp_header_add_int(header, pos, 40);
1099
1100    // width of the image in pixels
1101    bmp_header_add_int(header, pos, win_width);
1102
1103    // height of the image in pixels
1104    bmp_header_add_int(header, pos, win_height);
1105
1106    // 1 plane + (24 bits/pixel << 16)
1107    bmp_header_add_int(header, pos, 1572865);
1108
1109    // no compression
1110    // size of image for compression
1111    bmp_header_add_int(header, pos, 0);
1112    bmp_header_add_int(header, pos, 0);
1113
1114    // x pixels per meter
1115    // y pixels per meter
1116    bmp_header_add_int(header, pos, 0);
1117    bmp_header_add_int(header, pos, 0);
1118
1119    // number of colors used (0 = compute from bits/pixel)
1120    // number of important colors (0 = all colors important)
1121    bmp_header_add_int(header, pos, 0);
1122    bmp_header_add_int(header, pos, 0);
1123
1124    // BE CAREFUL: BMP format wants BGR ordering for screen data
1125    unsigned char* scr = screen_buffer;
1126    for (int row=0; row < win_height; row++) {
1127        for (int col=0; col < win_width; col++) {
1128            unsigned char tmp = scr[2];
1129            scr[2] = scr[0];  // B
1130            scr[0] = tmp;     // R
1131            scr += 3;
1132        }
1133        scr += pad;  // skip over padding already in screen data
1134    }
1135
1136    nWritten = write(0, header, SIZEOF_BMP_HEADER);
1137    assert(nWritten == SIZEOF_BMP_HEADER);
1138    nWritten = write(0, screen_buffer, (3*win_width+pad)*win_height);
1139    assert(nWritten == (3*win_width+pad)*win_height);
1140    stats.nFrames++;
1141    stats.nBytes += (3*win_width+pad)*win_height;
1142}
1143
1144/*
1145 * ppm_write --
1146 *
1147 *  Writes the screen image as PPM binary data to the nanovisviewer
1148 *  client.  The PPM binary format is very simple.
1149 *
1150 *      P6 w h 255\n
1151 *      3-byte RGB pixel data.
1152 *
1153 *  The nanovisviewer client (using the TkImg library) will do less work
1154 *  to unpack this format, as opposed to BMP or PNG.  (This doesn't
1155 *  eliminate the need to look into DXT compression performed on the GPU).
1156 *
1157 *      Note that currently the image data from the screen is both row-padded
1158 *      and the scan lines are reversed.  This routine could be made even
1159 *      simpler (faster) if the screen buffer is an array of packed 3-bytes
1160 *      per pixels (no padding) and where the origin is the top-left corner.
1161 */
1162void
1163NanoVis::ppm_write(const char *prefix)
1164{
1165#define PPM_MAXVAL 255
1166    char header[200];
1167
1168    // Generate the PPM binary file header
1169    sprintf(header, "P6 %d %d %d\n", win_width, win_height, PPM_MAXVAL);
1170
1171    size_t header_length = strlen(header);
1172    size_t data_length = win_width * win_height * 3;
1173
1174    char command[200];
1175    sprintf(command, "%s %lu\n", prefix,
1176            (unsigned long)header_length + data_length);
1177
1178    size_t wordsPerRow = (win_width * 24 + 31) / 32;
1179    size_t bytesPerRow = wordsPerRow * 4;
1180    size_t rowLength = win_width * 3;
1181    size_t nRecs = win_height + 2;
1182
1183    struct iovec *iov;
1184    iov = (struct iovec *)malloc(sizeof(struct iovec) * nRecs);
1185
1186    // Write the nanovisviewer command, then the image header and data.
1187    // Command
1188    iov[0].iov_base = command;
1189    iov[0].iov_len = strlen(command);
1190    // Header of image data
1191    iov[1].iov_base = header;
1192    iov[1].iov_len = header_length;
1193    // Image data.
1194    int y;
1195    unsigned char *srcRowPtr = screen_buffer;
1196    for (y = win_height + 1; y >= 2; y--) {
1197        iov[y].iov_base = srcRowPtr;
1198        iov[y].iov_len = rowLength;
1199        srcRowPtr += bytesPerRow;
1200    }
1201    writev(0, iov, nRecs);
1202    free(iov);
1203    stats.nFrames++;
1204    stats.nBytes += (bytesPerRow * win_height);
1205}
1206
1207void
1208NanoVis::sendDataToClient(const char *command, const char *data, size_t dlen)
1209{
1210    /*
1211      char header[200];
1212
1213      // Generate the PPM binary file header
1214      sprintf(header, "P6 %d %d %d\n", win_width, win_height, PPM_MAXVAL);
1215
1216      size_t header_length = strlen(header);
1217      size_t data_length = win_width * win_height * 3;
1218
1219      char command[200];
1220      sprintf(command, "%s %lu\n", prefix,
1221      (unsigned long)header_length + data_length);
1222    */
1223
1224    //    size_t wordsPerRow = (win_width * 24 + 31) / 32;
1225    //    size_t bytesPerRow = wordsPerRow * 4;
1226    //    size_t rowLength = win_width * 3;
1227    size_t nRecs = 2;
1228
1229    struct iovec *iov;
1230    iov = (struct iovec *)malloc(sizeof(struct iovec) * nRecs);
1231
1232    // Write the nanovisviewer command, then the image header and data.
1233    // Command
1234    // FIXME: shouldn't have to cast this
1235    iov[0].iov_base = (char *)command;
1236    iov[0].iov_len = strlen(command);
1237    // Data
1238    // FIXME: shouldn't have to cast this
1239    iov[1].iov_base = (char *)data;
1240    iov[1].iov_len = dlen;
1241    writev(0, iov, nRecs);
1242    free(iov);
1243    // stats.nFrames++;
1244    // stats.nBytes += (bytesPerRow * win_height);
1245}
1246
1247
1248/*----------------------------------------------------*/
1249void
1250NanoVis::idle()
1251{
1252    if (debug_flag) {
1253        fprintf(stderr, "in idle()\n");
1254    }
1255    glutSetWindow(render_window);
1256
1257#ifdef XINETD
1258    xinetd_listen();
1259#else
1260    glutPostRedisplay();
1261#endif
1262    if (debug_flag) {
1263        fprintf(stderr, "leaving idle()\n");
1264    }
1265}
1266
1267void
1268NanoVis::display_offscreen_buffer()
1269{
1270    if (debug_flag) {
1271        fprintf(stderr, "in display_offscreen_buffer\n");
1272    }
1273    glEnable(GL_TEXTURE_2D);
1274    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1275    glBindTexture(GL_TEXTURE_2D, final_color_tex);
1276
1277    glViewport(0, 0, win_width, win_height);
1278    glMatrixMode(GL_PROJECTION);
1279    glLoadIdentity();
1280    gluOrtho2D(0, win_width, 0, win_height);
1281    glMatrixMode(GL_MODELVIEW);
1282    glLoadIdentity();
1283
1284    glColor3f(1.,1.,1.);                //MUST HAVE THIS LINE!!!
1285    glBegin(GL_QUADS);
1286    {
1287        glTexCoord2f(0, 0); glVertex2f(0, 0);
1288        glTexCoord2f(1, 0); glVertex2f(win_width, 0);
1289        glTexCoord2f(1, 1); glVertex2f(win_width, win_height);
1290        glTexCoord2f(0, 1); glVertex2f(0, win_height);
1291    }
1292    glEnd();
1293    if (debug_flag) {
1294        fprintf(stderr, "leaving display_offscreen_buffer\n");
1295    }
1296}
1297
1298
1299
1300#if 0
1301//oddeven sort on GPU
1302void
1303sortstep()
1304{
1305    // perform one step of the current sorting algorithm
1306
1307#ifdef notdef
1308    // swap buffers
1309    int sourceBuffer = targetBuffer;
1310    targetBuffer = (targetBuffer+1)%2;
1311    int pstage = (1<<stage);
1312    int ppass  = (1<<pass);
1313    int activeBitonicShader = 0;
1314
1315#ifdef _WIN32
1316    buffer->BindBuffer(wglTargets[sourceBuffer]);
1317#else
1318    buffer->BindBuffer(glTargets[sourceBuffer]);
1319#endif
1320    if (buffer->IsDoubleBuffered()) glDrawBuffer(glTargets[targetBuffer]);
1321#endif
1322
1323    checkGLError("after db");
1324
1325    int pstage = (1<<stage);
1326    int ppass  = (1<<pass);
1327    //int activeBitonicShader = 0;
1328
1329    // switch on correct sorting shader
1330    oddevenMergeSort.bind();
1331    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param1"), float(pstage+pstage),
1332                   float(ppass%pstage), float((pstage+pstage)-(ppass%pstage)-1));
1333    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param2"),
1334                   float(psys_width), float(psys_height), float(ppass));
1335    glUniform1iARB(oddevenMergeSort.getUniformLocation("Data"), 0);
1336    staticdebugmsg("sort","stage "<<pstage<<" pass "<<ppass);
1337
1338    // This clear is not necessary for sort to function. But if we are in
1339    // interactive mode unused parts of the texture that are visible will look
1340    // bad.
1341#ifdef notdef
1342    if (!perfTest) glClear(GL_COLOR_BUFFER_BIT);
1343
1344    buffer->Bind();
1345    buffer->EnableTextureTarget();
1346#endif
1347
1348    // Initiate the sorting step on the GPU a full-screen quad
1349    glBegin(GL_QUADS);
1350    {
1351#ifdef notdef
1352        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f);
1353        glVertex2f(-1.0f,-1.0f);
1354        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f);
1355        glVertex2f(1.0f,-1.0f);
1356        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f);
1357        glVertex2f(1.0f,1.0f);
1358        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f);
1359        glVertex2f(-1.0f,1.0f);
1360#endif
1361        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f);
1362        glVertex2f(0.,0.);
1363        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f);
1364        glVertex2f(float(psys_width), 0.);
1365        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f);
1366        glVertex2f(float(psys_width), float(psys_height));
1367        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f);
1368        glVertex2f(0., float(psys_height));
1369    }
1370    glEnd();
1371
1372    // switch off sorting shader
1373    oddevenMergeSort.release();
1374
1375    //buffer->DisableTextureTarget();
1376
1377    //assert(glGetError()==0);
1378}
1379#endif
1380
1381
1382void
1383draw_3d_axis()
1384{
1385    glDisable(GL_TEXTURE_2D);
1386    glEnable(GL_DEPTH_TEST);
1387
1388    //draw axes
1389    GLUquadric *obj;
1390
1391    obj = gluNewQuadric();
1392
1393    glDepthFunc(GL_LESS);
1394    glEnable(GL_COLOR_MATERIAL);
1395    glEnable(GL_DEPTH_TEST);
1396    glDisable(GL_BLEND);
1397
1398    int segments = 50;
1399
1400    glColor3f(0.8, 0.8, 0.8);
1401    glPushMatrix();
1402    glTranslatef(0.4, 0., 0.);
1403    glRotatef(90, 1, 0, 0);
1404    glRotatef(180, 0, 1, 0);
1405    glScalef(0.0005, 0.0005, 0.0005);
1406    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'x');
1407    glPopMatrix();
1408
1409    glPushMatrix();
1410    glTranslatef(0., 0.4, 0.);
1411    glRotatef(90, 1, 0, 0);
1412    glRotatef(180, 0, 1, 0);
1413    glScalef(0.0005, 0.0005, 0.0005);
1414    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'y');
1415    glPopMatrix();
1416
1417    glPushMatrix();
1418    glTranslatef(0., 0., 0.4);
1419    glRotatef(90, 1, 0, 0);
1420    glRotatef(180, 0, 1, 0);
1421    glScalef(0.0005, 0.0005, 0.0005);
1422    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'z');
1423    glPopMatrix();
1424
1425    glEnable(GL_LIGHTING);
1426    glEnable(GL_LIGHT0);
1427
1428    //glColor3f(0.2, 0.2, 0.8);
1429    glPushMatrix();
1430    glutSolidSphere(0.02, segments, segments );
1431    glPopMatrix();
1432
1433    glPushMatrix();
1434    glRotatef(-90, 1, 0, 0);
1435    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1436    glPopMatrix();
1437
1438    glPushMatrix();
1439    glTranslatef(0., 0.3, 0.);
1440    glRotatef(-90, 1, 0, 0);
1441    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1442    glPopMatrix();
1443
1444    glPushMatrix();
1445    glRotatef(90, 0, 1, 0);
1446    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1447    glPopMatrix();
1448
1449    glPushMatrix();
1450    glTranslatef(0.3, 0., 0.);
1451    glRotatef(90, 0, 1, 0);
1452    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1453    glPopMatrix();
1454
1455    glPushMatrix();
1456    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1457    glPopMatrix();
1458
1459    glPushMatrix();
1460    glTranslatef(0., 0., 0.3);
1461    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1462    glPopMatrix();
1463
1464    glDisable(GL_LIGHTING);
1465    glDisable(GL_DEPTH_TEST);
1466    gluDeleteQuadric(obj);
1467
1468    glEnable(GL_TEXTURE_2D);
1469    glDisable(GL_DEPTH_TEST);
1470}
1471
1472void NanoVis::update()
1473{
1474    if (vol_renderer->_volumeInterpolator->is_started()) {
1475        struct timeval clock;
1476        gettimeofday(&clock, NULL);
1477        double elapsed_time;
1478
1479        elapsed_time = clock.tv_sec + clock.tv_usec/1000000.0 -
1480            vol_renderer->_volumeInterpolator->getStartTime();
1481
1482        Trace("%lf %lf\n", elapsed_time, vol_renderer->_volumeInterpolator->getInterval());
1483        float fraction;
1484        float f;
1485
1486        f = fmod((float) elapsed_time, (float)vol_renderer->_volumeInterpolator->getInterval());
1487        if (f == 0.0) {
1488            fraction = 0.0f;
1489        } else {
1490            fraction = f / vol_renderer->_volumeInterpolator->getInterval();
1491        }
1492        Trace("fraction : %f\n", fraction);
1493        vol_renderer->_volumeInterpolator->update(fraction);
1494    }
1495}
1496
1497void
1498NanoVis::SetVolumeRanges()
1499{
1500    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1501
1502    if (debug_flag) {
1503        fprintf(stderr, "in SetVolumeRanges\n");
1504    }
1505    xMin = yMin = zMin = wMin = DBL_MAX;
1506    xMax = yMax = zMax = wMax = -DBL_MAX;
1507    for (unsigned int i = 0; i < volume.size(); i++) {
1508        Volume *volPtr;
1509
1510        volPtr = volume[i];
1511        if (volPtr == NULL) {
1512            continue;
1513        }
1514        if (!volPtr->enabled) {
1515            continue;
1516        }
1517        if (xMin > volPtr->xAxis.min()) {
1518            xMin = volPtr->xAxis.min();
1519        }
1520        if (xMax < volPtr->xAxis.max()) {
1521            xMax = volPtr->xAxis.max();
1522        }
1523        if (yMin > volPtr->yAxis.min()) {
1524            yMin = volPtr->yAxis.min();
1525        }
1526        if (yMax < volPtr->yAxis.max()) {
1527            yMax = volPtr->yAxis.max();
1528        }
1529        if (zMin > volPtr->zAxis.min()) {
1530            zMin = volPtr->zAxis.min();
1531        }
1532        if (zMax < volPtr->zAxis.max()) {
1533            zMax = volPtr->zAxis.max();
1534        }
1535        if (wMin > volPtr->wAxis.min()) {
1536            wMin = volPtr->wAxis.min();
1537        }
1538        if (wMax < volPtr->wAxis.max()) {
1539            wMax = volPtr->wAxis.max();
1540        }
1541    }
1542    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1543        grid->xAxis.SetScale(xMin, xMax);
1544    }
1545    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1546        grid->yAxis.SetScale(yMin, yMax);
1547    }
1548    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1549        grid->zAxis.SetScale(zMin, zMax);
1550    }
1551    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1552        Volume::valueMin = wMin;
1553        Volume::valueMax = wMax;
1554    }
1555    Volume::update_pending = false;
1556    if (debug_flag) {
1557        fprintf(stderr, "leaving SetVolumeRanges\n");
1558    }
1559}
1560
1561void
1562NanoVis::SetHeightmapRanges()
1563{
1564    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1565
1566    if (debug_flag) {
1567        fprintf(stderr, "in SetHeightmapRanges\n");
1568    }
1569    xMin = yMin = zMin = wMin = DBL_MAX;
1570    xMax = yMax = zMax = wMax = -DBL_MAX;
1571    for (unsigned int i = 0; i < heightMap.size(); i++) {
1572        HeightMap *hmPtr;
1573
1574        hmPtr = heightMap[i];
1575        if (hmPtr == NULL) {
1576            continue;
1577        }
1578        if (xMin > hmPtr->xAxis.min()) {
1579            xMin = hmPtr->xAxis.min();
1580        }
1581        if (xMax < hmPtr->xAxis.max()) {
1582            xMax = hmPtr->xAxis.max();
1583        }
1584        if (yMin > hmPtr->yAxis.min()) {
1585            yMin = hmPtr->yAxis.min();
1586        }
1587        if (yMax < hmPtr->yAxis.max()) {
1588            yMax = hmPtr->yAxis.max();
1589        }
1590        if (zMin > hmPtr->zAxis.min()) {
1591            zMin = hmPtr->zAxis.min();
1592        }
1593        if (zMax < hmPtr->zAxis.max()) {
1594            zMax = hmPtr->zAxis.max();
1595        }
1596        if (wMin > hmPtr->wAxis.min()) {
1597            wMin = hmPtr->wAxis.min();
1598        }
1599        if (wMax < hmPtr->wAxis.max()) {
1600            wMax = hmPtr->wAxis.max();
1601        }
1602    }
1603    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1604        grid->xAxis.SetScale(xMin, xMax);
1605    }
1606    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1607        grid->yAxis.SetScale(yMin, yMax);
1608    }
1609    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1610        grid->zAxis.SetScale(zMin, zMax);
1611    }
1612    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1613        HeightMap::valueMin = grid->yAxis.min();
1614        HeightMap::valueMax = grid->yAxis.max();
1615    }
1616    for (unsigned int i = 0; i < heightMap.size(); i++) {
1617        HeightMap *hmPtr;
1618
1619        hmPtr = heightMap[i];
1620        if (hmPtr == NULL) {
1621            continue;
1622        }
1623        hmPtr->MapToGrid(grid);
1624    }
1625    HeightMap::update_pending = false;
1626    if (debug_flag) {
1627        fprintf(stderr, "leaving SetHeightmapRanges\n");
1628    }
1629}
1630
1631/*----------------------------------------------------*/
1632void
1633NanoVis::display()
1634{
1635    if (debug_flag) {
1636        fprintf(stderr, "in display\n");
1637    }
1638    //assert(glGetError()==0);
1639    if (HeightMap::update_pending) {
1640        SetHeightmapRanges();
1641    }
1642    if (Volume::update_pending) {
1643        SetVolumeRanges();
1644    }
1645    if (debug_flag) {
1646        fprintf(stderr, "in display: glClear\n");
1647    }
1648    //start final rendering
1649    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
1650
1651    if (volume_mode) {
1652        if (debug_flag) {
1653            fprintf(stderr, "in display: volume_mode\n");
1654        }
1655        //3D rendering mode
1656        // TBD..
1657        //glEnable(GL_TEXTURE_2D);
1658        glEnable(GL_DEPTH_TEST);
1659
1660        //camera setting activated
1661        cam->activate();
1662
1663        //set up the orientation of items in the scene.
1664        glPushMatrix();
1665        switch (updir) {
1666        case 1:  // x
1667            glRotatef(90, 0, 0, 1);
1668            glRotatef(90, 1, 0, 0);
1669            break;
1670
1671        case 2:  // y
1672            // this is the default
1673            break;
1674
1675        case 3:  // z
1676            glRotatef(-90, 1, 0, 0);
1677            glRotatef(-90, 0, 0, 1);
1678            break;
1679
1680        case -1:  // -x
1681            glRotatef(-90, 0, 0, 1);
1682            break;
1683
1684        case -2:  // -y
1685            glRotatef(180, 0, 0, 1);
1686            glRotatef(-90, 0, 1, 0);
1687            break;
1688
1689        case -3:  // -z
1690            glRotatef(90, 1, 0, 0);
1691            break;
1692        }
1693
1694        // TBD : This will be removed after being sure that all the functions work well.
1695        //glPushMatrix();
1696
1697        //now render things in the scene
1698        if (axis_on) {
1699            draw_3d_axis();
1700        }
1701        if (grid->isVisible()) {
1702            grid->render();
1703        }
1704        if ((licRenderer != NULL) && (licRenderer->isActivated())) {
1705            licRenderer->render();
1706        }
1707
1708        if ((flowVisRenderer != NULL) && (flowVisRenderer->isActivated())) {
1709            flowVisRenderer->render();
1710        }
1711
1712        //soft_display_verts();
1713        //perf->enable();
1714        //perf->disable();
1715        //fprintf(stderr, "particle pixels: %d\n", perf->get_pixel_count());
1716        //perf->reset();
1717
1718        //perf->enable();
1719        vol_renderer->render_all();
1720        //perf->disable();
1721
1722        if (debug_flag) {
1723            fprintf(stderr, "in display: render heightmap\n");
1724        }
1725        for (unsigned int i = 0; i < heightMap.size(); ++i) {
1726            if (heightMap[i]->isVisible()) {
1727                heightMap[i]->render(renderContext);
1728            }
1729        }
1730        glPopMatrix();
1731    } else {
1732        //2D rendering mode
1733        perf->enable();
1734        plane_render->render();
1735        perf->disable();
1736    }
1737
1738    perf->reset();
1739    if (debug_flag) {
1740        fprintf(stderr, "leaving display\n");
1741    }
1742
1743}
1744
1745#ifndef XINETD
1746void
1747NanoVis::mouse(int button, int state, int x, int y)
1748{
1749    if(button==GLUT_LEFT_BUTTON){
1750        if (state==GLUT_DOWN) {
1751            left_last_x = x;
1752            left_last_y = y;
1753            left_down = true;
1754            right_down = false;
1755        } else {
1756            left_down = false;
1757            right_down = false;
1758        }
1759    } else {
1760        //fprintf(stderr, "right mouse\n");
1761
1762        if(state==GLUT_DOWN){
1763            //fprintf(stderr, "right mouse down\n");
1764            right_last_x = x;
1765            right_last_y = y;
1766            left_down = false;
1767            right_down = true;
1768        } else {
1769            //fprintf(stderr, "right mouse up\n");
1770            left_down = false;
1771            right_down = false;
1772        }
1773    }
1774}
1775
1776void
1777NanoVis::update_rot(int delta_x, int delta_y)
1778{
1779    Vector3 angle;
1780
1781    angle = cam->rotate();
1782    angle.x += delta_x;
1783    angle.y += delta_y;
1784
1785    if (angle.x > 360.0) {
1786        angle.x -= 360.0;
1787    } else if(angle.x < -360.0) {
1788        angle.x += 360.0;
1789    }
1790    if (angle.y > 360.0) {
1791        angle.y -= 360.0;
1792    } else if(angle.y < -360.0) {
1793        angle.y += 360.0;
1794    }
1795    cam->rotate(angle);
1796}
1797
1798void
1799NanoVis::update_trans(int delta_x, int delta_y, int delta_z)
1800{
1801    cam->x(cam->x() + delta_x * 0.03);
1802    cam->y(cam->y() + delta_y * 0.03);
1803    cam->z(cam->z() + delta_z * 0.03);
1804}
1805
1806#ifdef NEW_FLOW_ENGINE
1807void addVectorField(const char* filename, const char* vf_name,
1808                    const char* plane_name1, const char* plane_name2,
1809                    const Vector4& color1, const Vector4& color2)
1810{
1811    Rappture::Outcome result;
1812    std::ifstream fdata;
1813    fdata.open(filename, std::ios::in);
1814   
1815    int n = NanoVis::n_volumes;
1816    //fdata.write(buf.bytes(),buf.size());
1817    if (load_vector_stream2(result, n, fdata)) {
1818        Volume *volPtr = NanoVis::volume[n];
1819        if (volPtr != NULL) {
1820            volPtr->set_n_slice(256-n);
1821            // volPtr->set_n_slice(512-n);
1822            volPtr->disable_cutplane(0);
1823            volPtr->disable_cutplane(1);
1824            volPtr->disable_cutplane(2);
1825           
1826            NanoVis::vol_renderer->add_volume(volPtr,
1827                                              NanoVis::get_transfunc("default"));
1828            float dx0 = -0.5;
1829            float dy0 = -0.5*volPtr->height/volPtr->width;
1830            float dz0 = -0.5*volPtr->depth/volPtr->width;
1831            volPtr->move(Vector3(dx0, dy0, dz0));
1832            //volPtr->enable_data();
1833            volPtr->disable_data();
1834            NanoVis::flowVisRenderer->addVectorField(vf_name, volPtr,
1835                *(volPtr->get_location()),
1836                1.0f,
1837                volPtr->height / (float)volPtr->width,
1838                volPtr->depth  / (float)volPtr->width,
1839                1.0f);
1840            NanoVis::flowVisRenderer->activateVectorField(vf_name);
1841           
1842            //////////////////////////////////
1843            // ADD Particle Injection Plane1
1844            NanoVis::flowVisRenderer->addPlane(vf_name, plane_name1);
1845            NanoVis::flowVisRenderer->setPlaneAxis(vf_name, plane_name1, 0);
1846            NanoVis::flowVisRenderer->setPlanePos(vf_name, plane_name1, 0.9);
1847            NanoVis::flowVisRenderer->setParticleColor(vf_name, plane_name1, color1);
1848            // ADD Particle Injection Plane2
1849            NanoVis::flowVisRenderer->addPlane(vf_name, plane_name2);
1850            NanoVis::flowVisRenderer->setPlaneAxis(vf_name, plane_name2, 0);
1851            NanoVis::flowVisRenderer->setPlanePos(vf_name, plane_name2, 0.2);
1852            NanoVis::flowVisRenderer->setParticleColor(vf_name, plane_name2, color2);
1853            NanoVis::flowVisRenderer->initialize(vf_name);
1854           
1855            NanoVis::flowVisRenderer->activatePlane(vf_name, plane_name1);
1856            NanoVis::flowVisRenderer->activatePlane(vf_name, plane_name2);
1857           
1858            NanoVis::licRenderer->setVectorField(volPtr->id,
1859                                *(volPtr->get_location()),
1860                                1.0f / volPtr->aspect_ratio_width,
1861                                1.0f / volPtr->aspect_ratio_height,
1862                                1.0f / volPtr->aspect_ratio_depth,
1863                                volPtr->wAxis.max());
1864        }
1865    }
1866    //NanoVis::initParticle();
1867}
1868#endif
1869
1870void
1871NanoVis::keyboard(unsigned char key, int x, int y)
1872{
1873#ifdef EVENTLOG
1874    if(log){
1875        float param[3];
1876        param[0] = cam->x();
1877        param[1] = cam->y();
1878        param[2] = cam->z();
1879        Event* tmp = new Event(EVENT_MOVE, param, NvGetTimeInterval());
1880        tmp->write(event_log);
1881        delete tmp;
1882    }
1883#endif
1884
1885#ifdef NEW_FLOW_ENGINE
1886    switch (key)
1887    {
1888        case 'a' :
1889                {
1890                        printf("flowvis active\n");
1891                        NanoVis::flowVisRenderer->activate();
1892                        NanoVis::licRenderer->activate();
1893                }
1894                break;
1895        case 'd' :
1896                {
1897                        printf("flowvis deactived\n");
1898                        NanoVis::flowVisRenderer->deactivate();
1899                        NanoVis::licRenderer->deactivate();
1900                }
1901                break;
1902        case '1' :
1903                {
1904                        addVectorField("/home/iwoo/projects/nanovis/rappture/packages/vizservers/nanovis/data/flowvis_dx_files/jwire/J-wire-vec.dx",
1905                                        "vf_name2", "plane_name1", "plane_name2", Vector4(0, 0, 1, 1), Vector4(0, 1, 1, 1));
1906                        printf("add vector field\n");
1907                }
1908                break;
1909        case '2' :
1910                {
1911                        printf("add vector field\n");
1912                        addVectorField("/home/iwoo/projects/nanovis/rappture/packages/vizservers/nanovis/data/flowvis_dx_files/3DWireLeakage/SiO2/SiO2.dx",
1913                                        "vf_name1", "plane_name1", "plane_name2", Vector4(1, 0, 0, 1), Vector4(1, 1, 0, 1));
1914                }
1915                break;
1916        case '3':
1917                {
1918                        printf("activate\n");
1919                        NanoVis::flowVisRenderer->activatePlane("vf_name1", "plane_name2");
1920                }
1921                break;
1922        case '4' :
1923                {
1924                        printf("deactivate\n");
1925                        NanoVis::flowVisRenderer->deactivatePlane("vf_name1", "plane_name2");
1926                }
1927                break;
1928        case '5' :
1929                {
1930                        printf("vector field deleted (vf_name2)\n");
1931                        NanoVis::flowVisRenderer->removeVectorField("vf_name2");
1932                }
1933                break;
1934        case '6' :
1935                {
1936                        printf("add device shape\n");
1937                        NvDeviceShape shape;
1938                        shape.min.set(0, 0, 0);
1939                        shape.max.set(30, 3, 3);
1940                        shape.color.set(1, 0, 0, 1);
1941                        NanoVis::flowVisRenderer->addDeviceShape("vf_name1", "device1", shape);
1942                        shape.min.set(0, -1, -1);
1943                        shape.max.set(30, 4, 4);
1944                        shape.color.set(0, 1, 0, 1);
1945                        NanoVis::flowVisRenderer->addDeviceShape("vf_name1", "device2", shape);
1946                        shape.min.set(10, -1.5, -1);
1947                        shape.max.set(20, 4.5, 4.5);
1948                        shape.color.set(0, 0, 1, 1);
1949                        NanoVis::flowVisRenderer->addDeviceShape("vf_name1", "device3", shape);
1950                        NanoVis::flowVisRenderer->activateDeviceShape("vf_name1");
1951                }
1952                break;
1953        case '7' :
1954                {
1955                        printf("hide shape \n");
1956                        NanoVis::flowVisRenderer->deactivateDeviceShape("vf_name1");
1957                }
1958                break;
1959        case '8' :
1960                {
1961                        printf("show shape\n");
1962                        NanoVis::flowVisRenderer->activateDeviceShape("vf_name1");
1963                }
1964                break;
1965        case '9' :
1966                {
1967                        printf("show a shape \n");
1968                        NanoVis::flowVisRenderer->activateDeviceShape("vf_name1", "device3");
1969                }
1970                break;
1971        case '0' :
1972                {
1973                        printf("delete a shape \n");
1974                        NanoVis::flowVisRenderer->deactivateDeviceShape("vf_name1", "device3");
1975                }
1976                break;
1977        case 'r' :
1978                {
1979                        NanoVis::flowVisRenderer->reset();
1980                        NanoVis::licRenderer->reset();
1981                        printf("reset \n");
1982                }
1983                break;
1984        }
1985#endif
1986}
1987
1988void
1989NanoVis::motion(int x, int y)
1990{
1991    int old_x, old_y;
1992
1993    if(left_down){
1994        old_x = left_last_x;
1995        old_y = left_last_y;
1996    } else if(right_down){
1997        old_x = right_last_x;
1998        old_y = right_last_y;
1999    }
2000
2001    int delta_x = x - old_x;
2002    int delta_y = y - old_y;
2003
2004    //more coarse event handling
2005    //if(abs(delta_x)<10 && abs(delta_y)<10)
2006    //return;
2007
2008    if(left_down){
2009        left_last_x = x;
2010        left_last_y = y;
2011
2012        update_rot(-delta_y, -delta_x);
2013    } else if (right_down){
2014        //fprintf(stderr, "right mouse motion (%d,%d)\n", x, y);
2015
2016        right_last_x = x;
2017        right_last_y = y;
2018
2019        update_trans(0, 0, delta_x);
2020    }
2021
2022#ifdef EVENTLOG
2023    Vector3 angle = cam->rotate();
2024    Event* tmp = new Event(EVENT_ROTATE, &angle, NvGetTimeInterval());
2025    tmp->write(event_log);
2026    delete tmp;
2027#endif
2028    glutPostRedisplay();
2029}
2030
2031#endif /*XINETD*/
2032
2033void
2034NanoVis::render()
2035{
2036
2037    if ((NanoVis::licRenderer != NULL) &&
2038        (NanoVis::licRenderer->isActivated())) {
2039        NanoVis::licRenderer->convolve();
2040    }
2041
2042    if ((NanoVis::flowVisRenderer != NULL) &&
2043        (NanoVis::flowVisRenderer->isActivated())) {
2044        NanoVis::flowVisRenderer->advect();
2045    }
2046
2047    NanoVis::update();
2048    display();
2049    glutSwapBuffers();
2050}
2051
2052void
2053NanoVis::resize(int x, int y)
2054{
2055    glViewport(0, 0, x, y);
2056}
2057
2058void
2059NanoVis::xinetd_listen(void)
2060{
2061    if (debug_flag) {
2062        fprintf(stderr, "in xinetd_listen\n");
2063    }
2064    int flags = fcntl(0, F_GETFL, 0);
2065    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2066
2067    int status = TCL_OK;
2068
2069    //
2070    //  Read and execute as many commands as we can from stdin...
2071    //
2072    bool isComplete = false;
2073    while (status == TCL_OK) {
2074        //
2075        //  Read the next command from the buffer.  First time through we
2076        //  block here and wait if necessary until a command comes in.
2077        //
2078        //  BE CAREFUL: Read only one command, up to a newline.  The "volume
2079        //  data follows" command needs to be able to read the data
2080        //  immediately following the command, and we shouldn't consume it
2081        //  here.
2082        //
2083        if (debug_flag) {
2084            fprintf(stderr, "in xinetd_listen: check eof %d\n",
2085                    feof(NanoVis::stdin));
2086        }
2087        while (!feof(NanoVis::stdin)) {
2088            int c = fgetc(NanoVis::stdin);
2089            char ch;
2090            if (c <= 0) {
2091                if (errno == EWOULDBLOCK) {
2092                    break;
2093                }
2094                DoExit(0);
2095            }
2096            ch = (char)c;
2097            Tcl_DStringAppend(&cmdbuffer, &ch, 1);
2098            if (ch == '\n') {
2099                isComplete = Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer));
2100                if (isComplete) {
2101                    break;
2102                }
2103            }
2104        }
2105        // no command? then we're done for now
2106        if (Tcl_DStringLength(&cmdbuffer) == 0) {
2107            break;
2108        }
2109
2110        if (isComplete) {
2111            // back to original flags during command evaluation...
2112            fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2113            status = ExecuteCommand(interp, &cmdbuffer);
2114            // non-blocking for next read -- we might not get anything
2115            fcntl(0, F_SETFL, flags | O_NONBLOCK);
2116            isComplete = false;
2117        }
2118    }
2119    fcntl(0, F_SETFL, flags);
2120
2121    if (status != TCL_OK) {
2122        const char *string;
2123        int nBytes;
2124
2125        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
2126        nBytes = strlen(string);
2127        struct iovec iov[3];
2128        iov[0].iov_base = (char *)"NanoVis Server Error: ";
2129        iov[0].iov_len = strlen((char *)iov[0].iov_base);
2130        iov[1].iov_base = (char *)string;
2131        iov[1].iov_len = nBytes;
2132        iov[2].iov_len = 1;
2133        iov[2].iov_base = (char *)'\n';
2134        writev(0, iov, 3);
2135        if (debug_flag) {
2136            fprintf(stderr, "leaving xinetd_listen\n");
2137        }
2138        return;
2139    }
2140
2141    NanoVis::update();
2142
2143    NanoVis::offscreen_buffer_capture();  //enable offscreen render
2144
2145    NanoVis::display();
2146
2147    // INSOO
2148#ifdef XINETD
2149    NanoVis::read_screen();
2150    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2151#else
2152    NanoVis::display_offscreen_buffer(); //display the final rendering on screen
2153    NanoVis::read_screen();
2154    glutSwapBuffers();
2155#endif
2156
2157#if DO_RLE
2158    do_rle();
2159    int sizes[2] = {  offsets_size*sizeof(offsets[0]), rle_size };
2160    fprintf(stderr, "Writing %d,%d\n", sizes[0], sizes[1]); fflush(stderr);
2161    write(0, &sizes, sizeof(sizes));
2162    write(0, offsets, offsets_size*sizeof(offsets[0]));
2163    write(0, rle, rle_size);    //unsigned byte
2164#else
2165    if (debug_flag) {
2166        fprintf(stderr, "ppm image not written (debug mode)\n");
2167        bmp_write_to_file(1, "/tmp");
2168    } else {
2169        NanoVis::ppm_write("nv>image -type image -bytes");
2170    }
2171#endif
2172    if (feof(NanoVis::stdin)) {
2173        DoExit(0);
2174    }
2175    if (debug_flag) {
2176        fprintf(stderr, "leaving xinetd_listen\n");
2177    }
2178}
2179
2180
2181/*----------------------------------------------------*/
2182int
2183main(int argc, char** argv)
2184{
2185    const char *path;
2186    char *newPath;
2187    struct timeval tv;
2188
2189    newPath = NULL;
2190    path = NULL;
2191    NanoVis::stdin = stdin;
2192    NanoVis::logfile = stderr;
2193
2194    gettimeofday(&tv, NULL);
2195    stats.start = tv;
2196
2197    /* Initialize GLUT here so it can parse and remove GLUT-specific
2198     * command-line options before we parse the command-line below. */
2199    glutInit(&argc, argv);
2200    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
2201    glutInitWindowSize(NanoVis::win_width, NanoVis::win_height);
2202    glutInitWindowPosition(10, 10);
2203    NanoVis::render_window = glutCreateWindow("nanovis");
2204    glutIdleFunc(NanoVis::idle);
2205
2206#ifndef XINETD
2207    glutMouseFunc(NanoVis::mouse);
2208    glutMotionFunc(NanoVis::motion);
2209    glutKeyboardFunc(NanoVis::keyboard);
2210    glutReshapeFunc(NanoVis::resize);
2211    glutDisplayFunc(NanoVis::render);
2212#else
2213    glutDisplayFunc(NanoVis::display);
2214    glutReshapeFunc(NanoVis::resize_offscreen_buffer);
2215#endif
2216
2217    while (1) {
2218        static struct option long_options[] = {
2219            {"infile",  required_argument, NULL,           0},
2220            {"logfile", required_argument, NULL,           1},
2221            {"path",    required_argument, NULL,           2},
2222            {"debug",   no_argument,       NULL,           3},
2223            {"record",  required_argument, NULL,           4},
2224            {0, 0, 0, 0}
2225        };
2226        int option_index = 0;
2227        int c;
2228
2229        c = getopt_long(argc, argv, ":dp:i:l:r:", long_options, &option_index);
2230        if (c == -1) {
2231            break;
2232        }
2233        switch (c) {
2234        case '?':
2235            fprintf(stderr, "unknown option -%c\n", optopt);
2236            return 1;
2237        case ':':
2238            if (optopt < 4) {
2239                fprintf(stderr, "argument missing for --%s option\n",
2240                        long_options[optopt].name);
2241            } else {
2242                fprintf(stderr, "argument missing for -%c option\n", optopt);
2243            }
2244            return 1;
2245        case 2:
2246        case 'p':
2247            path = optarg;
2248            break;
2249        case 3:
2250        case 'd':
2251            NanoVis::debug_flag = true;
2252            break;
2253        case 0:
2254        case 'i':
2255            NanoVis::stdin = fopen(optarg, "r");
2256            if (NanoVis::stdin == NULL) {
2257                perror(optarg);
2258                return 2;
2259            }
2260            break;
2261        case 1:
2262        case 'l':
2263            NanoVis::logfile = fopen(optarg, "w");
2264            if (NanoVis::logfile == NULL) {
2265                perror(optarg);
2266                return 2;
2267            }
2268            break;
2269        case 4:
2270        case 'r':
2271            Tcl_DString ds;
2272            char buf[200];
2273
2274            Tcl_DStringInit(&ds);
2275            Tcl_DStringAppend(&ds, optarg, -1);
2276            sprintf(buf, ".%d", getpid());
2277            Tcl_DStringAppend(&ds, buf, -1);
2278            NanoVis::recfile = fopen(Tcl_DStringValue(&ds), "w");
2279            if (NanoVis::recfile == NULL) {
2280                perror(optarg);
2281                return 2;
2282            }
2283            break;
2284        default:
2285            fprintf(stderr,"unknown option '%c'.\n", c);
2286            return 1;
2287        }
2288    }     
2289    if (path == NULL) {
2290        char *p;
2291
2292        // See if we can derive the path from the location of the program.
2293        // Assume program is in the form <path>/bin/nanovis.
2294
2295#ifdef XINETD
2296        path = argv[0];
2297        p = strrchr(path, '/');
2298        if (p != NULL) {
2299            *p = '\0';
2300            p = strrchr(path, '/');
2301        }
2302        if (p == NULL) {
2303            fprintf(stderr, "path not specified\n");
2304            return 1;
2305        }
2306        *p = '\0';
2307        newPath = new char[(strlen(path) + 15) * 2 + 1];
2308        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", path, path);
2309        path = newPath;
2310#else
2311        char buff[256];
2312        getcwd(buff, 255);
2313        p = strrchr(buff, '/');
2314        if (p != NULL) {
2315            *p = '\0';
2316        }
2317        newPath = new char[(strlen(buff) + 15) * 2 + 1];
2318        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", buff, buff);
2319        path = newPath;
2320#endif
2321    }
2322    R2FilePath::getInstance()->setWorkingDirectory(argc, (const char**) argv);
2323
2324#ifdef XINETD
2325    signal(SIGPIPE,SIG_IGN);
2326    NvInitService();
2327#endif
2328
2329    NanoVis::init(path);
2330    if (newPath != NULL) {
2331        delete [] newPath;
2332    }
2333    NanoVis::initGL();
2334#ifdef EVENTLOG
2335    NvInitEventLog();
2336#endif
2337    Tcl_DStringInit(&NanoVis::cmdbuffer);
2338    NanoVis::interp = initTcl();
2339    NanoVis::resize_offscreen_buffer(NanoVis::win_width, NanoVis::win_height);
2340
2341    glutMainLoop();
2342    DoExit(0);
2343}
2344
2345int
2346NanoVis::render_2d_contour(HeightMap* heightmap, int width, int height)
2347{
2348    int old_width = win_width;
2349    int old_height = win_height;
2350
2351    resize_offscreen_buffer(width, height);
2352
2353    /*
2354      plane_render->set_screen_size(width, height);
2355
2356      // generate data for the legend
2357      float data[512];
2358      for (int i=0; i < 256; i++) {
2359      data[i] = data[i+256] = (float)(i/255.0);
2360      }
2361      plane[0] = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
2362      int index = plane_render->add_plane(plane[0], tf);
2363      plane_render->set_active_plane(index);
2364
2365      offscreen_buffer_capture();
2366      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
2367
2368      //plane_render->render();
2369      // INSOO : is going to implement here for the topview of the heightmap
2370      heightmap->render(renderContext);
2371
2372      // INSOO
2373      glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
2374      //glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, screen_buffer); // INSOO's
2375      */
2376
2377
2378    // HELP ME
2379    // GEORGE
2380    // I am not sure what I should do
2381    //char prefix[200];
2382    //sprintf(prefix, "nv>height_top_view %s %g %g", volArg, min, max);
2383    //ppm_write(prefix);
2384    //write(0, "\n", 1);
2385    //plane_render->remove_plane(index);
2386
2387    // CURRENT
2388    offscreen_buffer_capture();
2389    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
2390    //glEnable(GL_TEXTURE_2D);
2391    //glEnable(GL_DEPTH_TEST);
2392    //heightmap->render_topview(renderContext, width, height);
2393    //NanoVis::display();
2394    if (HeightMap::update_pending) {
2395        SetHeightmapRanges();
2396    }
2397
2398    //cam->activate();
2399
2400    heightmap->render_topview(renderContext, width, height);
2401
2402    NanoVis::read_screen();
2403    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2404
2405    // INSOO TEST CODE
2406    bmp_write_to_file(1, "/tmp");
2407
2408    resize_offscreen_buffer(old_width, old_height);
2409
2410    return TCL_OK;
2411}
Note: See TracBrowser for help on using the repository browser.