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

Last change on this file since 2880 was 2880, checked in by ldelgass, 12 years ago
  1. 2877 included some files that weren't intended to be checked in yet, but

now that the cat is out of the bag, include the rest of the fixes to the dx
reader, gradient computation, etc. old and new dx reader functions are merged
into one now. Camera behavior still defaults to what the old client side
expects.

  • Property svn:eol-style set to native
File size: 68.3 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->make_patterns();
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("GLEW_ARB_texture_non_power_of_two extension is required to run nanovis\n");
753        doExit(1);
754    }
755#endif
756#ifdef HAVE_FLOAT_TEXTURES
757    if (!GLEW_ARB_texture_float ||
758        !GLEW_ARB_color_buffer_float) {
759        ERROR("ARB_texture_float and ARB_color_buffer_float extensions are required to run nanovis\n");
760        doExit(1);
761    }
762#endif
763
764    if (!R2FilePath::getInstance()->setPath(path)) {
765        ERROR("can't set file path to %s\n", path);
766        doExit(1);
767    }
768
769    vrFilePath::getInstance()->setPath(path);
770
771    ImageLoaderFactory::getInstance()->addLoaderImpl("bmp", new BMPImageLoaderImpl());
772
773    NvShader::initCg();
774    NvShader::setErrorCallback(cgErrorCallback);
775
776    fonts = new R2Fonts();
777    fonts->addFont("verdana", "verdana.fnt");
778    fonts->setFont("verdana");
779
780    colorTableRenderer = new NvColorTableRenderer();
781    colorTableRenderer->setFonts(fonts);
782
783    flowVisRenderer = new NvFlowVisRenderer(NMESH, NMESH);
784
785    NanoVis::velocityArrowsSlice = new VelocityArrowsSlice;
786
787    licRenderer = new NvLIC(NMESH, NPIX, NPIX, _licAxis,
788                            Vector3(_licSliceX, _licSliceY, _licSliceZ),
789                            NvShader::getCgContext());
790
791    grid = new Grid();
792    grid->setFont(fonts);
793
794#ifdef USE_POINTSET_RENDERER
795    pointSetRenderer = new PointSetRenderer();
796#endif
797}
798
799/*----------------------------------------------------*/
800void
801NanoVis::initGL(void)
802{
803    TRACE("in initGL\n");
804    //buffer to store data read from the screen
805    if (screenBuffer) {
806        delete[] screenBuffer;
807        screenBuffer = NULL;
808    }
809    screenBuffer = new unsigned char[4*winWidth*winHeight];
810    assert(screenBuffer != NULL);
811
812    //create the camera with default setting
813    cam = new NvCamera(0, 0, winWidth, winHeight,
814                       def_eye_x, def_eye_y, def_eye_z,          /* location. */
815                       def_target_x, def_target_y, def_target_z, /* target. */
816                       def_rot_x, def_rot_y, def_rot_z);         /* angle. */
817
818    glEnable(GL_TEXTURE_2D);
819    glShadeModel(GL_FLAT);
820    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
821
822    glClearColor(0,0,0,1);
823    glClear(GL_COLOR_BUFFER_BIT);
824
825    //initialize lighting
826    GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
827    GLfloat mat_shininess[] = {30.0};
828    GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
829    GLfloat green_light[] = {0.1, 0.5, 0.1, 1.0};
830
831    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
832    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
833    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
834    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
835    glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light);
836    glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
837
838    // init table of transfer functions
839    Tcl_InitHashTable(&tfTable, TCL_STRING_KEYS);
840
841    //check if performance query is supported
842    if (PerfQuery::checkQuerySupport()) {
843        //create queries to count number of rendered pixels
844        perf = new PerfQuery();
845    }
846
847    initOffscreenBuffer();    //frame buffer object for offscreen rendering
848
849    //create volume renderer and add volumes to it
850    volRenderer = new VolumeRenderer();
851
852    // create
853    renderContext = new graphics::RenderContext();
854
855    //create a 2D plane renderer
856    planeRenderer = new PlaneRenderer(winWidth, winHeight);
857#if PROTOTYPE
858    make_test_2D_data();
859    planeRenderer->add_plane(plane[0], getTransfunc("default"));
860#endif
861
862    //assert(glGetError()==0);
863
864    TRACE("leaving initGL\n");
865}
866
867#if DO_RLE
868char rle[512*512*3];
869int rleSize;
870
871short offsets[512*512*3];
872int offsetsSize;
873
874static void
875doRle()
876{
877    int len = NanoVis::winWidth*NanoVis::winHeight*3;
878    rleSize = 0;
879    offsetsSize = 0;
880
881    int i = 0;
882    while (i < len) {
883        if (NanoVis::screenBuffer[i] == 0) {
884            int pos = i+1;
885            while ( (pos < len) && (NanoVis::screenBuffer[pos] == 0)) {
886                pos++;
887            }
888            offsets[offsetsSize++] = -(pos - i);
889            i = pos;
890        }
891
892        else {
893            int pos;
894            for (pos = i; (pos < len) && (NanoVis::screenBuffer[pos] != 0); pos++){
895                rle[rleSize++] = NanoVis::screenBuffer[pos];
896            }
897            offsets[offsetsSize++] = (pos - i);
898            i = pos;
899        }
900
901    }
902}
903#endif
904
905// used internally to build up the BMP file header
906// Writes an integer value into the header data structure at pos
907static inline void
908bmpHeaderAddInt(unsigned char* header, int& pos, int data)
909{
910#ifdef WORDS_BIGENDIAN
911    header[pos++] = (data >> 24) & 0xFF;
912    header[pos++] = (data >> 16) & 0xFF;
913    header[pos++] = (data >> 8)  & 0xFF;
914    header[pos++] = (data)       & 0xFF;
915#else
916    header[pos++] = data & 0xff;
917    header[pos++] = (data >> 8) & 0xff;
918    header[pos++] = (data >> 16) & 0xff;
919    header[pos++] = (data >> 24) & 0xff;
920#endif
921}
922
923// INSOO
924// FOR DEBUGGING
925void
926NanoVis::bmpWriteToFile(int frame_number, const char *directory_name)
927{
928    unsigned char header[SIZEOF_BMP_HEADER];
929    int pos = 0;
930    header[pos++] = 'B';
931    header[pos++] = 'M';
932
933    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
934    // on each scan line.  If need be, we add padding to each line.
935    int pad = 0;
936    if ((3*winWidth) % 4 > 0) {
937        pad = 4 - ((3*winWidth) % 4);
938    }
939
940    // file size in bytes
941    int fsize = (3*winWidth+pad)*winHeight + SIZEOF_BMP_HEADER;
942    bmpHeaderAddInt(header, pos, fsize);
943
944    // reserved value (must be 0)
945    bmpHeaderAddInt(header, pos, 0);
946
947    // offset in bytes to start of bitmap data
948    bmpHeaderAddInt(header, pos, SIZEOF_BMP_HEADER);
949
950    // size of the BITMAPINFOHEADER
951    bmpHeaderAddInt(header, pos, 40);
952
953    // width of the image in pixels
954    bmpHeaderAddInt(header, pos, winWidth);
955
956    // height of the image in pixels
957    bmpHeaderAddInt(header, pos, winHeight);
958
959    // 1 plane + (24 bits/pixel << 16)
960    bmpHeaderAddInt(header, pos, 1572865);
961
962    // no compression
963    // size of image for compression
964    bmpHeaderAddInt(header, pos, 0);
965    bmpHeaderAddInt(header, pos, 0);
966
967    // x pixels per meter
968    // y pixels per meter
969    bmpHeaderAddInt(header, pos, 0);
970    bmpHeaderAddInt(header, pos, 0);
971
972    // number of colors used (0 = compute from bits/pixel)
973    // number of important colors (0 = all colors important)
974    bmpHeaderAddInt(header, pos, 0);
975    bmpHeaderAddInt(header, pos, 0);
976
977    // BE CAREFUL: BMP format wants BGR ordering for screen data
978    unsigned char* scr = screenBuffer;
979    for (int row=0; row < winHeight; row++) {
980        for (int col=0; col < winWidth; col++) {
981            unsigned char tmp = scr[2];
982            scr[2] = scr[0];  // B
983            scr[0] = tmp;     // R
984            scr += 3;
985        }
986        scr += pad;  // skip over padding already in screen data
987    }
988
989    FILE* f;
990    char filename[100];
991    if (frame_number >= 0) {
992        if (directory_name)
993            sprintf(filename, "%s/image%03d.bmp", directory_name, frame_number);
994        else
995            sprintf(filename, "/tmp/flow_animation/image%03d.bmp", frame_number);
996
997        TRACE("Writing %s\n", filename);
998        f = fopen(filename, "wb");
999        if (f == 0) {
1000            ERROR("cannot create file\n");
1001        }
1002    } else {
1003        f = fopen("/tmp/image.bmp", "wb");
1004        if (f == 0) {
1005            ERROR("cannot create file\n");
1006        }
1007    }
1008    if (fwrite(header, SIZEOF_BMP_HEADER, 1, f) != 1) {
1009        ERROR("can't write header: short write\n");
1010    }
1011    if (fwrite(screenBuffer, (3*winWidth+pad)*winHeight, 1, f) != 1) {
1012        ERROR("can't write data: short write\n");
1013    }
1014    fclose(f);
1015}
1016
1017void
1018NanoVis::bmpWrite(const char *prefix)
1019{
1020    unsigned char header[SIZEOF_BMP_HEADER];
1021    ssize_t nWritten;
1022    int pos = 0;
1023
1024    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
1025    // on each scan line.  If need be, we add padding to each line.
1026    int pad = 0;
1027    if ((3*winWidth) % 4 > 0) {
1028        pad = 4 - ((3*winWidth) % 4);
1029    }
1030    pad = 0;
1031    int fsize = (3*winWidth+pad)*winHeight + sizeof(header);
1032
1033    char string[200];
1034    sprintf(string, "%s %d\n", prefix, fsize);
1035    nWritten = write(1, string, strlen(string));
1036    assert(nWritten == (ssize_t)strlen(string));
1037    header[pos++] = 'B';
1038    header[pos++] = 'M';
1039
1040    // file size in bytes
1041    bmpHeaderAddInt(header, pos, fsize);
1042
1043    // reserved value (must be 0)
1044    bmpHeaderAddInt(header, pos, 0);
1045
1046    // offset in bytes to start of bitmap data
1047    bmpHeaderAddInt(header, pos, SIZEOF_BMP_HEADER);
1048
1049    // size of the BITMAPINFOHEADER
1050    bmpHeaderAddInt(header, pos, 40);
1051
1052    // width of the image in pixels
1053    bmpHeaderAddInt(header, pos, winWidth);
1054
1055    // height of the image in pixels
1056    bmpHeaderAddInt(header, pos, winHeight);
1057
1058    // 1 plane + (24 bits/pixel << 16)
1059    bmpHeaderAddInt(header, pos, 1572865);
1060
1061    // no compression
1062    // size of image for compression
1063    bmpHeaderAddInt(header, pos, 0);
1064    bmpHeaderAddInt(header, pos, 0);
1065
1066    // x pixels per meter
1067    // y pixels per meter
1068    bmpHeaderAddInt(header, pos, 0);
1069    bmpHeaderAddInt(header, pos, 0);
1070
1071    // number of colors used (0 = compute from bits/pixel)
1072    // number of important colors (0 = all colors important)
1073    bmpHeaderAddInt(header, pos, 0);
1074    bmpHeaderAddInt(header, pos, 0);
1075
1076    // BE CAREFUL: BMP format wants BGR ordering for screen data
1077    unsigned char* scr = screenBuffer;
1078    for (int row=0; row < winHeight; row++) {
1079        for (int col=0; col < winWidth; col++) {
1080            unsigned char tmp = scr[2];
1081            scr[2] = scr[0];  // B
1082            scr[0] = tmp;     // R
1083            scr += 3;
1084        }
1085        scr += pad;  // skip over padding already in screen data
1086    }
1087
1088    nWritten = write(1, header, SIZEOF_BMP_HEADER);
1089    assert(nWritten == SIZEOF_BMP_HEADER);
1090    nWritten = write(1, screenBuffer, (3*winWidth+pad)*winHeight);
1091    assert(nWritten == (3*winWidth+pad)*winHeight);
1092    stats.nFrames++;
1093    stats.nBytes += (3*winWidth+pad)*winHeight;
1094}
1095
1096/*
1097 * ppmWrite --
1098 *
1099 *  Writes the screen image as PPM binary data to the nanovisviewer
1100 *  client.  The PPM binary format is very simple.
1101 *
1102 *      P6 w h 255\n
1103 *      3-byte RGB pixel data.
1104 *
1105 *  The nanovisviewer client (using the TkImg library) will do less work
1106 *  to unpack this format, as opposed to BMP or PNG.  (This doesn't
1107 *  eliminate the need to look into DXT compression performed on the GPU).
1108 *
1109 *      Note that currently the image data from the screen is both row-padded
1110 *      and the scan lines are reversed.  This routine could be made even
1111 *      simpler (faster) if the screen buffer is an array of packed 3-bytes
1112 *      per pixels (no padding) and where the origin is the top-left corner.
1113 */
1114void
1115NanoVis::ppmWrite(const char *prefix)
1116{
1117#define PPM_MAXVAL 255
1118    char header[200];
1119
1120    TRACE("Enter ppmWrite (%dx%d)\n", winWidth, winHeight);
1121    // Generate the PPM binary file header
1122    sprintf(header, "P6 %d %d %d\n", winWidth, winHeight, PPM_MAXVAL);
1123
1124    size_t header_length = strlen(header);
1125    size_t data_length = winWidth * winHeight * 3;
1126
1127    char command[200];
1128    sprintf(command, "%s %lu\n", prefix,
1129            (unsigned long)header_length + data_length);
1130
1131    size_t wordsPerRow = (winWidth * 24 + 31) / 32;
1132    size_t bytesPerRow = wordsPerRow * 4;
1133    size_t rowLength = winWidth * 3;
1134    size_t nRecs = winHeight + 2;
1135
1136    struct iovec *iov;
1137    iov = (struct iovec *)malloc(sizeof(struct iovec) * nRecs);
1138
1139    // Write the nanovisviewer command, then the image header and data.
1140    // Command
1141    iov[0].iov_base = command;
1142    iov[0].iov_len = strlen(command);
1143    // Header of image data
1144    iov[1].iov_base = header;
1145    iov[1].iov_len = header_length;
1146    // Image data.
1147    int y;
1148    unsigned char *srcRowPtr = screenBuffer;
1149    for (y = winHeight + 1; y >= 2; y--) {
1150        iov[y].iov_base = srcRowPtr;
1151        iov[y].iov_len = rowLength;
1152        srcRowPtr += bytesPerRow;
1153    }
1154    if (writev(1, iov, nRecs) < 0) {
1155        ERROR("write failed: %s\n", strerror(errno));
1156    }
1157    free(iov);
1158    stats.nFrames++;
1159    stats.nBytes += (bytesPerRow * winHeight);
1160    TRACE("Leaving ppmWrite (%dx%d)\n", winWidth, winHeight);
1161}
1162
1163void
1164NanoVis::sendDataToClient(const char *command, const char *data, size_t dlen)
1165{
1166    /*
1167      char header[200];
1168
1169      // Generate the PPM binary file header
1170      sprintf(header, "P6 %d %d %d\n", winWidth, winHeight, PPM_MAXVAL);
1171
1172      size_t header_length = strlen(header);
1173      size_t data_length = winWidth * winHeight * 3;
1174
1175      char command[200];
1176      sprintf(command, "%s %lu\n", prefix,
1177      (unsigned long)header_length + data_length);
1178    */
1179
1180    //    size_t wordsPerRow = (winWidth * 24 + 31) / 32;
1181    //    size_t bytesPerRow = wordsPerRow * 4;
1182    //    size_t rowLength = winWidth * 3;
1183    size_t nRecs = 2;
1184
1185    struct iovec *iov = new iovec[nRecs];
1186
1187    // Write the nanovisviewer command, then the image header and data.
1188    // Command
1189    // FIXME: shouldn't have to cast this
1190    iov[0].iov_base = (char *)command;
1191    iov[0].iov_len = strlen(command);
1192    // Data
1193    // FIXME: shouldn't have to cast this
1194    iov[1].iov_base = (char *)data;
1195    iov[1].iov_len = dlen;
1196    if (writev(1, iov, nRecs) < 0) {
1197        ERROR("write failed: %s\n", strerror(errno));
1198    }
1199    delete [] iov;
1200    // stats.nFrames++;
1201    // stats.nBytes += (bytesPerRow * winHeight);
1202}
1203
1204
1205/*----------------------------------------------------*/
1206void
1207NanoVis::idle()
1208{
1209    TRACE("in idle()\n");
1210    glutSetWindow(renderWindow);
1211
1212#ifdef XINETD
1213    xinetdListen();
1214#else
1215    glutPostRedisplay();
1216#endif
1217    TRACE("leaving idle()\n");
1218}
1219
1220void
1221NanoVis::displayOffscreenBuffer()
1222{
1223    TRACE("in display_offscreen_buffer\n");
1224    glEnable(GL_TEXTURE_2D);
1225    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1226    glBindTexture(GL_TEXTURE_2D, _finalColorTex);
1227
1228    glViewport(0, 0, winWidth, winHeight);
1229    glMatrixMode(GL_PROJECTION);
1230    glLoadIdentity();
1231    gluOrtho2D(0, winWidth, 0, winHeight);
1232    glMatrixMode(GL_MODELVIEW);
1233    glLoadIdentity();
1234
1235    glColor3f(1.,1.,1.);                //MUST HAVE THIS LINE!!!
1236    glBegin(GL_QUADS);
1237    {
1238        glTexCoord2f(0, 0); glVertex2f(0, 0);
1239        glTexCoord2f(1, 0); glVertex2f(winWidth, 0);
1240        glTexCoord2f(1, 1); glVertex2f(winWidth, winHeight);
1241        glTexCoord2f(0, 1); glVertex2f(0, winHeight);
1242    }
1243    glEnd();
1244    TRACE("leaving display_offscreen_buffer\n");
1245}
1246
1247#if 0
1248//oddeven sort on GPU
1249static void
1250sortstep()
1251{
1252    // perform one step of the current sorting algorithm
1253
1254#ifdef notdef
1255    // swap buffers
1256    int sourceBuffer = targetBuffer;
1257    targetBuffer = (targetBuffer+1)%2;
1258    int pstage = (1<<stage);
1259    int ppass  = (1<<pass);
1260    int activeBitonicShader = 0;
1261
1262#ifdef _WIN32
1263    buffer->BindBuffer(wglTargets[sourceBuffer]);
1264#else
1265    buffer->BindBuffer(glTargets[sourceBuffer]);
1266#endif
1267    if (buffer->IsDoubleBuffered()) glDrawBuffer(glTargets[targetBuffer]);
1268#endif
1269
1270    checkGLError("after db");
1271
1272    int pstage = (1<<stage);
1273    int ppass  = (1<<pass);
1274    //int activeBitonicShader = 0;
1275
1276    // switch on correct sorting shader
1277    oddevenMergeSort.bind();
1278    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param1"), float(pstage+pstage),
1279                   float(ppass%pstage), float((pstage+pstage)-(ppass%pstage)-1));
1280    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param2"),
1281                   float(psys_width), float(psys_height), float(ppass));
1282    glUniform1iARB(oddevenMergeSort.getUniformLocation("Data"), 0);
1283    staticdebugmsg("sort","stage "<<pstage<<" pass "<<ppass);
1284
1285    // This clear is not necessary for sort to function. But if we are in
1286    // interactive mode unused parts of the texture that are visible will look
1287    // bad.
1288#ifdef notdef
1289    if (!perfTest) glClear(GL_COLOR_BUFFER_BIT);
1290
1291    buffer->Bind();
1292    buffer->EnableTextureTarget();
1293#endif
1294
1295    // Initiate the sorting step on the GPU a full-screen quad
1296    glBegin(GL_QUADS);
1297    {
1298#ifdef notdef
1299        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f);
1300        glVertex2f(-1.0f,-1.0f);
1301        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f);
1302        glVertex2f(1.0f,-1.0f);
1303        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f);
1304        glVertex2f(1.0f,1.0f);
1305        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f);
1306        glVertex2f(-1.0f,1.0f);
1307#endif
1308        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f);
1309        glVertex2f(0.,0.);
1310        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f);
1311        glVertex2f(float(psys_width), 0.);
1312        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f);
1313        glVertex2f(float(psys_width), float(psys_height));
1314        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f);
1315        glVertex2f(0., float(psys_height));
1316    }
1317    glEnd();
1318
1319    // switch off sorting shader
1320    oddevenMergeSort.release();
1321
1322    //buffer->DisableTextureTarget();
1323
1324    //assert(glGetError()==0);
1325}
1326#endif
1327
1328static void
1329draw3dAxis()
1330{
1331    glDisable(GL_TEXTURE_2D);
1332    glEnable(GL_DEPTH_TEST);
1333
1334    //draw axes
1335    GLUquadric *obj;
1336
1337    obj = gluNewQuadric();
1338
1339    glDepthFunc(GL_LESS);
1340    glEnable(GL_COLOR_MATERIAL);
1341    glEnable(GL_DEPTH_TEST);
1342    glDisable(GL_BLEND);
1343
1344    int segments = 50;
1345
1346    glColor3f(0.8, 0.8, 0.8);
1347    glPushMatrix();
1348    glTranslatef(0.4, 0., 0.);
1349    glRotatef(90, 1, 0, 0);
1350    glRotatef(180, 0, 1, 0);
1351    glScalef(0.0005, 0.0005, 0.0005);
1352    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'x');
1353    glPopMatrix();
1354
1355    glPushMatrix();
1356    glTranslatef(0., 0.4, 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, 'y');
1361    glPopMatrix();
1362
1363    glPushMatrix();
1364    glTranslatef(0., 0., 0.4);
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, 'z');
1369    glPopMatrix();
1370
1371    glEnable(GL_LIGHTING);
1372    glEnable(GL_LIGHT0);
1373
1374    //glColor3f(0.2, 0.2, 0.8);
1375    glPushMatrix();
1376    glutSolidSphere(0.02, segments, segments );
1377    glPopMatrix();
1378
1379    glPushMatrix();
1380    glRotatef(-90, 1, 0, 0);
1381    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1382    glPopMatrix();
1383
1384    glPushMatrix();
1385    glTranslatef(0., 0.3, 0.);
1386    glRotatef(-90, 1, 0, 0);
1387    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1388    glPopMatrix();
1389
1390    glPushMatrix();
1391    glRotatef(90, 0, 1, 0);
1392    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1393    glPopMatrix();
1394
1395    glPushMatrix();
1396    glTranslatef(0.3, 0., 0.);
1397    glRotatef(90, 0, 1, 0);
1398    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1399    glPopMatrix();
1400
1401    glPushMatrix();
1402    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1403    glPopMatrix();
1404
1405    glPushMatrix();
1406    glTranslatef(0., 0., 0.3);
1407    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1408    glPopMatrix();
1409
1410    glDisable(GL_LIGHTING);
1411    glDisable(GL_DEPTH_TEST);
1412    gluDeleteQuadric(obj);
1413
1414    glEnable(GL_TEXTURE_2D);
1415    glDisable(GL_DEPTH_TEST);
1416}
1417
1418void NanoVis::update()
1419{
1420    if (volRenderer->_volumeInterpolator->isStarted()) {
1421        struct timeval clock;
1422        gettimeofday(&clock, NULL);
1423        double elapsed_time;
1424
1425        elapsed_time = clock.tv_sec + clock.tv_usec/1000000.0 -
1426            volRenderer->_volumeInterpolator->getStartTime();
1427
1428        TRACE("%lf %lf\n", elapsed_time,
1429               volRenderer->_volumeInterpolator->getInterval());
1430        float fraction;
1431        float f;
1432
1433        f = fmod((float) elapsed_time, (float)volRenderer->_volumeInterpolator->getInterval());
1434        if (f == 0.0) {
1435            fraction = 0.0f;
1436        } else {
1437            fraction = f / volRenderer->_volumeInterpolator->getInterval();
1438        }
1439        TRACE("fraction : %f\n", fraction);
1440        volRenderer->_volumeInterpolator->update(fraction);
1441    }
1442}
1443
1444void
1445NanoVis::setVolumeRanges()
1446{
1447    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1448
1449    TRACE("in SetVolumeRanges\n");
1450    xMin = yMin = zMin = wMin = DBL_MAX;
1451    xMax = yMax = zMax = wMax = -DBL_MAX;
1452    Tcl_HashEntry *hPtr;
1453    Tcl_HashSearch iter;
1454    for (hPtr = Tcl_FirstHashEntry(&volumeTable, &iter); hPtr != NULL;
1455         hPtr = Tcl_NextHashEntry(&iter)) {
1456        Volume *volPtr = (Volume *)Tcl_GetHashValue(hPtr);
1457        if (xMin > volPtr->xAxis.min()) {
1458            xMin = volPtr->xAxis.min();
1459        }
1460        if (xMax < volPtr->xAxis.max()) {
1461            xMax = volPtr->xAxis.max();
1462        }
1463        if (yMin > volPtr->yAxis.min()) {
1464            yMin = volPtr->yAxis.min();
1465        }
1466        if (yMax < volPtr->yAxis.max()) {
1467            yMax = volPtr->yAxis.max();
1468        }
1469        if (zMin > volPtr->zAxis.min()) {
1470            zMin = volPtr->zAxis.min();
1471        }
1472        if (zMax < volPtr->zAxis.max()) {
1473            zMax = volPtr->zAxis.max();
1474        }
1475        if (wMin > volPtr->wAxis.min()) {
1476            wMin = volPtr->wAxis.min();
1477        }
1478        if (wMax < volPtr->wAxis.max()) {
1479            wMax = volPtr->wAxis.max();
1480        }
1481    }
1482    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1483        grid->xAxis.SetScale(xMin, xMax);
1484    }
1485    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1486        grid->yAxis.SetScale(yMin, yMax);
1487    }
1488    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1489        grid->zAxis.SetScale(zMin, zMax);
1490    }
1491    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1492        Volume::valueMin = wMin;
1493        Volume::valueMax = wMax;
1494    }
1495    Volume::updatePending = false;
1496    TRACE("leaving SetVolumeRanges\n");
1497}
1498
1499void
1500NanoVis::setHeightmapRanges()
1501{
1502    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1503
1504    TRACE("in setHeightmapRanges\n");
1505    xMin = yMin = zMin = wMin = DBL_MAX;
1506    xMax = yMax = zMax = wMax = -DBL_MAX;
1507    Tcl_HashEntry *hPtr;
1508    Tcl_HashSearch iter;
1509    for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1510         hPtr = Tcl_NextHashEntry(&iter)) {
1511        HeightMap *hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1512        if (xMin > hmPtr->xAxis.min()) {
1513            xMin = hmPtr->xAxis.min();
1514        }
1515        if (xMax < hmPtr->xAxis.max()) {
1516            xMax = hmPtr->xAxis.max();
1517        }
1518        if (yMin > hmPtr->yAxis.min()) {
1519            yMin = hmPtr->yAxis.min();
1520        }
1521        if (yMax < hmPtr->yAxis.max()) {
1522            yMax = hmPtr->yAxis.max();
1523        }
1524        if (zMin > hmPtr->zAxis.min()) {
1525            zMin = hmPtr->zAxis.min();
1526        }
1527        if (zMax < hmPtr->zAxis.max()) {
1528            zMax = hmPtr->zAxis.max();
1529        }
1530        if (wMin > hmPtr->wAxis.min()) {
1531            wMin = hmPtr->wAxis.min();
1532        }
1533        if (wMax < hmPtr->wAxis.max()) {
1534            wMax = hmPtr->wAxis.max();
1535        }
1536    }
1537    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1538        grid->xAxis.SetScale(xMin, xMax);
1539    }
1540    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1541        grid->yAxis.SetScale(yMin, yMax);
1542    }
1543    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1544        grid->zAxis.SetScale(zMin, zMax);
1545    }
1546    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1547        HeightMap::valueMin = grid->yAxis.min();
1548        HeightMap::valueMax = grid->yAxis.max();
1549    }
1550    for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1551         hPtr = Tcl_NextHashEntry(&iter)) {
1552        HeightMap *hmPtr;
1553        hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1554        hmPtr->MapToGrid(grid);
1555    }
1556    HeightMap::updatePending = false;
1557    TRACE("leaving setHeightmapRanges\n");
1558}
1559
1560/*----------------------------------------------------*/
1561void
1562NanoVis::display()
1563{
1564    TRACE("in display\n");
1565#ifdef notdef
1566    if (flags & MAP_FLOWS) {
1567        xMin = yMin = zMin = wMin = FLT_MAX, magMin = DBL_MAX;
1568        xMax = yMax = zMax = wMax = -FLT_MAX, magMax = -DBL_MAX;
1569    }
1570#endif
1571    if (flags & MAP_FLOWS) {
1572        MapFlows();
1573        grid->xAxis.SetScale(xMin, xMax);
1574        grid->yAxis.SetScale(yMin, yMax);
1575        grid->zAxis.SetScale(zMin, zMax);
1576    }
1577    //assert(glGetError()==0);
1578    if (HeightMap::updatePending) {
1579        setHeightmapRanges();
1580    }
1581    if (Volume::updatePending) {
1582        setVolumeRanges();
1583    }
1584    TRACE("in display: glClear\n");
1585    //start final rendering
1586    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
1587
1588    if (volumeMode) {
1589        TRACE("in display: volumeMode\n");
1590        //3D rendering mode
1591        // TBD..
1592        //glEnable(GL_TEXTURE_2D);
1593        glEnable(GL_DEPTH_TEST);
1594
1595        //camera setting activated
1596        cam->initialize();
1597
1598        //set up the orientation of items in the scene.
1599        glPushMatrix();
1600
1601        switch (updir) {
1602        case X_POS:
1603            glRotatef(90, 0, 0, 1);
1604            glRotatef(90, 1, 0, 0);
1605            break;
1606        case Y_POS:
1607            // this is the default
1608            break;
1609        case Z_POS:
1610            glRotatef(-90, 1, 0, 0);
1611            glRotatef(-90, 0, 0, 1);
1612            break;
1613        case X_NEG:
1614            glRotatef(-90, 0, 0, 1);
1615            break;
1616        case Y_NEG:
1617            glRotatef(180, 0, 0, 1);
1618            glRotatef(-90, 0, 1, 0);
1619            break;
1620        case Z_NEG:
1621            glRotatef(90, 1, 0, 0);
1622            break;
1623        }
1624
1625        // TBD : This will be removed after being sure that all the functions work well.
1626        //glPushMatrix();
1627
1628        //now render things in the scene
1629        if (axisOn) {
1630            draw3dAxis();
1631        }
1632        if (grid->isVisible()) {
1633            grid->render();
1634        }
1635        if ((licRenderer != NULL) && (licRenderer->active())) {
1636            licRenderer->render();
1637        }
1638
1639        if ((velocityArrowsSlice != NULL) && (velocityArrowsSlice->enabled())) {
1640            velocityArrowsSlice->render();
1641        }
1642#ifdef notdef
1643        if ((flowVisRenderer != NULL) && (flowVisRenderer->active())) {
1644            flowVisRenderer->render();
1645        }
1646#endif
1647        if (flowTable.numEntries > 0) {
1648            RenderFlows();
1649        }
1650
1651        //soft_display_verts();
1652        //perf->enable();
1653        //perf->disable();
1654        //TRACE("particle pixels: %d\n", perf->get_pixel_count());
1655        //perf->reset();
1656
1657        //perf->enable();
1658        volRenderer->renderAll();
1659        //perf->disable();
1660
1661        if (heightmapTable.numEntries > 0) {
1662            TRACE("in display: render heightmap\n");
1663            Tcl_HashEntry *hPtr;
1664            Tcl_HashSearch iter;
1665            for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1666                 hPtr = Tcl_NextHashEntry(&iter)) {
1667                HeightMap *hmPtr;
1668                hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1669                if (hmPtr->isVisible()) {
1670                    hmPtr->render(renderContext);
1671                }
1672            }
1673        }
1674        glPopMatrix();
1675    } else {
1676        //2D rendering mode
1677        perf->enable();
1678        planeRenderer->render();
1679        perf->disable();
1680    }
1681
1682    perf->reset();
1683    CHECK_FRAMEBUFFER_STATUS();
1684    TRACE("leaving display\n");
1685}
1686
1687#ifndef XINETD
1688void
1689NanoVis::mouse(int button, int state, int x, int y)
1690{
1691    if (button == GLUT_LEFT_BUTTON) {
1692        if (state == GLUT_DOWN) {
1693            left_last_x = x;
1694            left_last_y = y;
1695            left_down = true;
1696            right_down = false;
1697        } else {
1698            left_down = false;
1699            right_down = false;
1700        }
1701    } else {
1702        //TRACE("right mouse\n");
1703
1704        if (state == GLUT_DOWN) {
1705            //TRACE("right mouse down\n");
1706            right_last_x = x;
1707            right_last_y = y;
1708            left_down = false;
1709            right_down = true;
1710        } else {
1711            //TRACE("right mouse up\n");
1712            left_down = false;
1713            right_down = false;
1714        }
1715    }
1716}
1717
1718void
1719NanoVis::updateRot(int delta_x, int delta_y)
1720{
1721    Vector3 angle;
1722
1723    angle = cam->rotate();
1724    angle.x += delta_x;
1725    angle.y += delta_y;
1726
1727    if (angle.x > 360.0) {
1728        angle.x -= 360.0;
1729    } else if(angle.x < -360.0) {
1730        angle.x += 360.0;
1731    }
1732    if (angle.y > 360.0) {
1733        angle.y -= 360.0;
1734    } else if(angle.y < -360.0) {
1735        angle.y += 360.0;
1736    }
1737    cam->rotate(angle);
1738}
1739
1740void
1741NanoVis::updateTrans(int delta_x, int delta_y, int delta_z)
1742{
1743    cam->x(cam->x() + delta_x * 0.03);
1744    cam->y(cam->y() + delta_y * 0.03);
1745    cam->z(cam->z() + delta_z * 0.03);
1746}
1747
1748#ifdef notdef
1749static
1750void addVectorField(const char* filename, const char* vf_name,
1751                    const char* plane_name1, const char* plane_name2,
1752                    const Vector4& color1, const Vector4& color2)
1753{
1754    Rappture::Outcome result;
1755    Rappture::Buffer buf;
1756
1757    buf.load(filename);
1758    int n = NanoVis::n_volumes;
1759    if (load_vector_stream2(result, n, buf.size(), buf.bytes())) {
1760        Volume *volPtr = NanoVis::volume[n];
1761        if (volPtr != NULL) {
1762            volPtr->numSlices(256-n);
1763            // volPtr->numSlices(512-n);
1764            volPtr->disableCutplane(0);
1765            volPtr->disableCutplane(1);
1766            volPtr->disableCutplane(2);
1767            volPtr->transferFunction(NanoVis::getTransfunc("default"));
1768
1769            float dx0 = -0.5;
1770            float dy0 = -0.5*volPtr->height/volPtr->width;
1771            float dz0 = -0.5*volPtr->depth/volPtr->width;
1772            volPtr->move(Vector3(dx0, dy0, dz0));
1773            //volPtr->data(true);
1774            volPtr->data(false);
1775            NanoVis::flowVisRenderer->addVectorField(vf_name, volPtr,
1776                volPtr->location(),
1777                1.0f,
1778                volPtr->height / (float)volPtr->width,
1779                volPtr->depth  / (float)volPtr->width,
1780                1.0f);
1781            NanoVis::flowVisRenderer->activateVectorField(vf_name);
1782
1783            //////////////////////////////////
1784            // ADD Particle Injection Plane1
1785            NanoVis::flowVisRenderer->addPlane(vf_name, plane_name1);
1786            NanoVis::flowVisRenderer->setPlaneAxis(vf_name, plane_name1, 0);
1787            NanoVis::flowVisRenderer->setPlanePos(vf_name, plane_name1, 0.9);
1788            NanoVis::flowVisRenderer->setParticleColor(vf_name, plane_name1, color1);
1789            // ADD Particle Injection Plane2
1790            NanoVis::flowVisRenderer->addPlane(vf_name, plane_name2);
1791            NanoVis::flowVisRenderer->setPlaneAxis(vf_name, plane_name2, 0);
1792            NanoVis::flowVisRenderer->setPlanePos(vf_name, plane_name2, 0.2);
1793            NanoVis::flowVisRenderer->setParticleColor(vf_name, plane_name2, color2);
1794            NanoVis::flowVisRenderer->initialize(vf_name);
1795
1796            NanoVis::flowVisRenderer->activatePlane(vf_name, plane_name1);
1797            NanoVis::flowVisRenderer->activatePlane(vf_name, plane_name2);
1798
1799            NanoVis::licRenderer->
1800                setVectorField(volPtr->id,
1801                               *(volPtr->get_location()),
1802                               1.0f / volPtr->aspectRatioWidth,
1803                               1.0f / volPtr->aspectRatioHeight,
1804                               1.0f / volPtr->aspectRatioDepth,
1805                               volPtr->wAxis.max());
1806        }
1807    }
1808    //NanoVis::initParticle();
1809}
1810#endif
1811
1812void
1813NanoVis::keyboard(unsigned char key, int x, int y)
1814{
1815#ifdef EVENTLOG
1816    if (log) {
1817        float param[3];
1818        param[0] = cam->x();
1819        param[1] = cam->y();
1820        param[2] = cam->z();
1821        Event* tmp = new Event(EVENT_MOVE, param, NvGetTimeInterval());
1822        tmp->write(event_log);
1823        delete tmp;
1824    }
1825#endif
1826
1827    switch (key) {
1828    case 'a' :
1829        {
1830            TRACE("flowvis active\n");
1831            char cmd[] = {
1832                "foreach flow [flow names] {\n"
1833                "    $flow configure -hide no -slice yes\n"
1834                "}\n"
1835            };
1836            Tcl_Eval(interp, cmd);
1837#ifdef notdef
1838            NanoVis::flowVisRenderer->active(true);
1839            NanoVis::licRenderer->active(true);
1840#endif
1841        }
1842        break;
1843    case 'd' :
1844        {
1845            TRACE("flowvis deactived\n");
1846            char cmd[] = {
1847                "foreach flow [flow names] {\n"
1848                "    $flow configure -hide yes -slice no\n"
1849                "}\n"
1850            };
1851            Tcl_Eval(interp, cmd);
1852#ifdef notdef
1853            NanoVis::flowVisRenderer->active(false);
1854            NanoVis::licRenderer->active(false);
1855#endif
1856        }
1857        break;
1858    case '1' :
1859        {
1860            TRACE("add vector field\n");
1861            char cmd[] = {
1862                "flow create flow1\n"
1863                "flow1 data file data/flowvis_dx_files/jwire/J-wire-vec.dx 3\n"
1864                "flow1 particles add plane1 -color { 0 0 1 1 }\n"
1865                "flow1 particles add plane2 -color { 0 1 1 1 }\n"
1866            };
1867            Tcl_Eval(interp, cmd);
1868#ifdef notdef
1869            addVectorField("data/flowvis_dx_files/jwire/J-wire-vec.dx",
1870                           "vf_name2", "plane_name1", "plane_name2", Vector4(0, 0, 1, 1), Vector4(0, 1, 1, 1));
1871#endif
1872        }
1873        break;
1874    case '2' :
1875        {
1876            char cmd[] = {
1877                "flow create flow2\n"
1878                "flow2 data file data/flowvis_dx_files/3DWireLeakage/SiO2/SiO2.dx 3\n"
1879                "flow2 particles add plane1 -color { 1 0 0 1 }\n"
1880                "flow2 particles add plane2 -color { 1 1 0 1 }\n"
1881            };
1882            Tcl_Eval(interp, cmd);
1883            TRACE("add vector field\n");
1884#ifdef notdef
1885            addVectorField("data/flowvis_dx_files/3DWireLeakage/SiO2/SiO2.dx",
1886                           "vf_name1", "plane_name1", "plane_name2", Vector4(1, 0, 0, 1), Vector4(1, 1, 0, 1));
1887#endif
1888        }
1889        break;
1890    case '3':
1891        {
1892            TRACE("activate\n");
1893            char cmd[] = {
1894                "flow1 particles add plane2 -hide no\n"
1895            };
1896            Tcl_Eval(interp, cmd);
1897#ifdef notdef
1898            NanoVis::flowVisRenderer->activatePlane("vf_name1", "plane_name2");
1899#endif
1900        }
1901        break;
1902    case '4' :
1903        {
1904            TRACE("deactivate\n");
1905            char cmd[] = {
1906                "flow1 particles add plane2 -hide yes\n"
1907            };
1908            Tcl_Eval(interp, cmd);
1909#ifdef notdef
1910            NanoVis::flowVisRenderer->deactivatePlane("vf_name1", "plane_name2");
1911#endif
1912        }
1913        break;
1914    case '5' :
1915        {
1916            TRACE("vector field deleted (vf_name2)\n");
1917            char cmd[] = {
1918                "flow delete flow2\n"
1919            };
1920            Tcl_Eval(interp, cmd);
1921#ifdef notdef
1922            NanoVis::flowVisRenderer->removeVectorField("vf_name2");
1923#endif
1924        }
1925        break;
1926    case '6' :
1927        {
1928            TRACE("add device shape\n");
1929            char cmd[] = {
1930                "flow1 box add box1 -corner1 {0 0 0} -corner2 {30 3 3} -color { 1 0 0 1 }\n"
1931                "flow1 box add box2 -corner1 {0 -1 -1} -corner2 {30 4 4} -color { 0 1 0 1 }\n"
1932                "flow1 box add box3 -corner1 {10 -1.5 -1} -corner2 {20 4.5 4.5} -color { 0 0 1 1 }\n"
1933            };
1934            Tcl_Eval(interp, cmd);
1935#ifdef notdef
1936            NvDeviceShape shape;
1937            shape.min.set(0, 0, 0);
1938            shape.max.set(30, 3, 3);
1939            shape.color.set(1, 0, 0, 1);
1940            NanoVis::flowVisRenderer->addDeviceShape("vf_name1", "device1", shape);
1941            shape.min.set(0, -1, -1);
1942            shape.max.set(30, 4, 4);
1943            shape.color.set(0, 1, 0, 1);
1944            NanoVis::flowVisRenderer->addDeviceShape("vf_name1", "device2", shape);
1945            shape.min.set(10, -1.5, -1);
1946            shape.max.set(20, 4.5, 4.5);
1947            shape.color.set(0, 0, 1, 1);
1948            NanoVis::flowVisRenderer->addDeviceShape("vf_name1", "device3", shape);
1949            NanoVis::flowVisRenderer->activateDeviceShape("vf_name1");
1950#endif
1951        }
1952        break;
1953    case '7' :
1954        {
1955            TRACE("hide shape \n");
1956            char cmd[] = {
1957                "flow1 box configure box1 -hide yes\n"
1958            };
1959            Tcl_Eval(interp, cmd);
1960#ifdef notdef
1961            NanoVis::flowVisRenderer->deactivateDeviceShape("vf_name1");
1962#endif
1963        }
1964        break;
1965    case '8' :
1966        {
1967            TRACE("show shape\n");
1968            char cmd[] = {
1969                "flow1 box configure box1 -hide no\n"
1970            };
1971            Tcl_Eval(interp, cmd);
1972#ifdef notdef
1973            NanoVis::flowVisRenderer->activateDeviceShape("vf_name1");
1974#endif
1975        }
1976        break;
1977    case '9' :
1978        {
1979            TRACE("show a shape \n");
1980            char cmd[] = {
1981                "flow1 box configure box3 -hide no\n"
1982            };
1983            Tcl_Eval(interp, cmd);
1984#ifdef notdef
1985            NanoVis::flowVisRenderer->activateDeviceShape("vf_name1", "device3");
1986#endif
1987        }
1988        break;
1989    case '0' :
1990        {
1991            TRACE("delete a shape \n");
1992            char cmd[] = {
1993                "flow1 box delete box3\n"
1994            };
1995            Tcl_Eval(interp, cmd);
1996#ifdef notdef
1997            NanoVis::flowVisRenderer->deactivateDeviceShape("vf_name1", "device3");
1998#endif
1999        }
2000        break;
2001    case 'r' :
2002        {
2003            TRACE("reset \n");
2004            char cmd[] = {
2005                "flow reset\n"
2006            };
2007            Tcl_Eval(interp, cmd);
2008#ifdef notdef
2009            NanoVis::flowVisRenderer->reset();
2010            NanoVis::licRenderer->reset();
2011#endif
2012        }
2013        break;
2014    }
2015}
2016
2017void
2018NanoVis::motion(int x, int y)
2019{
2020    int old_x, old_y;
2021
2022    if (left_down) {
2023        old_x = left_last_x;
2024        old_y = left_last_y;
2025    } else if (right_down) {
2026        old_x = right_last_x;
2027        old_y = right_last_y;
2028    }
2029
2030    int delta_x = x - old_x;
2031    int delta_y = y - old_y;
2032
2033    //more coarse event handling
2034    //if(abs(delta_x)<10 && abs(delta_y)<10)
2035    //return;
2036
2037    if (left_down) {
2038        left_last_x = x;
2039        left_last_y = y;
2040
2041        updateRot(-delta_y, -delta_x);
2042    } else if (right_down) {
2043        //TRACE("right mouse motion (%d,%d)\n", x, y);
2044
2045        right_last_x = x;
2046        right_last_y = y;
2047
2048        updateTrans(0, 0, delta_x);
2049    }
2050
2051#ifdef EVENTLOG
2052    Vector3 angle = cam->rotate();
2053    Event* tmp = new Event(EVENT_ROTATE, &angle, NvGetTimeInterval());
2054    tmp->write(event_log);
2055    delete tmp;
2056#endif
2057    glutPostRedisplay();
2058}
2059
2060#endif /*XINETD*/
2061
2062void
2063NanoVis::render()
2064{
2065
2066#ifdef notdef
2067    if ((NanoVis::licRenderer != NULL) && (NanoVis::licRenderer->active())) {
2068        NanoVis::licRenderer->convolve();
2069    }
2070#else
2071    if (NanoVis::licRenderer != NULL) {
2072        NanoVis::licRenderer->convolve();
2073    }
2074#endif
2075
2076#ifdef notdef
2077    if ((NanoVis::flowVisRenderer != NULL) && (NanoVis::flowVisRenderer->active())) {
2078        NanoVis::flowVisRenderer->advect();
2079    }
2080#endif
2081    NanoVis::update();
2082    display();
2083    glutSwapBuffers();
2084}
2085
2086void
2087NanoVis::resize(int x, int y)
2088{
2089    glViewport(0, 0, x, y);
2090}
2091
2092void
2093NanoVis::xinetdListen(void)
2094{
2095    NanoVis::flags &= ~REDRAW_PENDING;
2096
2097    TRACE("Enter xinetdListen\n");
2098
2099    int flags = fcntl(0, F_GETFL, 0);
2100    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2101
2102    int status = TCL_OK;
2103
2104    //  Read and execute as many commands as we can from stdin...
2105
2106    int nCommands = 0;
2107    bool isComplete = false;
2108    while ((!feof(NanoVis::stdin)) && (status == TCL_OK)) {
2109        //
2110        //  Read the next command from the buffer.  First time through we
2111        //  block here and wait if necessary until a command comes in.
2112        //
2113        //  BE CAREFUL: Read only one command, up to a newline.  The "volume
2114        //  data follows" command needs to be able to read the data
2115        //  immediately following the command, and we shouldn't consume it
2116        //  here.
2117        //
2118        TRACE("in xinetdListen: EOF=%d\n", feof(NanoVis::stdin));
2119        while (!feof(NanoVis::stdin)) {
2120            int c = fgetc(NanoVis::stdin);
2121            char ch;
2122            if (c <= 0) {
2123                if (errno == EWOULDBLOCK) {
2124                    break;
2125                }
2126                doExit(100);
2127            }
2128            ch = (char)c;
2129            Tcl_DStringAppend(&cmdbuffer, &ch, 1);
2130            if (ch == '\n') {
2131                isComplete = Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer));
2132                if (isComplete) {
2133                    break;
2134                }
2135            }
2136        }
2137        // no command? then we're done for now
2138        if (Tcl_DStringLength(&cmdbuffer) == 0) {
2139            break;
2140        }
2141        if (isComplete) {
2142            // back to original flags during command evaluation...
2143            fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2144            status = executeCommand(interp, &cmdbuffer);
2145            // non-blocking for next read -- we might not get anything
2146            fcntl(0, F_SETFL, flags | O_NONBLOCK);
2147            isComplete = false;
2148            nCommands++;
2149            CHECK_FRAMEBUFFER_STATUS();
2150        }
2151    }
2152    fcntl(0, F_SETFL, flags);
2153
2154    if (status != TCL_OK) {
2155        const char *string;
2156        int nBytes;
2157
2158        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
2159        TRACE("errorInfo=(%s)\n", string);
2160        nBytes = strlen(string);
2161        struct iovec iov[3];
2162        iov[0].iov_base = (char *)"NanoVis Server Error: ";
2163        iov[0].iov_len = strlen((char *)iov[0].iov_base);
2164        iov[1].iov_base = (char *)string;
2165        iov[1].iov_len = nBytes;
2166        iov[2].iov_len = 1;
2167        iov[2].iov_base = (char *)'\n';
2168        if (writev(1, iov, 3) < 0) {
2169            ERROR("write failed: %s\n", strerror(errno));
2170        }
2171        TRACE("Leaving xinetd_listen on ERROR\n");
2172        return;
2173    }
2174    if (feof(NanoVis::stdin)) {
2175        doExit(90);
2176    }
2177
2178    NanoVis::update();
2179
2180    NanoVis::offscreenBufferCapture();  //enable offscreen render
2181
2182    NanoVis::display();
2183
2184    // INSOO
2185#ifdef XINETD
2186    NanoVis::readScreen();
2187    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2188#else
2189    NanoVis::displayOffscreenBuffer(); //display the final rendering on screen
2190    NanoVis::readScreen();
2191    glutSwapBuffers();
2192#endif
2193
2194    if (feof(NanoVis::stdin)) {
2195        doExit(90);
2196    }
2197#if DO_RLE
2198    do_rle();
2199    int sizes[2] = {  offsets_size*sizeof(offsets[0]), rle_size };
2200    TRACE("Writing %d,%d\n", sizes[0], sizes[1]);
2201    write(1, &sizes, sizeof(sizes));
2202    write(1, offsets, offsets_size*sizeof(offsets[0]));
2203    write(1, rle, rle_size);    //unsigned byte
2204#else
2205    NanoVis::ppmWrite("\nnv>image -type image -bytes");
2206#endif
2207    TRACE("Leaving xinetd_listen OK\n");
2208}
2209
2210
2211/*----------------------------------------------------*/
2212int
2213main(int argc, char **argv)
2214{
2215    const char *path;
2216    char *newPath;
2217    struct timeval tv;
2218
2219    newPath = NULL;
2220    path = NULL;
2221    NanoVis::stdin = stdin;
2222
2223    fprintf(stdout, "NanoVis %s\n", NANOVIS_VERSION);
2224    fflush(stdout);
2225
2226    openlog("nanovis", LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
2227    gettimeofday(&tv, NULL);
2228    stats.start = tv;
2229
2230    /* Initialize GLUT here so it can parse and remove GLUT-specific
2231     * command-line options before we parse the command-line below. */
2232    glutInit(&argc, argv);
2233    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
2234    glutInitWindowSize(NanoVis::winWidth, NanoVis::winHeight);
2235    glutInitWindowPosition(10, 10);
2236    NanoVis::renderWindow = glutCreateWindow("nanovis");
2237    glutIdleFunc(NanoVis::idle);
2238
2239#ifndef XINETD
2240    glutMouseFunc(NanoVis::mouse);
2241    glutMotionFunc(NanoVis::motion);
2242    glutKeyboardFunc(NanoVis::keyboard);
2243    glutReshapeFunc(NanoVis::resize);
2244    glutDisplayFunc(NanoVis::render);
2245#else
2246    glutDisplayFunc(NanoVis::display);
2247    glutReshapeFunc(NanoVis::resizeOffscreenBuffer);
2248#endif
2249
2250    while (1) {
2251        static struct option long_options[] = {
2252            {"infile",  required_argument, NULL, 0},
2253            {"path",    required_argument, NULL, 2},
2254            {"debug",   no_argument,       NULL, 3},
2255            {"record",  required_argument, NULL, 4},
2256            {0, 0, 0, 0}
2257        };
2258        int option_index = 0;
2259        int c;
2260
2261        c = getopt_long(argc, argv, ":dp:i:l:r:", long_options, &option_index);
2262        if (c == -1) {
2263            break;
2264        }
2265        switch (c) {
2266        case '?':
2267            fprintf(stderr, "unknown option -%c\n", optopt);
2268            return 1;
2269        case ':':
2270            if (optopt < 4) {
2271                fprintf(stderr, "argument missing for --%s option\n",
2272                        long_options[optopt].name);
2273            } else {
2274                fprintf(stderr, "argument missing for -%c option\n", optopt);
2275            }
2276            return 1;
2277        case 2:
2278        case 'p':
2279            path = optarg;
2280            break;
2281        case 3:
2282        case 'd':
2283            NanoVis::debugFlag = true;
2284            break;
2285        case 0:
2286        case 'i':
2287            NanoVis::stdin = fopen(optarg, "r");
2288            if (NanoVis::stdin == NULL) {
2289                perror(optarg);
2290                return 2;
2291            }
2292            break;
2293        case 4:
2294        case 'r':
2295            Tcl_DString ds;
2296            char buf[200];
2297
2298            Tcl_DStringInit(&ds);
2299            Tcl_DStringAppend(&ds, optarg, -1);
2300            sprintf(buf, ".%d", getpid());
2301            Tcl_DStringAppend(&ds, buf, -1);
2302            NanoVis::recfile = fopen(Tcl_DStringValue(&ds), "w");
2303            if (NanoVis::recfile == NULL) {
2304                perror(optarg);
2305                return 2;
2306            }
2307            break;
2308        default:
2309            fprintf(stderr,"unknown option '%c'.\n", c);
2310            return 1;
2311        }
2312    }     
2313    if (path == NULL) {
2314        char *p;
2315
2316        // See if we can derive the path from the location of the program.
2317        // Assume program is in the form <path>/bin/nanovis.
2318
2319#ifdef XINETD
2320        path = argv[0];
2321        p = strrchr((char *)path, '/');
2322        if (p != NULL) {
2323            *p = '\0';
2324            p = strrchr((char *)path, '/');
2325        }
2326        if (p == NULL) {
2327            TRACE("path not specified\n");
2328            return 1;
2329        }
2330        *p = '\0';
2331        newPath = new char[(strlen(path) + 15) * 2 + 1];
2332        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", path, path);
2333        path = newPath;
2334#else
2335        char buff[256];
2336        getcwd(buff, 255);
2337        p = strrchr(buff, '/');
2338        if (p != NULL) {
2339            *p = '\0';
2340        }
2341        newPath = new char[(strlen(buff) + 15) * 2 + 1];
2342        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", buff, buff);
2343        path = newPath;
2344#endif
2345    }
2346
2347    R2FilePath::getInstance()->setWorkingDirectory(argc, (const char**) argv);
2348    vrFilePath::getInstance()->setWorkingDirectory(argc, (const char**) argv);
2349
2350#ifdef XINETD
2351#ifdef notdef
2352    signal(SIGPIPE, SIG_IGN);
2353#endif
2354    NvInitService();
2355#endif
2356
2357    NanoVis::init(path);
2358    if (newPath != NULL) {
2359        delete [] newPath;
2360    }
2361    NanoVis::initGL();
2362#ifdef EVENTLOG
2363    NvInitEventLog();
2364#endif
2365    Tcl_DStringInit(&NanoVis::cmdbuffer);
2366    NanoVis::interp = initTcl();
2367    NanoVis::resizeOffscreenBuffer(NanoVis::winWidth, NanoVis::winHeight);
2368
2369    glutMainLoop();
2370    doExit(80);
2371}
2372
2373int
2374NanoVis::render2dContour(HeightMap* heightmap, int width, int height)
2375{
2376    int old_width = winWidth;
2377    int old_height = winHeight;
2378
2379    resizeOffscreenBuffer(width, height);
2380
2381    /*
2382      planeRenderer->set_screen_size(width, height);
2383
2384      // generate data for the legend
2385      float data[512];
2386      for (int i=0; i < 256; i++) {
2387      data[i] = data[i+256] = (float)(i/255.0);
2388      }
2389      plane[0] = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
2390      int index = planeRenderer->add_plane(plane[0], tf);
2391      planeRenderer->set_active_plane(index);
2392
2393      offscreenBufferCapture();
2394      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
2395
2396      //planeRenderer->render();
2397      // INSOO : is going to implement here for the topview of the heightmap
2398      heightmap->render(renderContext);
2399
2400      // INSOO
2401      glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
2402      //glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, screen_buffer); // INSOO's
2403      */
2404
2405
2406    // HELP ME
2407    // GEORGE
2408    // I am not sure what I should do
2409    //char prefix[200];
2410    //sprintf(prefix, "nv>height_top_view %s %g %g", volArg, min, max);
2411    //ppmWrite(prefix);
2412    //write(1, "\n", 1);
2413    //planeRenderer->remove_plane(index);
2414
2415    // CURRENT
2416    offscreenBufferCapture();
2417    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
2418    //glEnable(GL_TEXTURE_2D);
2419    //glEnable(GL_DEPTH_TEST);
2420    //heightmap->render_topview(renderContext, width, height);
2421    //NanoVis::display();
2422    if (HeightMap::updatePending) {
2423        setHeightmapRanges();
2424    }
2425
2426    //cam->initialize();
2427
2428    heightmap->render_topview(renderContext, width, height);
2429
2430    NanoVis::readScreen();
2431    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2432
2433    // INSOO TEST CODE
2434    bmpWriteToFile(1, "/tmp");
2435
2436    resizeOffscreenBuffer(old_width, old_height);
2437
2438    return TCL_OK;
2439}
2440
2441void
2442NanoVis::removeVolume(Volume *volPtr)
2443{
2444    Tcl_HashEntry *hPtr;
2445    hPtr = Tcl_FindHashEntry(&volumeTable, volPtr->name());
2446    if (hPtr != NULL) {
2447        Tcl_DeleteHashEntry(hPtr);
2448    }
2449    delete volPtr;
2450}
Note: See TracBrowser for help on using the repository browser.