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

Last change on this file since 2975 was 2975, checked in by ldelgass, 13 years ago

Unfriend NanoVis? from VolumeRenderer?, use getVolumeInterpolator() method instead
of accessing private member pointer.

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