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

Last change on this file since 2921 was 2920, checked in by ldelgass, 12 years ago

Convert LIC renderer to use NvShader? class. Also, prevent GL state leaks from
LIC renderer, esp. with framebuffer binding.

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