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

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

Remove vrutil library. Was only used for FilePath? that already exists in
R2 library (may need some fixing for windows portability though). Make
R2FilePath::getPath return a std::string so users can allocate a std::string
on the stack and not worry about deleting the string buffer returned. Also,
use std::string in R2Fonts to avoid leaking font names. Remove R2string as
it is now replaced by std::strings.

  • Property svn:eol-style set to native
File size: 68.4 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    if (volRenderer->_volumeInterpolator->isStarted()) {
1426        struct timeval clock;
1427        gettimeofday(&clock, NULL);
1428        double elapsed_time;
1429
1430        elapsed_time = clock.tv_sec + clock.tv_usec/1000000.0 -
1431            volRenderer->_volumeInterpolator->getStartTime();
1432
1433        TRACE("%lf %lf\n", elapsed_time,
1434               volRenderer->_volumeInterpolator->getInterval());
1435        float fraction;
1436        float f;
1437
1438        f = fmod((float) elapsed_time, (float)volRenderer->_volumeInterpolator->getInterval());
1439        if (f == 0.0) {
1440            fraction = 0.0f;
1441        } else {
1442            fraction = f / volRenderer->_volumeInterpolator->getInterval();
1443        }
1444        TRACE("fraction : %f\n", fraction);
1445        volRenderer->_volumeInterpolator->update(fraction);
1446    }
1447}
1448
1449void
1450NanoVis::setVolumeRanges()
1451{
1452    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1453
1454    TRACE("in SetVolumeRanges\n");
1455    xMin = yMin = zMin = wMin = DBL_MAX;
1456    xMax = yMax = zMax = wMax = -DBL_MAX;
1457    Tcl_HashEntry *hPtr;
1458    Tcl_HashSearch iter;
1459    for (hPtr = Tcl_FirstHashEntry(&volumeTable, &iter); hPtr != NULL;
1460         hPtr = Tcl_NextHashEntry(&iter)) {
1461        Volume *volPtr = (Volume *)Tcl_GetHashValue(hPtr);
1462        if (xMin > volPtr->xAxis.min()) {
1463            xMin = volPtr->xAxis.min();
1464        }
1465        if (xMax < volPtr->xAxis.max()) {
1466            xMax = volPtr->xAxis.max();
1467        }
1468        if (yMin > volPtr->yAxis.min()) {
1469            yMin = volPtr->yAxis.min();
1470        }
1471        if (yMax < volPtr->yAxis.max()) {
1472            yMax = volPtr->yAxis.max();
1473        }
1474        if (zMin > volPtr->zAxis.min()) {
1475            zMin = volPtr->zAxis.min();
1476        }
1477        if (zMax < volPtr->zAxis.max()) {
1478            zMax = volPtr->zAxis.max();
1479        }
1480        if (wMin > volPtr->wAxis.min()) {
1481            wMin = volPtr->wAxis.min();
1482        }
1483        if (wMax < volPtr->wAxis.max()) {
1484            wMax = volPtr->wAxis.max();
1485        }
1486    }
1487    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1488        grid->xAxis.setScale(xMin, xMax);
1489    }
1490    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1491        grid->yAxis.setScale(yMin, yMax);
1492    }
1493    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1494        grid->zAxis.setScale(zMin, zMax);
1495    }
1496    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1497        Volume::valueMin = wMin;
1498        Volume::valueMax = wMax;
1499    }
1500    Volume::updatePending = false;
1501    TRACE("leaving SetVolumeRanges\n");
1502}
1503
1504void
1505NanoVis::setHeightmapRanges()
1506{
1507    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1508
1509    TRACE("in setHeightmapRanges\n");
1510    xMin = yMin = zMin = wMin = DBL_MAX;
1511    xMax = yMax = zMax = wMax = -DBL_MAX;
1512    Tcl_HashEntry *hPtr;
1513    Tcl_HashSearch iter;
1514    for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1515         hPtr = Tcl_NextHashEntry(&iter)) {
1516        HeightMap *hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1517        if (xMin > hmPtr->xAxis.min()) {
1518            xMin = hmPtr->xAxis.min();
1519        }
1520        if (xMax < hmPtr->xAxis.max()) {
1521            xMax = hmPtr->xAxis.max();
1522        }
1523        if (yMin > hmPtr->yAxis.min()) {
1524            yMin = hmPtr->yAxis.min();
1525        }
1526        if (yMax < hmPtr->yAxis.max()) {
1527            yMax = hmPtr->yAxis.max();
1528        }
1529        if (zMin > hmPtr->zAxis.min()) {
1530            zMin = hmPtr->zAxis.min();
1531        }
1532        if (zMax < hmPtr->zAxis.max()) {
1533            zMax = hmPtr->zAxis.max();
1534        }
1535        if (wMin > hmPtr->wAxis.min()) {
1536            wMin = hmPtr->wAxis.min();
1537        }
1538        if (wMax < hmPtr->wAxis.max()) {
1539            wMax = hmPtr->wAxis.max();
1540        }
1541    }
1542    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1543        grid->xAxis.setScale(xMin, xMax);
1544    }
1545    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1546        grid->yAxis.setScale(yMin, yMax);
1547    }
1548    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1549        grid->zAxis.setScale(zMin, zMax);
1550    }
1551    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1552        HeightMap::valueMin = grid->yAxis.min();
1553        HeightMap::valueMax = grid->yAxis.max();
1554    }
1555    for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1556         hPtr = Tcl_NextHashEntry(&iter)) {
1557        HeightMap *hmPtr;
1558        hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1559        hmPtr->mapToGrid(grid);
1560    }
1561    HeightMap::updatePending = false;
1562    TRACE("leaving setHeightmapRanges\n");
1563}
1564
1565/*----------------------------------------------------*/
1566void
1567NanoVis::display()
1568{
1569    TRACE("in display\n");
1570#ifdef notdef
1571    if (flags & MAP_FLOWS) {
1572        xMin = yMin = zMin = wMin = FLT_MAX, magMin = DBL_MAX;
1573        xMax = yMax = zMax = wMax = -FLT_MAX, magMax = -DBL_MAX;
1574    }
1575#endif
1576    if (flags & MAP_FLOWS) {
1577        MapFlows();
1578        grid->xAxis.setScale(xMin, xMax);
1579        grid->yAxis.setScale(yMin, yMax);
1580        grid->zAxis.setScale(zMin, zMax);
1581    }
1582    //assert(glGetError()==0);
1583    if (HeightMap::updatePending) {
1584        setHeightmapRanges();
1585    }
1586    if (Volume::updatePending) {
1587        setVolumeRanges();
1588    }
1589
1590    //start final rendering
1591
1592    // Need to reset fbo since it may have been changed to default (0)
1593    bindOffscreenBuffer();
1594
1595    TRACE("in display: glClear\n");
1596    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
1597
1598    if (volumeMode) {
1599        TRACE("in display: volumeMode\n");
1600        //3D rendering mode
1601        glEnable(GL_DEPTH_TEST);
1602        glEnable(GL_COLOR_MATERIAL);
1603
1604        //camera setting activated
1605        cam->initialize();
1606
1607        //set up the orientation of items in the scene.
1608        glPushMatrix();
1609
1610        switch (updir) {
1611        case X_POS:
1612            glRotatef(90, 0, 0, 1);
1613            glRotatef(90, 1, 0, 0);
1614            break;
1615        case Y_POS:
1616            // this is the default
1617            break;
1618        case Z_POS:
1619            glRotatef(-90, 1, 0, 0);
1620            glRotatef(-90, 0, 0, 1);
1621            break;
1622        case X_NEG:
1623            glRotatef(-90, 0, 0, 1);
1624            break;
1625        case Y_NEG:
1626            glRotatef(180, 0, 0, 1);
1627            glRotatef(-90, 0, 1, 0);
1628            break;
1629        case Z_NEG:
1630            glRotatef(90, 1, 0, 0);
1631            break;
1632        }
1633
1634        //now render things in the scene
1635        if (axisOn) {
1636            draw3dAxis();
1637        }
1638        if (grid->isVisible()) {
1639            grid->render();
1640        }
1641        if ((licRenderer != NULL) && (licRenderer->active())) {
1642            licRenderer->render();
1643        }
1644
1645        if ((velocityArrowsSlice != NULL) && (velocityArrowsSlice->enabled())) {
1646            velocityArrowsSlice->render();
1647        }
1648#ifdef notdef
1649        if ((flowVisRenderer != NULL) && (flowVisRenderer->active())) {
1650            flowVisRenderer->render();
1651        }
1652#endif
1653        if (flowTable.numEntries > 0) {
1654            RenderFlows();
1655        }
1656
1657        //soft_display_verts();
1658        //perf->enable();
1659        //perf->disable();
1660        //TRACE("particle pixels: %d\n", perf->get_pixel_count());
1661        //perf->reset();
1662
1663        //perf->enable();
1664        volRenderer->renderAll();
1665        //perf->disable();
1666
1667        if (heightmapTable.numEntries > 0) {
1668            TRACE("in display: render heightmap\n");
1669            Tcl_HashEntry *hPtr;
1670            Tcl_HashSearch iter;
1671            for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1672                 hPtr = Tcl_NextHashEntry(&iter)) {
1673                HeightMap *hmPtr;
1674                hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1675                if (hmPtr->isVisible()) {
1676                    hmPtr->render(renderContext);
1677                }
1678            }
1679        }
1680        glPopMatrix();
1681    } else {
1682        //2D rendering mode
1683        perf->enable();
1684        planeRenderer->render();
1685        perf->disable();
1686    }
1687
1688    perf->reset();
1689    CHECK_FRAMEBUFFER_STATUS();
1690    TRACE("leaving display\n");
1691}
1692
1693#ifndef XINETD
1694void
1695NanoVis::mouse(int button, int state, int x, int y)
1696{
1697    if (button == GLUT_LEFT_BUTTON) {
1698        if (state == GLUT_DOWN) {
1699            left_last_x = x;
1700            left_last_y = y;
1701            left_down = true;
1702            right_down = false;
1703        } else {
1704            left_down = false;
1705            right_down = false;
1706        }
1707    } else {
1708        //TRACE("right mouse\n");
1709
1710        if (state == GLUT_DOWN) {
1711            //TRACE("right mouse down\n");
1712            right_last_x = x;
1713            right_last_y = y;
1714            left_down = false;
1715            right_down = true;
1716        } else {
1717            //TRACE("right mouse up\n");
1718            left_down = false;
1719            right_down = false;
1720        }
1721    }
1722}
1723
1724void
1725NanoVis::updateRot(int delta_x, int delta_y)
1726{
1727    Vector3 angle;
1728
1729    angle = cam->rotate();
1730    angle.x += delta_x;
1731    angle.y += delta_y;
1732
1733    if (angle.x > 360.0) {
1734        angle.x -= 360.0;
1735    } else if(angle.x < -360.0) {
1736        angle.x += 360.0;
1737    }
1738    if (angle.y > 360.0) {
1739        angle.y -= 360.0;
1740    } else if(angle.y < -360.0) {
1741        angle.y += 360.0;
1742    }
1743    cam->rotate(angle);
1744}
1745
1746void
1747NanoVis::updateTrans(int delta_x, int delta_y, int delta_z)
1748{
1749    cam->x(cam->x() + delta_x * 0.03);
1750    cam->y(cam->y() + delta_y * 0.03);
1751    cam->z(cam->z() + delta_z * 0.03);
1752}
1753
1754#ifdef notdef
1755void NanoVis::initParticle()
1756{
1757    flowVisRenderer->initialize();
1758    licRenderer->makePatterns();
1759}
1760
1761static
1762void addVectorField(const char* filename, const char* vf_name,
1763                    const char* plane_name1, const char* plane_name2,
1764                    const Vector4& color1, const Vector4& color2)
1765{
1766    Rappture::Outcome result;
1767    Rappture::Buffer buf;
1768
1769    buf.load(filename);
1770    int n = NanoVis::n_volumes;
1771    if (load_vector_stream2(result, n, buf.size(), buf.bytes())) {
1772        Volume *volPtr = NanoVis::volume[n];
1773        if (volPtr != NULL) {
1774            volPtr->numSlices(256-n);
1775            // volPtr->numSlices(512-n);
1776            volPtr->disableCutplane(0);
1777            volPtr->disableCutplane(1);
1778            volPtr->disableCutplane(2);
1779            volPtr->transferFunction(NanoVis::getTransfunc("default"));
1780
1781            float dx0 = -0.5;
1782            float dy0 = -0.5*volPtr->height/volPtr->width;
1783            float dz0 = -0.5*volPtr->depth/volPtr->width;
1784            volPtr->move(Vector3(dx0, dy0, dz0));
1785            //volPtr->data(true);
1786            volPtr->data(false);
1787            NanoVis::flowVisRenderer->addVectorField(vf_name, volPtr,
1788                volPtr->location(),
1789                1.0f,
1790                volPtr->height / (float)volPtr->width,
1791                volPtr->depth  / (float)volPtr->width,
1792                1.0f);
1793            NanoVis::flowVisRenderer->activateVectorField(vf_name);
1794
1795            //////////////////////////////////
1796            // ADD Particle Injection Plane1
1797            NanoVis::flowVisRenderer->addPlane(vf_name, plane_name1);
1798            NanoVis::flowVisRenderer->setPlaneAxis(vf_name, plane_name1, 0);
1799            NanoVis::flowVisRenderer->setPlanePos(vf_name, plane_name1, 0.9);
1800            NanoVis::flowVisRenderer->setParticleColor(vf_name, plane_name1, color1);
1801            // ADD Particle Injection Plane2
1802            NanoVis::flowVisRenderer->addPlane(vf_name, plane_name2);
1803            NanoVis::flowVisRenderer->setPlaneAxis(vf_name, plane_name2, 0);
1804            NanoVis::flowVisRenderer->setPlanePos(vf_name, plane_name2, 0.2);
1805            NanoVis::flowVisRenderer->setParticleColor(vf_name, plane_name2, color2);
1806            NanoVis::flowVisRenderer->initialize(vf_name);
1807
1808            NanoVis::flowVisRenderer->activatePlane(vf_name, plane_name1);
1809            NanoVis::flowVisRenderer->activatePlane(vf_name, plane_name2);
1810
1811            NanoVis::licRenderer->
1812                setVectorField(volPtr->id,
1813                               *(volPtr->get_location()),
1814                               1.0f / volPtr->aspectRatioWidth,
1815                               1.0f / volPtr->aspectRatioHeight,
1816                               1.0f / volPtr->aspectRatioDepth,
1817                               volPtr->wAxis.max());
1818        }
1819    }
1820    //NanoVis::initParticle();
1821}
1822#endif
1823
1824void
1825NanoVis::keyboard(unsigned char key, int x, int y)
1826{
1827#ifdef EVENTLOG
1828    if (log) {
1829        float param[3];
1830        param[0] = cam->x();
1831        param[1] = cam->y();
1832        param[2] = cam->z();
1833        Event* tmp = new Event(EVENT_MOVE, param, NvGetTimeInterval());
1834        tmp->write(event_log);
1835        delete tmp;
1836    }
1837#endif
1838
1839    switch (key) {
1840    case 'a' :
1841        {
1842            TRACE("flowvis active\n");
1843            char cmd[] = {
1844                "foreach flow [flow names] {\n"
1845                "    $flow configure -hide no -slice yes\n"
1846                "}\n"
1847            };
1848            Tcl_Eval(interp, cmd);
1849#ifdef notdef
1850            flowVisRenderer->active(true);
1851            licRenderer->active(true);
1852#endif
1853        }
1854        break;
1855    case 'd' :
1856        {
1857            TRACE("flowvis deactived\n");
1858            char cmd[] = {
1859                "foreach flow [flow names] {\n"
1860                "    $flow configure -hide yes -slice no\n"
1861                "}\n"
1862            };
1863            Tcl_Eval(interp, cmd);
1864#ifdef notdef
1865            flowVisRenderer->active(false);
1866            licRenderer->active(false);
1867#endif
1868        }
1869        break;
1870    case '1' :
1871        {
1872            TRACE("add vector field\n");
1873            char cmd[] = {
1874                "flow create flow1\n"
1875                "flow1 data file data/flowvis_dx_files/jwire/J-wire-vec.dx 3\n"
1876                "flow1 particles add plane1 -color { 0 0 1 1 }\n"
1877                "flow1 particles add plane2 -color { 0 1 1 1 }\n"
1878            };
1879            Tcl_Eval(interp, cmd);
1880#ifdef notdef
1881            addVectorField("data/flowvis_dx_files/jwire/J-wire-vec.dx",
1882                           "vf_name2", "plane_name1", "plane_name2", Vector4(0, 0, 1, 1), Vector4(0, 1, 1, 1));
1883#endif
1884        }
1885        break;
1886    case '2' :
1887        {
1888            char cmd[] = {
1889                "flow create flow2\n"
1890                "flow2 data file data/flowvis_dx_files/3DWireLeakage/SiO2/SiO2.dx 3\n"
1891                "flow2 particles add plane1 -color { 1 0 0 1 }\n"
1892                "flow2 particles add plane2 -color { 1 1 0 1 }\n"
1893            };
1894            Tcl_Eval(interp, cmd);
1895            TRACE("add vector field\n");
1896#ifdef notdef
1897            addVectorField("data/flowvis_dx_files/3DWireLeakage/SiO2/SiO2.dx",
1898                           "vf_name1", "plane_name1", "plane_name2", Vector4(1, 0, 0, 1), Vector4(1, 1, 0, 1));
1899#endif
1900        }
1901        break;
1902    case '3':
1903        {
1904            TRACE("activate\n");
1905            char cmd[] = {
1906                "flow1 particles add plane2 -hide no\n"
1907            };
1908            Tcl_Eval(interp, cmd);
1909#ifdef notdef
1910            NanoVis::flowVisRenderer->activatePlane("vf_name1", "plane_name2");
1911#endif
1912        }
1913        break;
1914    case '4' :
1915        {
1916            TRACE("deactivate\n");
1917            char cmd[] = {
1918                "flow1 particles add plane2 -hide yes\n"
1919            };
1920            Tcl_Eval(interp, cmd);
1921#ifdef notdef
1922            flowVisRenderer->deactivatePlane("vf_name1", "plane_name2");
1923#endif
1924        }
1925        break;
1926    case '5' :
1927        {
1928            TRACE("vector field deleted (vf_name2)\n");
1929            char cmd[] = {
1930                "flow delete flow2\n"
1931            };
1932            Tcl_Eval(interp, cmd);
1933#ifdef notdef
1934            flowVisRenderer->removeVectorField("vf_name2");
1935#endif
1936        }
1937        break;
1938    case '6' :
1939        {
1940            TRACE("add device shape\n");
1941            char cmd[] = {
1942                "flow1 box add box1 -corner1 {0 0 0} -corner2 {30 3 3} -color { 1 0 0 1 }\n"
1943                "flow1 box add box2 -corner1 {0 -1 -1} -corner2 {30 4 4} -color { 0 1 0 1 }\n"
1944                "flow1 box add box3 -corner1 {10 -1.5 -1} -corner2 {20 4.5 4.5} -color { 0 0 1 1 }\n"
1945            };
1946            Tcl_Eval(interp, cmd);
1947#ifdef notdef
1948            NvDeviceShape shape;
1949            shape.min.set(0, 0, 0);
1950            shape.max.set(30, 3, 3);
1951            shape.color.set(1, 0, 0, 1);
1952            flowVisRenderer->addDeviceShape("vf_name1", "device1", shape);
1953            shape.min.set(0, -1, -1);
1954            shape.max.set(30, 4, 4);
1955            shape.color.set(0, 1, 0, 1);
1956            flowVisRenderer->addDeviceShape("vf_name1", "device2", shape);
1957            shape.min.set(10, -1.5, -1);
1958            shape.max.set(20, 4.5, 4.5);
1959            shape.color.set(0, 0, 1, 1);
1960            flowVisRenderer->addDeviceShape("vf_name1", "device3", shape);
1961            flowVisRenderer->activateDeviceShape("vf_name1");
1962#endif
1963        }
1964        break;
1965    case '7' :
1966        {
1967            TRACE("hide shape \n");
1968            char cmd[] = {
1969                "flow1 box configure box1 -hide yes\n"
1970            };
1971            Tcl_Eval(interp, cmd);
1972#ifdef notdef
1973            flowVisRenderer->deactivateDeviceShape("vf_name1");
1974#endif
1975        }
1976        break;
1977    case '8' :
1978        {
1979            TRACE("show shape\n");
1980            char cmd[] = {
1981                "flow1 box configure box1 -hide no\n"
1982            };
1983            Tcl_Eval(interp, cmd);
1984#ifdef notdef
1985            flowVisRenderer->activateDeviceShape("vf_name1");
1986#endif
1987        }
1988        break;
1989    case '9' :
1990        {
1991            TRACE("show a shape \n");
1992            char cmd[] = {
1993                "flow1 box configure box3 -hide no\n"
1994            };
1995            Tcl_Eval(interp, cmd);
1996#ifdef notdef
1997            flowVisRenderer->activateDeviceShape("vf_name1", "device3");
1998#endif
1999        }
2000        break;
2001    case '0' :
2002        {
2003            TRACE("delete a shape \n");
2004            char cmd[] = {
2005                "flow1 box delete box3\n"
2006            };
2007            Tcl_Eval(interp, cmd);
2008#ifdef notdef
2009            flowVisRenderer->deactivateDeviceShape("vf_name1", "device3");
2010#endif
2011        }
2012        break;
2013    case 'r' :
2014        {
2015            TRACE("reset \n");
2016            char cmd[] = {
2017                "flow reset\n"
2018            };
2019            Tcl_Eval(interp, cmd);
2020#ifdef notdef
2021            flowVisRenderer->reset();
2022            licRenderer->reset();
2023#endif
2024        }
2025        break;
2026    }
2027}
2028
2029void
2030NanoVis::motion(int x, int y)
2031{
2032    int old_x, old_y;
2033
2034    if (left_down) {
2035        old_x = left_last_x;
2036        old_y = left_last_y;
2037    } else if (right_down) {
2038        old_x = right_last_x;
2039        old_y = right_last_y;
2040    }
2041
2042    int delta_x = x - old_x;
2043    int delta_y = y - old_y;
2044
2045    //more coarse event handling
2046    //if(abs(delta_x)<10 && abs(delta_y)<10)
2047    //return;
2048
2049    if (left_down) {
2050        left_last_x = x;
2051        left_last_y = y;
2052
2053        updateRot(-delta_y, -delta_x);
2054    } else if (right_down) {
2055        //TRACE("right mouse motion (%d,%d)\n", x, y);
2056
2057        right_last_x = x;
2058        right_last_y = y;
2059
2060        updateTrans(0, 0, delta_x);
2061    }
2062
2063#ifdef EVENTLOG
2064    Vector3 angle = cam->rotate();
2065    Event* tmp = new Event(EVENT_ROTATE, &angle, NvGetTimeInterval());
2066    tmp->write(event_log);
2067    delete tmp;
2068#endif
2069    glutPostRedisplay();
2070}
2071
2072void
2073NanoVis::render()
2074{
2075
2076#ifdef notdef
2077    if ((licRenderer != NULL) && (licRenderer->active())) {
2078        licRenderer->convolve();
2079    }
2080#else
2081    if (licRenderer != NULL) {
2082        licRenderer->convolve();
2083    }
2084#endif
2085
2086#ifdef notdef
2087    if ((flowVisRenderer != NULL) && (flowVisRenderer->active())) {
2088        flowVisRenderer->advect();
2089    }
2090#endif
2091    update();
2092    display();
2093    glutSwapBuffers();
2094}
2095
2096void
2097NanoVis::resize(int x, int y)
2098{
2099    glViewport(0, 0, x, y);
2100}
2101
2102#endif /*XINETD*/
2103
2104void
2105NanoVis::xinetdListen()
2106{
2107    flags &= ~REDRAW_PENDING;
2108
2109    TRACE("Enter xinetdListen\n");
2110
2111    int flags = fcntl(0, F_GETFL, 0);
2112    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2113
2114    int status = TCL_OK;
2115
2116    //  Read and execute as many commands as we can from stdin...
2117    Tcl_DString cmdbuffer;
2118    Tcl_DStringInit(&cmdbuffer);
2119    int nCommands = 0;
2120    bool isComplete = false;
2121    while ((!feof(NanoVis::stdin)) && (status == TCL_OK)) {
2122        //
2123        //  Read the next command from the buffer.  First time through we
2124        //  block here and wait if necessary until a command comes in.
2125        //
2126        //  BE CAREFUL: Read only one command, up to a newline.  The "volume
2127        //  data follows" command needs to be able to read the data
2128        //  immediately following the command, and we shouldn't consume it
2129        //  here.
2130        //
2131        TRACE("in xinetdListen: EOF=%d\n", feof(NanoVis::stdin));
2132        while (!feof(NanoVis::stdin)) {
2133            int c = fgetc(NanoVis::stdin);
2134            char ch;
2135            if (c <= 0) {
2136                if (errno == EWOULDBLOCK) {
2137                    break;
2138                }
2139                doExit(100);
2140            }
2141            ch = (char)c;
2142            Tcl_DStringAppend(&cmdbuffer, &ch, 1);
2143            if (ch == '\n') {
2144                isComplete = Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer));
2145                if (isComplete) {
2146                    break;
2147                }
2148            }
2149        }
2150        // no command? then we're done for now
2151        if (Tcl_DStringLength(&cmdbuffer) == 0) {
2152            break;
2153        }
2154        if (isComplete) {
2155            // back to original flags during command evaluation...
2156            fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2157            status = executeCommand(interp, &cmdbuffer);
2158            // non-blocking for next read -- we might not get anything
2159            fcntl(0, F_SETFL, flags | O_NONBLOCK);
2160            isComplete = false;
2161            nCommands++;
2162            CHECK_FRAMEBUFFER_STATUS();
2163        }
2164    }
2165    fcntl(0, F_SETFL, flags);
2166
2167    if (status != TCL_OK) {
2168        const char *string;
2169        int nBytes;
2170
2171        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
2172        TRACE("errorInfo=(%s)\n", string);
2173        nBytes = strlen(string);
2174        struct iovec iov[3];
2175        iov[0].iov_base = (char *)"NanoVis Server Error: ";
2176        iov[0].iov_len = strlen((char *)iov[0].iov_base);
2177        iov[1].iov_base = (char *)string;
2178        iov[1].iov_len = nBytes;
2179        iov[2].iov_len = 1;
2180        iov[2].iov_base = (char *)'\n';
2181        if (writev(1, iov, 3) < 0) {
2182            ERROR("write failed: %s\n", strerror(errno));
2183        }
2184        TRACE("Leaving xinetd_listen on ERROR\n");
2185        return;
2186    }
2187    if (feof(NanoVis::stdin)) {
2188        doExit(90);
2189    }
2190
2191    update();
2192
2193    bindOffscreenBuffer();  //enable offscreen render
2194
2195    display();
2196
2197#ifdef XINETD
2198    readScreen();
2199#else
2200    displayOffscreenBuffer(); //display the final rendering on screen
2201    readScreen();
2202    glutSwapBuffers();
2203#endif
2204
2205    if (feof(NanoVis::stdin)) {
2206        doExit(90);
2207    }
2208#if DO_RLE
2209    do_rle();
2210    int sizes[2] = {  offsets_size*sizeof(offsets[0]), rle_size };
2211    TRACE("Writing %d,%d\n", sizes[0], sizes[1]);
2212    write(1, &sizes, sizeof(sizes));
2213    write(1, offsets, offsets_size*sizeof(offsets[0]));
2214    write(1, rle, rle_size);    //unsigned byte
2215#else
2216    ppmWrite("\nnv>image -type image -bytes");
2217#endif
2218    TRACE("Leaving xinetd_listen OK\n");
2219}
2220
2221int
2222main(int argc, char **argv)
2223{
2224    const char *path;
2225    char *newPath;
2226    struct timeval tv;
2227
2228    newPath = NULL;
2229    path = NULL;
2230    NanoVis::stdin = stdin;
2231
2232    fprintf(stdout, "NanoVis %s\n", NANOVIS_VERSION);
2233    fflush(stdout);
2234
2235    openlog("nanovis", LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
2236    gettimeofday(&tv, NULL);
2237    stats.start = tv;
2238
2239    /* Initialize GLUT here so it can parse and remove GLUT-specific
2240     * command-line options before we parse the command-line below. */
2241    glutInit(&argc, argv);
2242    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
2243    glutInitWindowSize(NanoVis::winWidth, NanoVis::winHeight);
2244    glutInitWindowPosition(10, 10);
2245    NanoVis::renderWindow = glutCreateWindow("nanovis");
2246    glutIdleFunc(NanoVis::idle);
2247
2248#ifndef XINETD
2249    glutMouseFunc(NanoVis::mouse);
2250    glutMotionFunc(NanoVis::motion);
2251    glutKeyboardFunc(NanoVis::keyboard);
2252    glutReshapeFunc(NanoVis::resize);
2253    glutDisplayFunc(NanoVis::render);
2254#else
2255    glutDisplayFunc(NanoVis::display);
2256    glutReshapeFunc(NanoVis::resizeOffscreenBuffer);
2257#endif
2258
2259    while (1) {
2260        static struct option long_options[] = {
2261            {"infile",  required_argument, NULL, 0},
2262            {"path",    required_argument, NULL, 2},
2263            {"debug",   no_argument,       NULL, 3},
2264            {"record",  required_argument, NULL, 4},
2265            {0, 0, 0, 0}
2266        };
2267        int option_index = 0;
2268        int c;
2269
2270        c = getopt_long(argc, argv, ":dp:i:l:r:", long_options, &option_index);
2271        if (c == -1) {
2272            break;
2273        }
2274        switch (c) {
2275        case '?':
2276            fprintf(stderr, "unknown option -%c\n", optopt);
2277            return 1;
2278        case ':':
2279            if (optopt < 4) {
2280                fprintf(stderr, "argument missing for --%s option\n",
2281                        long_options[optopt].name);
2282            } else {
2283                fprintf(stderr, "argument missing for -%c option\n", optopt);
2284            }
2285            return 1;
2286        case 2:
2287        case 'p':
2288            path = optarg;
2289            break;
2290        case 3:
2291        case 'd':
2292            NanoVis::debugFlag = true;
2293            break;
2294        case 0:
2295        case 'i':
2296            NanoVis::stdin = fopen(optarg, "r");
2297            if (NanoVis::stdin == NULL) {
2298                perror(optarg);
2299                return 2;
2300            }
2301            break;
2302        case 4:
2303        case 'r':
2304            Tcl_DString ds;
2305            char buf[200];
2306
2307            Tcl_DStringInit(&ds);
2308            Tcl_DStringAppend(&ds, optarg, -1);
2309            sprintf(buf, ".%d", getpid());
2310            Tcl_DStringAppend(&ds, buf, -1);
2311            NanoVis::recfile = fopen(Tcl_DStringValue(&ds), "w");
2312            if (NanoVis::recfile == NULL) {
2313                perror(optarg);
2314                return 2;
2315            }
2316            break;
2317        default:
2318            fprintf(stderr,"unknown option '%c'.\n", c);
2319            return 1;
2320        }
2321    }     
2322    if (path == NULL) {
2323        char *p;
2324
2325        // See if we can derive the path from the location of the program.
2326        // Assume program is in the form <path>/bin/nanovis.
2327
2328#ifdef XINETD
2329        path = argv[0];
2330        p = strrchr((char *)path, '/');
2331        if (p != NULL) {
2332            *p = '\0';
2333            p = strrchr((char *)path, '/');
2334        }
2335        if (p == NULL) {
2336            TRACE("path not specified\n");
2337            return 1;
2338        }
2339        *p = '\0';
2340        newPath = new char[(strlen(path) + 15) * 2 + 1];
2341        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", path, path);
2342        path = newPath;
2343#else
2344        char buff[256];
2345        getcwd(buff, 255);
2346        p = strrchr(buff, '/');
2347        if (p != NULL) {
2348            *p = '\0';
2349        }
2350        newPath = new char[(strlen(buff) + 15) * 2 + 1];
2351        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", buff, buff);
2352        path = newPath;
2353#endif
2354    }
2355
2356    R2FilePath::getInstance()->setWorkingDirectory(argc, (const char**) argv);
2357
2358#ifdef XINETD
2359#ifdef notdef
2360    signal(SIGPIPE, SIG_IGN);
2361#endif
2362    NvInitService();
2363#endif
2364
2365    NanoVis::init(path);
2366    if (newPath != NULL) {
2367        delete [] newPath;
2368    }
2369    NanoVis::initGL();
2370#ifdef EVENTLOG
2371    NvInitEventLog();
2372#endif
2373    NanoVis::interp = initTcl();
2374    NanoVis::resizeOffscreenBuffer(NanoVis::winWidth, NanoVis::winHeight);
2375
2376    glutMainLoop();
2377    doExit(80);
2378}
2379
2380int
2381NanoVis::render2dContour(HeightMap* heightmap, int width, int height)
2382{
2383    int old_width = winWidth;
2384    int old_height = winHeight;
2385
2386    resizeOffscreenBuffer(width, height);
2387
2388    /*
2389      planeRenderer->setScreenSize(width, height);
2390
2391      // generate data for the legend
2392      float data[512];
2393      for (int i=0; i < 256; i++) {
2394          data[i] = data[i+256] = (float)(i/255.0);
2395      }
2396      plane[0] = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
2397      int index = planeRenderer->addPlane(plane[0], tf);
2398      planeRenderer->setActivePlane(index);
2399
2400      bindOffscreenBuffer();
2401      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
2402
2403      //planeRenderer->render();
2404      // INSOO : is going to implement here for the topview of the heightmap
2405      heightmap->render(renderContext);
2406
2407      // INSOO
2408      glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
2409      //glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, screen_buffer); // INSOO's
2410      */
2411
2412
2413    // HELP ME
2414    // GEORGE
2415    // I am not sure what I should do
2416    //char prefix[200];
2417    //sprintf(prefix, "nv>height_top_view %s %g %g", volArg, min, max);
2418    //ppmWrite(prefix);
2419    //write(1, "\n", 1);
2420    //planeRenderer->removePlane(index);
2421
2422    // CURRENT
2423    bindOffscreenBuffer();
2424    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
2425    //glEnable(GL_TEXTURE_2D);
2426    //glEnable(GL_DEPTH_TEST);
2427    //heightmap->renderTopview(renderContext, width, height);
2428    //NanoVis::display();
2429    if (HeightMap::updatePending) {
2430        setHeightmapRanges();
2431    }
2432
2433    //cam->initialize();
2434
2435    heightmap->renderTopview(renderContext, width, height);
2436
2437    readScreen();
2438
2439    // INSOO TEST CODE
2440    bmpWriteToFile(1, "/tmp");
2441
2442    resizeOffscreenBuffer(old_width, old_height);
2443
2444    return TCL_OK;
2445}
2446
2447void
2448NanoVis::removeVolume(Volume *volPtr)
2449{
2450    Tcl_HashEntry *hPtr;
2451    hPtr = Tcl_FindHashEntry(&volumeTable, volPtr->name());
2452    if (hPtr != NULL) {
2453        Tcl_DeleteHashEntry(hPtr);
2454    }
2455    delete volPtr;
2456}
Note: See TracBrowser for help on using the repository browser.