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

Last change on this file since 3408 was 3408, checked in by ldelgass, 11 years ago

Make nanovis report errors as internal (protocol errors) by default.

  • Property svn:eol-style set to native
File size: 58.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-2012  HUBzero Foundation, LLC
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 <RpEncode.h>
43
44#include <R2/R2FilePath.h>
45#include <R2/R2Fonts.h>
46
47#include <BMPImageLoaderImpl.h>
48#include <ImageLoaderFactory.h>
49
50#include <GL/glew.h>
51#include <GL/glut.h>
52
53#include "config.h"
54#include "nanovis.h"
55#include "define.h"
56
57#include "FlowCmd.h"
58#include "Grid.h"
59#include "HeightMap.h"
60#include "NvCamera.h"
61#include "NvEventLog.h"
62#include "RenderContext.h"
63#include "NvShader.h"
64#include "NvColorTableRenderer.h"
65#include "NvFlowVisRenderer.h"
66#include "NvLIC.h"
67#include "NvZincBlendeReconstructor.h"
68#include "PerfQuery.h"
69#include "PlaneRenderer.h"
70#ifdef USE_POINTSET_RENDERER
71#include "PointSetRenderer.h"
72#include "PointSet.h"
73#endif
74#include "Switch.h"
75#include "Trace.h"
76#include "Unirect.h"
77#include "VelocityArrowsSlice.h"
78#include "VolumeInterpolator.h"
79#include "VolumeRenderer.h"
80#include "ZincBlendeVolume.h"
81
82#define SIZEOF_BMP_HEADER   54
83
84/// Indicates "up" axis
85enum AxisDirections {
86    X_POS = 1,
87    Y_POS = 2,
88    Z_POS = 3,
89    X_NEG = -1,
90    Y_NEG = -2,
91    Z_NEG = -3
92};
93
94#define CVT2SECS(x)  ((double)(x).tv_sec) + ((double)(x).tv_usec * 1.0e-6)
95
96#define TRUE    1
97#define FALSE   0
98
99typedef struct {
100    pid_t pid;
101    size_t nFrames;            /**< # of frames sent to client. */
102    size_t nBytes;             /**< # of bytes for all frames. */
103    size_t nCommands;          /**< # of commands executed */
104    double cmdTime;            /**< Elasped time spend executing
105                                * commands. */
106    struct timeval start;      /**< Start of elapsed time. */
107} Stats;
108
109static Stats stats;
110
111// STATIC MEMBER DATA
112struct timeval NanoVis::startTime;      /* Start of elapsed time. */
113Grid *NanoVis::grid = NULL;
114int NanoVis::updir = Y_POS;
115NvCamera *NanoVis::cam = NULL;
116Tcl_HashTable NanoVis::volumeTable;
117Tcl_HashTable NanoVis::heightmapTable;
118VolumeRenderer *NanoVis::volRenderer = NULL;
119#ifdef USE_POINTSET_RENDERER
120PointSetRenderer *NanoVis::pointSetRenderer = NULL;
121std::vector<PointSet *> NanoVis::pointSet;
122#endif
123
124PlaneRenderer *NanoVis::planeRenderer = NULL;
125#ifdef PLANE_CMD
126// pointers to 2D planes, currently handle up 10
127int NanoVis::numPlanes = 10;
128Texture2D *NanoVis::plane[10];
129#endif
130Texture2D *NanoVis::legendTexture = NULL;
131NvColorTableRenderer *NanoVis::colorTableRenderer = NULL;
132#ifdef notdef
133NvFlowVisRenderer *NanoVis::flowVisRenderer = NULL;
134#endif
135VelocityArrowsSlice *NanoVis::velocityArrowsSlice = NULL;
136
137graphics::RenderContext *NanoVis::renderContext = NULL;
138NvLIC *NanoVis::licRenderer = NULL;
139R2Fonts *NanoVis::fonts;
140
141FILE *NanoVis::stdin = NULL;
142FILE *NanoVis::logfile = NULL;
143FILE *NanoVis::recfile = NULL;
144
145int NanoVis::statsFile = -1;
146
147bool NanoVis::axisOn = true;
148bool NanoVis::debugFlag = false;
149
150Tcl_Interp *NanoVis::interp;
151
152//frame buffer for final rendering
153GLuint NanoVis::_finalColorTex = 0;
154GLuint NanoVis::_finalDepthRb = 0;
155GLuint NanoVis::_finalFbo = 0;
156int NanoVis::renderWindow = 0;       /* GLUT handle for the render window */
157int NanoVis::winWidth = NPIX;        /* Width of the render window */
158int NanoVis::winHeight = NPIX;       /* Height of the render window */
159
160unsigned char* NanoVis::screenBuffer = NULL;
161
162unsigned int NanoVis::flags = 0;
163Tcl_HashTable NanoVis::flowTable;
164double NanoVis::magMin = DBL_MAX;
165double NanoVis::magMax = -DBL_MAX;
166float NanoVis::xMin = FLT_MAX;
167float NanoVis::xMax = -FLT_MAX;
168float NanoVis::yMin = FLT_MAX;
169float NanoVis::yMax = -FLT_MAX;
170float NanoVis::zMin = FLT_MAX;
171float NanoVis::zMax = -FLT_MAX;
172float NanoVis::wMin = FLT_MAX;
173float NanoVis::wMax = -FLT_MAX;
174
175/* FIXME: This variable is always true. */
176static bool volumeMode = true;
177
178// in Command.cpp
179extern Tcl_Interp *initTcl();
180
181// maps transfunc name to TransferFunction object
182Tcl_HashTable NanoVis::tfTable;
183
184PerfQuery *perf = NULL;                        //performance counter
185
186// Default camera location.
187const float def_eye_x = 0.0f;
188const float def_eye_y = 0.0f;
189const float def_eye_z = 2.5f;
190
191#ifndef XINETD
192// Variables for mouse events
193// Last locations mouse events
194static int left_last_x;
195static int left_last_y;
196static int right_last_x;
197static int right_last_y;
198static bool left_down = false;
199static bool right_down = false;
200#endif /*XINETD*/
201
202// Image based flow visualization slice location
203// FLOW
204float NanoVis::_licSlice = 0.5f;
205int NanoVis::_licAxis = 2; // z axis
206
207void
208NanoVis::removeAllData()
209{
210    TRACE("in removeAllData\n");
211    if (grid != NULL) {
212        TRACE("Deleting grid");
213        delete grid;
214    }
215    if (cam != NULL) {
216        TRACE("Deleting cam");
217        delete cam;
218    }
219    if (volRenderer != NULL) {
220        TRACE("Deleting volRenderer");
221        delete volRenderer;
222    }
223    if (planeRenderer != NULL) {
224        TRACE("Deleting planeRenderer");
225        delete planeRenderer;
226    }
227    if (colorTableRenderer != NULL) {
228        TRACE("Deleting colorTableRenderer");
229        delete colorTableRenderer;
230    }
231#ifdef PLANE_CMD
232    for (int i = 0; i < numPlanes; i++) {
233        TRACE("Deleting plane[%d]", i);
234        delete plane[i];
235    }
236#endif
237    if (legendTexture != NULL) {
238        TRACE("Deleting legendTexture");
239        delete legendTexture;
240    }
241#ifdef notdef
242    if (flowVisRenderer != NULL) {
243        TRACE("Deleting flowVisRenderer");
244        delete flowVisRenderer;
245    }
246#endif
247    TRACE("Deleting flows");
248    DeleteFlows(interp);
249    if (licRenderer != NULL) {
250        TRACE("Deleting licRenderer");
251        delete licRenderer;
252    }
253    if (velocityArrowsSlice != NULL) {
254        TRACE("Deleting velocityArrowsSlice");
255        delete velocityArrowsSlice;
256    }
257    if (renderContext != NULL) {
258        TRACE("Deleting renderContext");
259        delete renderContext;
260    }
261    if (screenBuffer != NULL) {
262        TRACE("Deleting screenBuffer");
263        delete [] screenBuffer;
264    }
265    if (perf != NULL) {
266        TRACE("Deleting perf");
267        delete perf;
268    }
269#ifdef USE_POINTSET_RENDERER
270    if (pointSetRenderer != NULL) {
271        TRACE("Deleting pointSetRenderer");
272        delete pointSetRenderer;
273    }
274    for (std::vector<PointSet *>::iterator itr = pointSet.begin();
275         itr != pointSet.end(); ++itr) {
276        TRACE("Deleting pointSet: %p", *itr);
277        delete (*itr);
278    }
279#endif
280}
281
282void
283NanoVis::eventuallyRedraw(unsigned int flag)
284{
285    if (flag) {
286        flags |= flag;
287    }
288    if ((flags & REDRAW_PENDING) == 0) {
289        glutPostRedisplay();
290        flags |= REDRAW_PENDING;
291    }
292}
293
294#ifdef KEEPSTATS
295
296#ifndef STATSDIR
297#define STATSDIR        "/var/tmp/visservers"
298#endif  /*STATSDIR*/
299
300int
301NanoVis::getStatsFile(Tcl_Obj *objPtr)
302{
303    Tcl_DString ds;
304    Tcl_Obj **objv;
305    int objc;
306    int i;
307    char fileName[33];
308    const char *path;
309    md5_state_t state;
310    md5_byte_t digest[16];
311    char *string;
312    int length;
313
314    if ((objPtr == NULL) || (statsFile >= 0)) {
315        return statsFile;
316    }
317    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
318        return -1;
319    }
320    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("pid", 3));
321    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(getpid()));
322    string = Tcl_GetStringFromObj(objPtr, &length);
323
324    md5_init(&state);
325    md5_append(&state, (const md5_byte_t *)string, length);
326    md5_finish(&state, digest);
327    for (i = 0; i < 16; i++) {
328        sprintf(fileName + i * 2, "%02x", digest[i]);
329    }
330    Tcl_DStringInit(&ds);
331    Tcl_DStringAppend(&ds, STATSDIR, -1);
332    Tcl_DStringAppend(&ds, "/", 1);
333    Tcl_DStringAppend(&ds, fileName, 32);
334    path = Tcl_DStringValue(&ds);
335
336    statsFile = open(path, O_EXCL | O_CREAT | O_WRONLY, 0600);
337    Tcl_DStringFree(&ds);
338    if (statsFile < 0) {
339        ERROR("can't open \"%s\": %s", fileName, strerror(errno));
340        return -1;
341    }
342    return statsFile;
343}
344
345int
346NanoVis::writeToStatsFile(int f, const char *s, size_t length)
347{
348    if (f >= 0) {
349        ssize_t numWritten;
350
351        numWritten = write(f, s, length);
352        if (numWritten == (ssize_t)length) {
353            close(dup(f));
354        }
355    }
356    return 0;
357}
358
359static int
360serverStats(int code)
361{
362    double start, finish;
363    char buf[BUFSIZ];
364    Tcl_DString ds;
365    int result;
366    int f;
367
368    {
369        struct timeval tv;
370
371        /* Get ending time.  */
372        gettimeofday(&tv, NULL);
373        finish = CVT2SECS(tv);
374        tv = stats.start;
375        start = CVT2SECS(tv);
376    }
377    /*
378     * Session information:
379     *   - Name of render server
380     *   - Process ID
381     *   - Hostname where server is running
382     *   - Start date of session
383     *   - Start date of session in seconds
384     *   - Number of frames returned
385     *   - Number of bytes total returned (in frames)
386     *   - Number of commands received
387     *   - Total elapsed time of all commands
388     *   - Total elapsed time of session
389     *   - Exit code of vizserver
390     *   - User time
391     *   - System time
392     *   - User time of children
393     *   - System time of children
394     */
395
396    Tcl_DStringInit(&ds);
397   
398    Tcl_DStringAppendElement(&ds, "render_stop");
399    /* renderer */
400    Tcl_DStringAppendElement(&ds, "renderer");
401    Tcl_DStringAppendElement(&ds, "nanovis");
402    /* pid */
403    Tcl_DStringAppendElement(&ds, "pid");
404    sprintf(buf, "%d", getpid());
405    Tcl_DStringAppendElement(&ds, buf);
406    /* host */
407    Tcl_DStringAppendElement(&ds, "host");
408    gethostname(buf, BUFSIZ-1);
409    buf[BUFSIZ-1] = '\0';
410    Tcl_DStringAppendElement(&ds, buf);
411    /* date */
412    Tcl_DStringAppendElement(&ds, "date");
413    strcpy(buf, ctime(&stats.start.tv_sec));
414    buf[strlen(buf) - 1] = '\0';
415    Tcl_DStringAppendElement(&ds, buf);
416    /* date_secs */
417    Tcl_DStringAppendElement(&ds, "date_secs");
418    sprintf(buf, "%ld", stats.start.tv_sec);
419    Tcl_DStringAppendElement(&ds, buf);
420    /* num_frames */
421    Tcl_DStringAppendElement(&ds, "num_frames");
422    sprintf(buf, "%lu", (unsigned long int)stats.nFrames);
423    Tcl_DStringAppendElement(&ds, buf);
424    /* frame_bytes */
425    Tcl_DStringAppendElement(&ds, "frame_bytes");
426    sprintf(buf, "%lu", (unsigned long int)stats.nBytes);
427    Tcl_DStringAppendElement(&ds, buf);
428    /* num_commands */
429    Tcl_DStringAppendElement(&ds, "num_commands");
430    sprintf(buf, "%lu", (unsigned long int)stats.nCommands);
431    Tcl_DStringAppendElement(&ds, buf);
432    /* cmd_time */
433    Tcl_DStringAppendElement(&ds, "cmd_time");
434    sprintf(buf, "%g", stats.cmdTime);
435    Tcl_DStringAppendElement(&ds, buf);
436    /* session_time */
437    Tcl_DStringAppendElement(&ds, "session_time");
438    sprintf(buf, "%g", finish - start);
439    Tcl_DStringAppendElement(&ds, buf);
440    /* status */
441    Tcl_DStringAppendElement(&ds, "status");
442    sprintf(buf, "%d", code);
443    Tcl_DStringAppendElement(&ds, buf);
444    {
445        long clocksPerSec = sysconf(_SC_CLK_TCK);
446        double clockRes = 1.0 / clocksPerSec;
447        struct tms tms;
448
449        memset(&tms, 0, sizeof(tms));
450        times(&tms);
451        /* utime */
452        Tcl_DStringAppendElement(&ds, "utime");
453        sprintf(buf, "%g", tms.tms_utime * clockRes);
454        Tcl_DStringAppendElement(&ds, buf);
455        /* stime */
456        Tcl_DStringAppendElement(&ds, "stime");
457        sprintf(buf, "%g", tms.tms_stime * clockRes);
458        Tcl_DStringAppendElement(&ds, buf);
459        /* cutime */
460        Tcl_DStringAppendElement(&ds, "cutime");
461        sprintf(buf, "%g", tms.tms_cutime * clockRes);
462        Tcl_DStringAppendElement(&ds, buf);
463        /* cstime */
464        Tcl_DStringAppendElement(&ds, "cstime");
465        sprintf(buf, "%g", tms.tms_cstime * clockRes);
466        Tcl_DStringAppendElement(&ds, buf);
467    }
468    Tcl_DStringAppend(&ds, "\n", -1);
469    f = NanoVis::getStatsFile(NULL);
470    result = NanoVis::writeToStatsFile(f, Tcl_DStringValue(&ds),
471                                       Tcl_DStringLength(&ds));
472    close(f);
473    Tcl_DStringFree(&ds);
474    return result;
475}
476
477#endif
478
479static void
480doExit(int code)
481{
482    TRACE("in doExit: %d\n", code);
483    NanoVis::removeAllData();
484
485    NvShader::exitCg();
486
487#ifdef EVENTLOG
488    NvExitEventLog();
489#endif
490
491#ifdef XINETD
492    NvExitService();
493#endif
494
495#ifdef KEEPSTATS
496    serverStats(code);
497#endif
498    closelog();
499    exit(code);
500}
501
502static int
503executeCommand(Tcl_Interp *interp, Tcl_DString *dsPtr)
504{
505    struct timeval tv;
506    double start, finish;
507    int result;
508
509    TRACE("command: '%s'", Tcl_DStringValue(dsPtr));
510
511    gettimeofday(&tv, NULL);
512    start = CVT2SECS(tv);
513
514    if (NanoVis::recfile != NULL) {
515        fprintf(NanoVis::recfile, "%s", Tcl_DStringValue(dsPtr));
516        fflush(NanoVis::recfile);
517    }
518    result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr));
519    Tcl_DStringSetLength(dsPtr, 0);
520
521    gettimeofday(&tv, NULL);
522    finish = CVT2SECS(tv);
523
524    stats.cmdTime += finish - start;
525    stats.nCommands++;
526    TRACE("leaving executeCommand status=%d\n", result);
527    return result;
528}
529
530void
531NanoVis::pan(float dx, float dy)
532{
533    /* Move the camera and its target by equal amounts along the x and y
534     * axes. */
535    TRACE("pan: x=%f, y=%f\n", dx, dy);
536
537    cam->x(def_eye_x - dx);
538    cam->y(def_eye_y + dy);
539    TRACE("set eye to %f %f\n", cam->x(), cam->y());
540}
541
542void
543NanoVis::zoom(float z)
544{
545    /* Move the camera and its target by equal amounts along the x and y
546     * axes. */
547    TRACE("zoom: z=%f\n", z);
548
549    cam->z(def_eye_z / z);
550    TRACE("set cam z to %f\n", cam->z());
551}
552
553/** \brief Load a 3D volume
554 *
555 * \param n_component the number of scalars for each space point. All component
556 * scalars for a point are placed consequtively in data array
557 * width, height and depth: number of points in each dimension
558 * \param data pointer to an array of floats.
559 */
560Volume *
561NanoVis::loadVolume(const char *name, int width, int height, int depth,
562                    int n_component, float *data, double vmin, double vmax,
563                    double nzero_min)
564{
565    Tcl_HashEntry *hPtr;
566    hPtr = Tcl_FindHashEntry(&volumeTable, name);
567    if (hPtr != NULL) {
568        Volume *volPtr;
569        WARN("volume \"%s\" already exists", name);
570        volPtr = (Volume *)Tcl_GetHashValue(hPtr);
571        removeVolume(volPtr);
572    }
573    int isNew;
574    hPtr = Tcl_CreateHashEntry(&volumeTable, name, &isNew);
575    Volume* volPtr;
576    volPtr = new Volume(0.f, 0.f, 0.f, width, height, depth, n_component,
577                        data, vmin, vmax, nzero_min);
578    Volume::updatePending = true;
579    Tcl_SetHashValue(hPtr, volPtr);
580    volPtr->name(Tcl_GetHashKey(&volumeTable, hPtr));
581    return volPtr;
582}
583
584// Gets a colormap 1D texture by name.
585TransferFunction *
586NanoVis::getTransfunc(const char *name)
587{
588    Tcl_HashEntry *hPtr;
589
590    hPtr = Tcl_FindHashEntry(&tfTable, name);
591    if (hPtr == NULL) {
592        ERROR("No transfer function named \"%s\" found", name);
593        return NULL;
594    }
595    return (TransferFunction *)Tcl_GetHashValue(hPtr);
596}
597
598// Creates of updates a colormap 1D texture by name.
599TransferFunction *
600NanoVis::defineTransferFunction(const char *name, size_t n, float *data)
601{
602    int isNew;
603    Tcl_HashEntry *hPtr;
604    TransferFunction *tfPtr;
605
606    hPtr = Tcl_CreateHashEntry(&tfTable, name, &isNew);
607    if (isNew) {
608        TRACE("Creating new transfer function \"%s\"", name);
609
610        tfPtr = new TransferFunction(n, data);
611        tfPtr->name(Tcl_GetHashKey(&tfTable, hPtr));
612        Tcl_SetHashValue(hPtr, tfPtr);
613    } else {
614        TRACE("Updating existing transfer function \"%s\"", name);
615
616        /*
617         * You can't delete the transfer function because many
618         * objects may be holding its pointer.  We must update it.
619         */
620        tfPtr = (TransferFunction *)Tcl_GetHashValue(hPtr);
621        tfPtr->update(n, data);
622    }
623    return tfPtr;
624}
625
626int
627NanoVis::renderLegend(TransferFunction *tf, double min, double max,
628                      int width, int height, const char *volArg)
629{
630    TRACE("in renderLegend\n");
631
632    int old_width = winWidth;
633    int old_height = winHeight;
634
635    planeRenderer->setScreenSize(width, height);
636    resizeOffscreenBuffer(width, height);
637
638    // generate data for the legend
639    float data[512];
640    for (int i=0; i < 256; i++) {
641        data[i] = data[i+256] = (float)(i/255.0);
642    }
643    legendTexture = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
644    int index = planeRenderer->addPlane(legendTexture, tf);
645    planeRenderer->setActivePlane(index);
646
647    bindOffscreenBuffer();
648    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
649    planeRenderer->render();
650
651    // INSOO
652    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer);
653    //glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, screenBuffer); // INSOO's
654
655    {
656        char prefix[200];
657        ssize_t nWritten;
658
659        TRACE("Sending ppm legend image %s min:%g max:%g", volArg, min, max);
660        sprintf(prefix, "nv>legend %s %g %g", volArg, min, max);
661        ppmWrite(prefix);
662        nWritten = write(1, "\n", 1);
663        assert(nWritten == 1);
664    }
665    planeRenderer->removePlane(index);
666    resizeOffscreenBuffer(old_width, old_height);
667
668    delete legendTexture;
669    legendTexture = NULL;
670    TRACE("leaving renderLegend\n");
671    return TCL_OK;
672}
673
674//initialize frame buffer objects for offscreen rendering
675void
676NanoVis::initOffscreenBuffer()
677{
678    TRACE("in initOffscreenBuffer\n");
679    assert(_finalFbo == 0);
680    // Initialize a fbo for final display.
681    glGenFramebuffersEXT(1, &_finalFbo);
682
683    glGenTextures(1, &_finalColorTex);
684    glBindTexture(GL_TEXTURE_2D, _finalColorTex);
685
686    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
687    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
688    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
689
690#if defined(HAVE_FLOAT_TEXTURES) && defined(USE_HALF_FLOAT)
691    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, winWidth, winHeight, 0,
692                 GL_RGB, GL_INT, NULL);
693#elif defined(HAVE_FLOAT_TEXTURES)
694    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, winWidth, winHeight, 0,
695                 GL_RGB, GL_INT, NULL);
696#else
697    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, winWidth, winHeight, 0,
698                 GL_RGB, GL_INT, NULL);
699#endif
700
701    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _finalFbo);
702    glGenRenderbuffersEXT(1, &_finalDepthRb);
703    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
704    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24,
705                             winWidth, winHeight);
706    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
707                              GL_TEXTURE_2D, _finalColorTex, 0);
708    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
709                                 GL_RENDERBUFFER_EXT, _finalDepthRb);
710
711    GLenum status;
712    if (!CheckFBO(&status)) {
713        PrintFBOStatus(status, "finalFbo");
714        doExit(3);
715    }
716
717    TRACE("leaving initOffscreenBuffer\n");
718}
719
720//resize the offscreen buffer
721void
722NanoVis::resizeOffscreenBuffer(int w, int h)
723{
724    TRACE("in resizeOffscreenBuffer(%d, %d)\n", w, h);
725    if ((w == winWidth) && (h == winHeight)) {
726        return;
727    }
728    winWidth = w;
729    winHeight = h;
730
731    if (fonts) {
732        fonts->resize(w, h);
733    }
734    TRACE("screenBuffer size: %d %d\n", w, h);
735
736    if (screenBuffer != NULL) {
737        delete [] screenBuffer;
738        screenBuffer = NULL;
739    }
740
741    screenBuffer = new unsigned char[4*winWidth*winHeight];
742    assert(screenBuffer != NULL);
743   
744    //delete the current render buffer resources
745    glDeleteTextures(1, &_finalColorTex);
746    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
747    glDeleteRenderbuffersEXT(1, &_finalDepthRb);
748
749    TRACE("before deleteframebuffers\n");
750    glDeleteFramebuffersEXT(1, &_finalFbo);
751
752    TRACE("reinitialize FBO\n");
753    //Reinitialize final fbo for final display
754    glGenFramebuffersEXT(1, &_finalFbo);
755
756    glGenTextures(1, &_finalColorTex);
757    glBindTexture(GL_TEXTURE_2D, _finalColorTex);
758
759    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
760    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
761    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
762
763#if defined(HAVE_FLOAT_TEXTURES) && defined(USE_HALF_FLOAT)
764    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, winWidth, winHeight, 0,
765                 GL_RGB, GL_INT, NULL);
766#elif defined(HAVE_FLOAT_TEXTURES)
767    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, winWidth, winHeight, 0,
768                 GL_RGB, GL_INT, NULL);
769#else
770    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, winWidth, winHeight, 0,
771                 GL_RGB, GL_INT, NULL);
772#endif
773
774    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _finalFbo);
775    glGenRenderbuffersEXT(1, &_finalDepthRb);
776    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
777    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24,
778                             winWidth, winHeight);
779    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
780                              GL_TEXTURE_2D, _finalColorTex, 0);
781    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
782                                 GL_RENDERBUFFER_EXT, _finalDepthRb);
783
784    GLenum status;
785    if (!CheckFBO(&status)) {
786        PrintFBOStatus(status, "finalFbo");
787        doExit(3);
788    }
789
790    TRACE("change camera\n");
791    //change the camera setting
792    cam->setScreenSize(0, 0, winWidth, winHeight);
793    planeRenderer->setScreenSize(winWidth, winHeight);
794
795    TRACE("leaving resizeOffscreenBuffer(%d, %d)\n", w, h);
796}
797
798static
799void cgErrorCallback(void)
800{
801    if (!NvShader::printErrorInfo()) {
802        TRACE("Cg error, exiting...\n");
803        doExit(-1);
804    }
805}
806
807void NanoVis::init(const char* path)
808{
809    // print OpenGL driver information
810    TRACE("-----------------------------------------------------------\n");
811    TRACE("OpenGL version: %s\n", glGetString(GL_VERSION));
812    TRACE("OpenGL vendor: %s\n", glGetString(GL_VENDOR));
813    TRACE("OpenGL renderer: %s\n", glGetString(GL_RENDERER));
814    TRACE("-----------------------------------------------------------\n");
815
816    if (path == NULL) {
817        ERROR("No path defined for shaders or resources\n");
818        doExit(1);
819    }
820    GLenum err = glewInit();
821    if (GLEW_OK != err) {
822        ERROR("Can't init GLEW: %s\n", glewGetErrorString(err));
823        doExit(1);
824    }
825    TRACE("Using GLEW %s\n", glewGetString(GLEW_VERSION));
826
827    // OpenGL 2.1 includes VBOs, PBOs, MRT, NPOT textures, point parameters, point sprites,
828    // GLSL 1.2, and occlusion queries.
829    if (!GLEW_VERSION_2_1) {
830        ERROR("OpenGL version 2.1 or greater is required\n");
831        doExit(1);
832    }
833
834    // NVIDIA driver may report OpenGL 2.1, but not support PBOs in
835    // indirect GLX contexts
836    if (!GLEW_ARB_pixel_buffer_object) {
837        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");
838        doExit(1);
839    }
840
841    // Additional extensions not in 2.1 core
842
843    // Framebuffer objects were promoted in 3.0
844    if (!GLEW_EXT_framebuffer_object) {
845        ERROR("EXT_framebuffer_oject extension is required\n");
846        doExit(1);
847    }
848    // Rectangle textures were promoted in 3.1
849    // FIXME: can use NPOT in place of rectangle textures
850    if (!GLEW_ARB_texture_rectangle) {
851        ERROR("ARB_texture_rectangle extension is required\n");
852        doExit(1);
853    }
854#ifdef HAVE_FLOAT_TEXTURES
855    // Float color buffers and textures were promoted in 3.0
856    if (!GLEW_ARB_texture_float ||
857        !GLEW_ARB_color_buffer_float) {
858        ERROR("ARB_texture_float and ARB_color_buffer_float extensions are required\n");
859        doExit(1);
860    }
861#endif
862    // FIXME: should use ARB programs or (preferably) a GLSL profile for portability
863    if (!GLEW_NV_vertex_program3 ||
864        !GLEW_NV_fragment_program2) {
865        ERROR("NV_vertex_program3 and NV_fragment_program2 extensions are required\n");
866        doExit(1);
867    }
868
869    if (!R2FilePath::getInstance()->setPath(path)) {
870        ERROR("can't set file path to %s\n", path);
871        doExit(1);
872    }
873
874    ImageLoaderFactory::getInstance()->addLoaderImpl("bmp", new BMPImageLoaderImpl());
875
876    NvShader::initCg();
877    NvShader::setErrorCallback(cgErrorCallback);
878
879    fonts = new R2Fonts();
880    fonts->addFont("verdana", "verdana.fnt");
881    fonts->setFont("verdana");
882
883    colorTableRenderer = new NvColorTableRenderer();
884    colorTableRenderer->setFonts(fonts);
885#ifdef notdef
886    flowVisRenderer = new NvFlowVisRenderer(NMESH, NMESH);
887#endif
888    velocityArrowsSlice = new VelocityArrowsSlice;
889
890    licRenderer = new NvLIC(NMESH, NPIX, NPIX, _licAxis, _licSlice);
891
892    grid = new Grid();
893    grid->setFont(fonts);
894
895#ifdef USE_POINTSET_RENDERER
896    pointSetRenderer = new PointSetRenderer();
897#endif
898}
899
900void
901NanoVis::initGL()
902{
903    TRACE("in initGL\n");
904    //buffer to store data read from the screen
905    if (screenBuffer) {
906        delete[] screenBuffer;
907        screenBuffer = NULL;
908    }
909    screenBuffer = new unsigned char[4*winWidth*winHeight];
910    assert(screenBuffer != NULL);
911
912    //create the camera with default setting
913    cam = new NvCamera(0, 0, winWidth, winHeight,
914                       def_eye_x, def_eye_y, def_eye_z);
915
916    glEnable(GL_TEXTURE_2D);
917    glShadeModel(GL_FLAT);
918    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
919    glClearColor(0, 0, 0, 1);
920    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
921
922    //initialize lighting
923    GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
924    GLfloat mat_shininess[] = {30.0};
925    GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
926    GLfloat green_light[] = {0.1, 0.5, 0.1, 1.0};
927
928    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
929    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
930    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
931    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
932    glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light);
933    glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
934
935    // init table of transfer functions
936    Tcl_InitHashTable(&tfTable, TCL_STRING_KEYS);
937
938    //check if performance query is supported
939    if (PerfQuery::checkQuerySupport()) {
940        //create queries to count number of rendered pixels
941        perf = new PerfQuery();
942    }
943
944    initOffscreenBuffer();    //frame buffer object for offscreen rendering
945
946    //create volume renderer and add volumes to it
947    volRenderer = new VolumeRenderer();
948
949    // create
950    renderContext = new graphics::RenderContext();
951
952    //create a 2D plane renderer
953    planeRenderer = new PlaneRenderer(winWidth, winHeight);
954
955    //assert(glGetError()==0);
956
957    TRACE("leaving initGL\n");
958}
959
960#ifdef DO_RLE
961char rle[512*512*3];
962int rleSize;
963
964short offsets[512*512*3];
965int offsetsSize;
966
967static void
968doRle()
969{
970    int len = NanoVis::winWidth*NanoVis::winHeight*3;
971    rleSize = 0;
972    offsetsSize = 0;
973
974    int i = 0;
975    while (i < len) {
976        if (NanoVis::screenBuffer[i] == 0) {
977            int pos = i+1;
978            while ( (pos < len) && (NanoVis::screenBuffer[pos] == 0)) {
979                pos++;
980            }
981            offsets[offsetsSize++] = -(pos - i);
982            i = pos;
983        }
984
985        else {
986            int pos;
987            for (pos = i; (pos < len) && (NanoVis::screenBuffer[pos] != 0); pos++){
988                rle[rleSize++] = NanoVis::screenBuffer[pos];
989            }
990            offsets[offsetsSize++] = (pos - i);
991            i = pos;
992        }
993
994    }
995}
996#endif
997
998// used internally to build up the BMP file header
999// Writes an integer value into the header data structure at pos
1000static inline void
1001bmpHeaderAddInt(unsigned char* header, int& pos, int data)
1002{
1003#ifdef WORDS_BIGENDIAN
1004    header[pos++] = (data >> 24) & 0xFF;
1005    header[pos++] = (data >> 16) & 0xFF;
1006    header[pos++] = (data >> 8)  & 0xFF;
1007    header[pos++] = (data)       & 0xFF;
1008#else
1009    header[pos++] = data & 0xff;
1010    header[pos++] = (data >> 8) & 0xff;
1011    header[pos++] = (data >> 16) & 0xff;
1012    header[pos++] = (data >> 24) & 0xff;
1013#endif
1014}
1015
1016// INSOO
1017// FOR DEBUGGING
1018void
1019NanoVis::bmpWriteToFile(int frame_number, const char *directory_name)
1020{
1021    unsigned char header[SIZEOF_BMP_HEADER];
1022    int pos = 0;
1023    header[pos++] = 'B';
1024    header[pos++] = 'M';
1025
1026    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
1027    // on each scan line.  If need be, we add padding to each line.
1028    int pad = 0;
1029    if ((3*winWidth) % 4 > 0) {
1030        pad = 4 - ((3*winWidth) % 4);
1031    }
1032
1033    // file size in bytes
1034    int fsize = (3*winWidth+pad)*winHeight + SIZEOF_BMP_HEADER;
1035    bmpHeaderAddInt(header, pos, fsize);
1036
1037    // reserved value (must be 0)
1038    bmpHeaderAddInt(header, pos, 0);
1039
1040    // offset in bytes to start of bitmap data
1041    bmpHeaderAddInt(header, pos, SIZEOF_BMP_HEADER);
1042
1043    // size of the BITMAPINFOHEADER
1044    bmpHeaderAddInt(header, pos, 40);
1045
1046    // width of the image in pixels
1047    bmpHeaderAddInt(header, pos, winWidth);
1048
1049    // height of the image in pixels
1050    bmpHeaderAddInt(header, pos, winHeight);
1051
1052    // 1 plane + (24 bits/pixel << 16)
1053    bmpHeaderAddInt(header, pos, 1572865);
1054
1055    // no compression
1056    // size of image for compression
1057    bmpHeaderAddInt(header, pos, 0);
1058    bmpHeaderAddInt(header, pos, 0);
1059
1060    // x pixels per meter
1061    // y pixels per meter
1062    bmpHeaderAddInt(header, pos, 0);
1063    bmpHeaderAddInt(header, pos, 0);
1064
1065    // number of colors used (0 = compute from bits/pixel)
1066    // number of important colors (0 = all colors important)
1067    bmpHeaderAddInt(header, pos, 0);
1068    bmpHeaderAddInt(header, pos, 0);
1069
1070    // BE CAREFUL: BMP format wants BGR ordering for screen data
1071    unsigned char* scr = screenBuffer;
1072    for (int row=0; row < winHeight; row++) {
1073        for (int col=0; col < winWidth; col++) {
1074            unsigned char tmp = scr[2];
1075            scr[2] = scr[0];  // B
1076            scr[0] = tmp;     // R
1077            scr += 3;
1078        }
1079        scr += pad;  // skip over padding already in screen data
1080    }
1081
1082    FILE* f;
1083    char filename[100];
1084    if (frame_number >= 0) {
1085        if (directory_name)
1086            sprintf(filename, "%s/image%03d.bmp", directory_name, frame_number);
1087        else
1088            sprintf(filename, "/tmp/flow_animation/image%03d.bmp", frame_number);
1089
1090        TRACE("Writing %s\n", filename);
1091        f = fopen(filename, "wb");
1092        if (f == 0) {
1093            ERROR("cannot create file\n");
1094        }
1095    } else {
1096        f = fopen("/tmp/image.bmp", "wb");
1097        if (f == 0) {
1098            ERROR("cannot create file\n");
1099        }
1100    }
1101    if (fwrite(header, SIZEOF_BMP_HEADER, 1, f) != 1) {
1102        ERROR("can't write header: short write\n");
1103    }
1104    if (fwrite(screenBuffer, (3*winWidth+pad)*winHeight, 1, f) != 1) {
1105        ERROR("can't write data: short write\n");
1106    }
1107    fclose(f);
1108}
1109
1110void
1111NanoVis::bmpWrite(const char *prefix)
1112{
1113    unsigned char header[SIZEOF_BMP_HEADER];
1114    ssize_t nWritten;
1115    int pos = 0;
1116
1117    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
1118    // on each scan line.  If need be, we add padding to each line.
1119    int pad = 0;
1120    if ((3*winWidth) % 4 > 0) {
1121        pad = 4 - ((3*winWidth) % 4);
1122    }
1123    pad = 0;
1124    int fsize = (3*winWidth+pad)*winHeight + sizeof(header);
1125
1126    char string[200];
1127    sprintf(string, "%s %d\n", prefix, fsize);
1128    nWritten = write(1, string, strlen(string));
1129    assert(nWritten == (ssize_t)strlen(string));
1130    header[pos++] = 'B';
1131    header[pos++] = 'M';
1132
1133    // file size in bytes
1134    bmpHeaderAddInt(header, pos, fsize);
1135
1136    // reserved value (must be 0)
1137    bmpHeaderAddInt(header, pos, 0);
1138
1139    // offset in bytes to start of bitmap data
1140    bmpHeaderAddInt(header, pos, SIZEOF_BMP_HEADER);
1141
1142    // size of the BITMAPINFOHEADER
1143    bmpHeaderAddInt(header, pos, 40);
1144
1145    // width of the image in pixels
1146    bmpHeaderAddInt(header, pos, winWidth);
1147
1148    // height of the image in pixels
1149    bmpHeaderAddInt(header, pos, winHeight);
1150
1151    // 1 plane + (24 bits/pixel << 16)
1152    bmpHeaderAddInt(header, pos, 1572865);
1153
1154    // no compression
1155    // size of image for compression
1156    bmpHeaderAddInt(header, pos, 0);
1157    bmpHeaderAddInt(header, pos, 0);
1158
1159    // x pixels per meter
1160    // y pixels per meter
1161    bmpHeaderAddInt(header, pos, 0);
1162    bmpHeaderAddInt(header, pos, 0);
1163
1164    // number of colors used (0 = compute from bits/pixel)
1165    // number of important colors (0 = all colors important)
1166    bmpHeaderAddInt(header, pos, 0);
1167    bmpHeaderAddInt(header, pos, 0);
1168
1169    // BE CAREFUL: BMP format wants BGR ordering for screen data
1170    unsigned char* scr = screenBuffer;
1171    for (int row=0; row < winHeight; row++) {
1172        for (int col=0; col < winWidth; col++) {
1173            unsigned char tmp = scr[2];
1174            scr[2] = scr[0];  // B
1175            scr[0] = tmp;     // R
1176            scr += 3;
1177        }
1178        scr += pad;  // skip over padding already in screen data
1179    }
1180
1181    nWritten = write(1, header, SIZEOF_BMP_HEADER);
1182    assert(nWritten == SIZEOF_BMP_HEADER);
1183    nWritten = write(1, screenBuffer, (3*winWidth+pad)*winHeight);
1184    assert(nWritten == (3*winWidth+pad)*winHeight);
1185    stats.nFrames++;
1186    stats.nBytes += (3*winWidth+pad)*winHeight;
1187}
1188
1189/*
1190 * ppmWrite --
1191 *
1192 *  Writes the screen image as PPM binary data to the nanovisviewer
1193 *  client.  The PPM binary format is very simple.
1194 *
1195 *      P6 w h 255\n
1196 *      3-byte RGB pixel data.
1197 *
1198 *  The nanovisviewer client (using the TkImg library) will do less work
1199 *  to unpack this format, as opposed to BMP or PNG.  (This doesn't
1200 *  eliminate the need to look into DXT compression performed on the GPU).
1201 *
1202 *      Note that currently the image data from the screen is both row-padded
1203 *      and the scan lines are reversed.  This routine could be made even
1204 *      simpler (faster) if the screen buffer is an array of packed 3-bytes
1205 *      per pixels (no padding) and where the origin is the top-left corner.
1206 */
1207void
1208NanoVis::ppmWrite(const char *prefix)
1209{
1210#define PPM_MAXVAL 255
1211    char header[200];
1212
1213    TRACE("Enter ppmWrite (%dx%d)\n", winWidth, winHeight);
1214    // Generate the PPM binary file header
1215    sprintf(header, "P6 %d %d %d\n", winWidth, winHeight, PPM_MAXVAL);
1216
1217    size_t header_length = strlen(header);
1218    size_t data_length = winWidth * winHeight * 3;
1219
1220    char command[200];
1221    sprintf(command, "%s %lu\n", prefix,
1222            (unsigned long)header_length + data_length);
1223
1224    size_t wordsPerRow = (winWidth * 24 + 31) / 32;
1225    size_t bytesPerRow = wordsPerRow * 4;
1226    size_t rowLength = winWidth * 3;
1227    size_t nRecs = winHeight + 2;
1228
1229    struct iovec *iov;
1230    iov = (struct iovec *)malloc(sizeof(struct iovec) * nRecs);
1231
1232    // Write the nanovisviewer command, then the image header and data.
1233    // Command
1234    iov[0].iov_base = command;
1235    iov[0].iov_len = strlen(command);
1236    // Header of image data
1237    iov[1].iov_base = header;
1238    iov[1].iov_len = header_length;
1239    // Image data.
1240    int y;
1241    unsigned char *srcRowPtr = screenBuffer;
1242    for (y = winHeight + 1; y >= 2; y--) {
1243        iov[y].iov_base = srcRowPtr;
1244        iov[y].iov_len = rowLength;
1245        srcRowPtr += bytesPerRow;
1246    }
1247    if (writev(1, iov, nRecs) < 0) {
1248        ERROR("write failed: %s\n", strerror(errno));
1249    }
1250    free(iov);
1251    stats.nFrames++;
1252    stats.nBytes += (bytesPerRow * winHeight);
1253    TRACE("Leaving ppmWrite (%dx%d)\n", winWidth, winHeight);
1254}
1255
1256void
1257NanoVis::sendDataToClient(const char *command, const char *data, size_t dlen)
1258{
1259    /*
1260      char header[200];
1261
1262      // Generate the PPM binary file header
1263      sprintf(header, "P6 %d %d %d\n", winWidth, winHeight, PPM_MAXVAL);
1264
1265      size_t header_length = strlen(header);
1266      size_t data_length = winWidth * winHeight * 3;
1267
1268      char command[200];
1269      sprintf(command, "%s %lu\n", prefix,
1270      (unsigned long)header_length + data_length);
1271    */
1272
1273    //    size_t wordsPerRow = (winWidth * 24 + 31) / 32;
1274    //    size_t bytesPerRow = wordsPerRow * 4;
1275    //    size_t rowLength = winWidth * 3;
1276    size_t nRecs = 2;
1277
1278    struct iovec *iov = new iovec[nRecs];
1279
1280    // Write the nanovisviewer command, then the image header and data.
1281    // Command
1282    // FIXME: shouldn't have to cast this
1283    iov[0].iov_base = (char *)command;
1284    iov[0].iov_len = strlen(command);
1285    // Data
1286    // FIXME: shouldn't have to cast this
1287    iov[1].iov_base = (char *)data;
1288    iov[1].iov_len = dlen;
1289    if (writev(1, iov, nRecs) < 0) {
1290        ERROR("write failed: %s\n", strerror(errno));
1291    }
1292    delete [] iov;
1293    // stats.nFrames++;
1294    // stats.nBytes += (bytesPerRow * winHeight);
1295}
1296
1297void
1298NanoVis::idle()
1299{
1300    TRACE("in idle()\n");
1301    glutSetWindow(renderWindow);
1302
1303#ifdef XINETD
1304    xinetdListen();
1305#else
1306    glutPostRedisplay();
1307#endif
1308    TRACE("leaving idle()\n");
1309}
1310
1311void
1312NanoVis::displayOffscreenBuffer()
1313{
1314    TRACE("in display_offscreen_buffer\n");
1315
1316    glEnable(GL_TEXTURE_2D);
1317    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1318    glBindTexture(GL_TEXTURE_2D, _finalColorTex);
1319
1320    glViewport(0, 0, winWidth, winHeight);
1321    glMatrixMode(GL_PROJECTION);
1322    glLoadIdentity();
1323    gluOrtho2D(0, winWidth, 0, winHeight);
1324    glMatrixMode(GL_MODELVIEW);
1325    glLoadIdentity();
1326
1327    glColor3f(1.,1.,1.);                //MUST HAVE THIS LINE!!!
1328    glBegin(GL_QUADS);
1329    {
1330        glTexCoord2f(0, 0); glVertex2f(0, 0);
1331        glTexCoord2f(1, 0); glVertex2f(winWidth, 0);
1332        glTexCoord2f(1, 1); glVertex2f(winWidth, winHeight);
1333        glTexCoord2f(0, 1); glVertex2f(0, winHeight);
1334    }
1335    glEnd();
1336
1337    TRACE("leaving display_offscreen_buffer\n");
1338}
1339
1340void
1341NanoVis::draw3dAxis()
1342{
1343    glPushAttrib(GL_ENABLE_BIT);
1344
1345    glDisable(GL_TEXTURE_2D);
1346    glEnable(GL_DEPTH_TEST);
1347    glEnable(GL_COLOR_MATERIAL);
1348    glDisable(GL_BLEND);
1349
1350    //draw axes
1351    GLUquadric *obj;
1352
1353    obj = gluNewQuadric();
1354
1355    int segments = 50;
1356
1357    glColor3f(0.8, 0.8, 0.8);
1358    glPushMatrix();
1359    glTranslatef(0.4, 0., 0.);
1360    glRotatef(90, 1, 0, 0);
1361    glRotatef(180, 0, 1, 0);
1362    glScalef(0.0005, 0.0005, 0.0005);
1363    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'x');
1364    glPopMatrix();
1365
1366    glPushMatrix();
1367    glTranslatef(0., 0.4, 0.);
1368    glRotatef(90, 1, 0, 0);
1369    glRotatef(180, 0, 1, 0);
1370    glScalef(0.0005, 0.0005, 0.0005);
1371    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'y');
1372    glPopMatrix();
1373
1374    glPushMatrix();
1375    glTranslatef(0., 0., 0.4);
1376    glRotatef(90, 1, 0, 0);
1377    glRotatef(180, 0, 1, 0);
1378    glScalef(0.0005, 0.0005, 0.0005);
1379    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'z');
1380    glPopMatrix();
1381
1382    glEnable(GL_LIGHTING);
1383    glEnable(GL_LIGHT0);
1384
1385    //glColor3f(0.2, 0.2, 0.8);
1386    glPushMatrix();
1387    glutSolidSphere(0.02, segments, segments );
1388    glPopMatrix();
1389
1390    glPushMatrix();
1391    glRotatef(-90, 1, 0, 0);
1392    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1393    glPopMatrix();
1394
1395    glPushMatrix();
1396    glTranslatef(0., 0.3, 0.);
1397    glRotatef(-90, 1, 0, 0);
1398    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1399    glPopMatrix();
1400
1401    glPushMatrix();
1402    glRotatef(90, 0, 1, 0);
1403    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1404    glPopMatrix();
1405
1406    glPushMatrix();
1407    glTranslatef(0.3, 0., 0.);
1408    glRotatef(90, 0, 1, 0);
1409    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1410    glPopMatrix();
1411
1412    glPushMatrix();
1413    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1414    glPopMatrix();
1415
1416    glPushMatrix();
1417    glTranslatef(0., 0., 0.3);
1418    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1419    glPopMatrix();
1420
1421    gluDeleteQuadric(obj);
1422
1423    glPopAttrib();
1424}
1425
1426void NanoVis::update()
1427{
1428    VolumeInterpolator *volInterp = volRenderer->getVolumeInterpolator();
1429    if (volInterp->isStarted()) {
1430        struct timeval clock;
1431        gettimeofday(&clock, NULL);
1432        double elapsed_time;
1433
1434        elapsed_time = clock.tv_sec + clock.tv_usec/1000000.0 -
1435            volInterp->getStartTime();
1436
1437        TRACE("%lf %lf\n", elapsed_time,
1438              volInterp->getInterval());
1439        float fraction;
1440        float f;
1441
1442        f = fmod((float) elapsed_time, (float)volInterp->getInterval());
1443        if (f == 0.0) {
1444            fraction = 0.0f;
1445        } else {
1446            fraction = f / volInterp->getInterval();
1447        }
1448        TRACE("fraction : %f\n", fraction);
1449        volInterp->update(fraction);
1450    }
1451}
1452
1453void
1454NanoVis::setVolumeRanges()
1455{
1456    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1457
1458    TRACE("in SetVolumeRanges\n");
1459    xMin = yMin = zMin = wMin = DBL_MAX;
1460    xMax = yMax = zMax = wMax = -DBL_MAX;
1461    Tcl_HashEntry *hPtr;
1462    Tcl_HashSearch iter;
1463    for (hPtr = Tcl_FirstHashEntry(&volumeTable, &iter); hPtr != NULL;
1464         hPtr = Tcl_NextHashEntry(&iter)) {
1465        Volume *volPtr = (Volume *)Tcl_GetHashValue(hPtr);
1466        if (xMin > volPtr->xAxis.min()) {
1467            xMin = volPtr->xAxis.min();
1468        }
1469        if (xMax < volPtr->xAxis.max()) {
1470            xMax = volPtr->xAxis.max();
1471        }
1472        if (yMin > volPtr->yAxis.min()) {
1473            yMin = volPtr->yAxis.min();
1474        }
1475        if (yMax < volPtr->yAxis.max()) {
1476            yMax = volPtr->yAxis.max();
1477        }
1478        if (zMin > volPtr->zAxis.min()) {
1479            zMin = volPtr->zAxis.min();
1480        }
1481        if (zMax < volPtr->zAxis.max()) {
1482            zMax = volPtr->zAxis.max();
1483        }
1484        if (wMin > volPtr->wAxis.min()) {
1485            wMin = volPtr->wAxis.min();
1486        }
1487        if (wMax < volPtr->wAxis.max()) {
1488            wMax = volPtr->wAxis.max();
1489        }
1490    }
1491    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1492        grid->xAxis.setScale(xMin, xMax);
1493    }
1494    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1495        grid->yAxis.setScale(yMin, yMax);
1496    }
1497    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1498        grid->zAxis.setScale(zMin, zMax);
1499    }
1500    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1501        Volume::valueMin = wMin;
1502        Volume::valueMax = wMax;
1503    }
1504    Volume::updatePending = false;
1505    TRACE("leaving SetVolumeRanges\n");
1506}
1507
1508void
1509NanoVis::setHeightmapRanges()
1510{
1511    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1512
1513    TRACE("in setHeightmapRanges\n");
1514    xMin = yMin = zMin = wMin = DBL_MAX;
1515    xMax = yMax = zMax = wMax = -DBL_MAX;
1516    Tcl_HashEntry *hPtr;
1517    Tcl_HashSearch iter;
1518    for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1519         hPtr = Tcl_NextHashEntry(&iter)) {
1520        HeightMap *hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1521        if (xMin > hmPtr->xAxis.min()) {
1522            xMin = hmPtr->xAxis.min();
1523        }
1524        if (xMax < hmPtr->xAxis.max()) {
1525            xMax = hmPtr->xAxis.max();
1526        }
1527        if (yMin > hmPtr->yAxis.min()) {
1528            yMin = hmPtr->yAxis.min();
1529        }
1530        if (yMax < hmPtr->yAxis.max()) {
1531            yMax = hmPtr->yAxis.max();
1532        }
1533        if (zMin > hmPtr->zAxis.min()) {
1534            zMin = hmPtr->zAxis.min();
1535        }
1536        if (zMax < hmPtr->zAxis.max()) {
1537            zMax = hmPtr->zAxis.max();
1538        }
1539        if (wMin > hmPtr->wAxis.min()) {
1540            wMin = hmPtr->wAxis.min();
1541        }
1542        if (wMax < hmPtr->wAxis.max()) {
1543            wMax = hmPtr->wAxis.max();
1544        }
1545    }
1546    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1547        grid->xAxis.setScale(xMin, xMax);
1548    }
1549    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1550        grid->yAxis.setScale(yMin, yMax);
1551    }
1552    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1553        grid->zAxis.setScale(zMin, zMax);
1554    }
1555    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1556        HeightMap::valueMin = grid->yAxis.min();
1557        HeightMap::valueMax = grid->yAxis.max();
1558    }
1559    for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1560         hPtr = Tcl_NextHashEntry(&iter)) {
1561        HeightMap *hmPtr;
1562        hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1563        hmPtr->mapToGrid(grid);
1564    }
1565    HeightMap::updatePending = false;
1566    TRACE("leaving setHeightmapRanges\n");
1567}
1568
1569void
1570NanoVis::display()
1571{
1572    TRACE("in display\n");
1573    if (flags & MAP_FLOWS) {
1574#ifdef notdef
1575        xMin = yMin = zMin = wMin = FLT_MAX, magMin = DBL_MAX;
1576        xMax = yMax = zMax = wMax = -FLT_MAX, magMax = -DBL_MAX;
1577#endif
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        volRenderer->renderAll();
1659
1660        if (heightmapTable.numEntries > 0) {
1661            TRACE("in display: render heightmap\n");
1662            Tcl_HashEntry *hPtr;
1663            Tcl_HashSearch iter;
1664            for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1665                 hPtr = Tcl_NextHashEntry(&iter)) {
1666                HeightMap *hmPtr;
1667                hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1668                if (hmPtr->isVisible()) {
1669                    hmPtr->render(renderContext);
1670                }
1671            }
1672        }
1673        glPopMatrix();
1674    } else {
1675        //2D rendering mode
1676        perf->enable();
1677        planeRenderer->render();
1678        perf->disable();
1679    }
1680
1681    perf->reset();
1682    CHECK_FRAMEBUFFER_STATUS();
1683    TRACE("leaving display\n");
1684}
1685
1686#ifndef XINETD
1687void
1688NanoVis::mouse(int button, int state, int x, int y)
1689{
1690    if (button == GLUT_LEFT_BUTTON) {
1691        if (state == GLUT_DOWN) {
1692            left_last_x = x;
1693            left_last_y = y;
1694            left_down = true;
1695            right_down = false;
1696        } else {
1697            left_down = false;
1698            right_down = false;
1699        }
1700    } else {
1701        //TRACE("right mouse\n");
1702
1703        if (state == GLUT_DOWN) {
1704            //TRACE("right mouse down\n");
1705            right_last_x = x;
1706            right_last_y = y;
1707            left_down = false;
1708            right_down = true;
1709        } else {
1710            //TRACE("right mouse up\n");
1711            left_down = false;
1712            right_down = false;
1713        }
1714    }
1715}
1716
1717void
1718NanoVis::updateRot(int delta_x, int delta_y)
1719{
1720    Vector3 angle;
1721
1722    angle = cam->rotate();
1723    angle.x += delta_x;
1724    angle.y += delta_y;
1725
1726    if (angle.x > 360.0) {
1727        angle.x -= 360.0;
1728    } else if(angle.x < -360.0) {
1729        angle.x += 360.0;
1730    }
1731    if (angle.y > 360.0) {
1732        angle.y -= 360.0;
1733    } else if(angle.y < -360.0) {
1734        angle.y += 360.0;
1735    }
1736    cam->rotate(angle);
1737}
1738
1739void
1740NanoVis::updateTrans(int delta_x, int delta_y, int delta_z)
1741{
1742    cam->x(cam->x() + delta_x * 0.03);
1743    cam->y(cam->y() + delta_y * 0.03);
1744    cam->z(cam->z() + delta_z * 0.03);
1745}
1746
1747void
1748NanoVis::keyboard(unsigned char key, int x, int y)
1749{
1750#ifdef EVENTLOG
1751    if (log) {
1752        float param[3];
1753        param[0] = cam->x();
1754        param[1] = cam->y();
1755        param[2] = cam->z();
1756        Event* tmp = new Event(EVENT_MOVE, param, NvGetTimeInterval());
1757        tmp->write(event_log);
1758        delete tmp;
1759    }
1760#endif
1761
1762    switch (key) {
1763    case 'a': {
1764        TRACE("flowvis activated\n");
1765        char cmd[] = {
1766            "foreach flow [flow names] {\n"
1767            "    $flow configure -hide no -slice yes\n"
1768            "}\n"
1769        };
1770        Tcl_Eval(interp, cmd);
1771    }
1772        break;
1773    case 'd': {
1774        TRACE("flowvis deactivated\n");
1775        char cmd[] = {
1776            "foreach flow [flow names] {\n"
1777            "    $flow configure -hide yes -slice no\n"
1778            "}\n"
1779        };
1780        Tcl_Eval(interp, cmd);
1781    }
1782        break;
1783    case 'r': {
1784        TRACE("flowvis reset\n");
1785        char cmd[] = {
1786            "flow reset\n"
1787        };
1788        Tcl_Eval(interp, cmd);
1789    }
1790        break;
1791    }
1792}
1793
1794void
1795NanoVis::motion(int x, int y)
1796{
1797    int old_x, old_y;
1798
1799    if (left_down) {
1800        old_x = left_last_x;
1801        old_y = left_last_y;
1802    } else if (right_down) {
1803        old_x = right_last_x;
1804        old_y = right_last_y;
1805    }
1806
1807    int delta_x = x - old_x;
1808    int delta_y = y - old_y;
1809
1810    //more coarse event handling
1811    //if(abs(delta_x)<10 && abs(delta_y)<10)
1812    //return;
1813
1814    if (left_down) {
1815        left_last_x = x;
1816        left_last_y = y;
1817
1818        updateRot(-delta_y, -delta_x);
1819    } else if (right_down) {
1820        //TRACE("right mouse motion (%d,%d)\n", x, y);
1821
1822        right_last_x = x;
1823        right_last_y = y;
1824
1825        updateTrans(0, 0, delta_x);
1826    }
1827
1828#ifdef EVENTLOG
1829    Vector3 angle = cam->rotate();
1830    Event* tmp = new Event(EVENT_ROTATE, &angle, NvGetTimeInterval());
1831    tmp->write(event_log);
1832    delete tmp;
1833#endif
1834    glutPostRedisplay();
1835}
1836
1837void
1838NanoVis::render()
1839{
1840    if (licRenderer != NULL) {
1841        licRenderer->convolve();
1842    }
1843
1844#ifdef notdef
1845    if ((flowVisRenderer != NULL) && (flowVisRenderer->active())) {
1846        flowVisRenderer->advect();
1847    }
1848#endif
1849    update();
1850    display();
1851    glutSwapBuffers();
1852}
1853
1854void
1855NanoVis::resize(int x, int y)
1856{
1857    glViewport(0, 0, x, y);
1858}
1859
1860#endif /*XINETD*/
1861
1862void
1863NanoVis::xinetdListen()
1864{
1865    flags &= ~REDRAW_PENDING;
1866
1867    TRACE("Enter xinetdListen\n");
1868
1869    int flags = fcntl(0, F_GETFL, 0);
1870    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
1871
1872    int status = TCL_OK;
1873
1874    //  Read and execute as many commands as we can from stdin...
1875    Tcl_DString cmdbuffer;
1876    Tcl_DStringInit(&cmdbuffer);
1877    int nCommands = 0;
1878    bool isComplete = false;
1879    while ((!feof(NanoVis::stdin)) && (status == TCL_OK)) {
1880        //
1881        //  Read the next command from the buffer.  First time through we
1882        //  block here and wait if necessary until a command comes in.
1883        //
1884        //  BE CAREFUL: Read only one command, up to a newline.  The "volume
1885        //  data follows" command needs to be able to read the data
1886        //  immediately following the command, and we shouldn't consume it
1887        //  here.
1888        //
1889        TRACE("in xinetdListen: EOF=%d\n", feof(NanoVis::stdin));
1890        while (!feof(NanoVis::stdin)) {
1891            int c = fgetc(NanoVis::stdin);
1892            char ch;
1893            if (c <= 0) {
1894                if (errno == EWOULDBLOCK) {
1895                    break;
1896                }
1897                doExit(100);
1898            }
1899            ch = (char)c;
1900            Tcl_DStringAppend(&cmdbuffer, &ch, 1);
1901            if (ch == '\n') {
1902                isComplete = Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer));
1903                if (isComplete) {
1904                    break;
1905                }
1906            }
1907        }
1908        // no command? then we're done for now
1909        if (Tcl_DStringLength(&cmdbuffer) == 0) {
1910            break;
1911        }
1912        if (isComplete) {
1913            // back to original flags during command evaluation...
1914            fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
1915            status = executeCommand(interp, &cmdbuffer);
1916            // non-blocking for next read -- we might not get anything
1917            fcntl(0, F_SETFL, flags | O_NONBLOCK);
1918            isComplete = false;
1919            nCommands++;
1920            CHECK_FRAMEBUFFER_STATUS();
1921        }
1922    }
1923    fcntl(0, F_SETFL, flags);
1924
1925    if (status != TCL_OK) {
1926        char *msg;
1927        char hdr[200];
1928        int msgSize, hdrSize;
1929        Tcl_Obj *objPtr;
1930
1931        objPtr = Tcl_GetObjResult(interp);
1932        msg = Tcl_GetStringFromObj(objPtr, &msgSize);
1933        hdrSize = sprintf(hdr, "nv>viserror -type internal_error -bytes %d\n", msgSize);
1934        {
1935            struct iovec iov[2];
1936
1937            iov[0].iov_base = hdr;
1938            iov[0].iov_len = hdrSize;
1939            iov[1].iov_base = msg;
1940            iov[1].iov_len = msgSize;
1941            if (writev(1, iov, 2) < 0) {
1942                ERROR("write failed: %s\n", strerror(errno));
1943            }
1944        }
1945        TRACE("Leaving xinetd_listen on ERROR\n");
1946        return;
1947    }
1948    if (feof(NanoVis::stdin)) {
1949        doExit(90);
1950    }
1951
1952    update();
1953
1954    bindOffscreenBuffer();  //enable offscreen render
1955
1956    display();
1957
1958#ifdef XINETD
1959    readScreen();
1960#else
1961    displayOffscreenBuffer(); //display the final rendering on screen
1962    readScreen();
1963    glutSwapBuffers();
1964#endif
1965
1966    if (feof(NanoVis::stdin)) {
1967        doExit(90);
1968    }
1969#ifdef DO_RLE
1970    do_rle();
1971    int sizes[2] = {  offsets_size*sizeof(offsets[0]), rle_size };
1972    TRACE("Writing %d,%d\n", sizes[0], sizes[1]);
1973    write(1, &sizes, sizeof(sizes));
1974    write(1, offsets, offsets_size*sizeof(offsets[0]));
1975    write(1, rle, rle_size);    //unsigned byte
1976#else
1977    ppmWrite("nv>image -type image -bytes");
1978#endif
1979    TRACE("Leaving xinetd_listen OK\n");
1980}
1981
1982int
1983main(int argc, char **argv)
1984{
1985    const char *path;
1986    char *newPath;
1987
1988    newPath = NULL;
1989    path = NULL;
1990    NanoVis::stdin = stdin;
1991
1992    fprintf(stdout, "NanoVis %s (build %s)\n", NANOVIS_VERSION, SVN_VERSION);
1993    fflush(stdout);
1994
1995    openlog("nanovis", LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
1996    gettimeofday(&NanoVis::startTime, NULL);
1997    stats.start = NanoVis::startTime;
1998
1999    /* Initialize GLUT here so it can parse and remove GLUT-specific
2000     * command-line options before we parse the command-line below. */
2001    glutInit(&argc, argv);
2002    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
2003    glutInitWindowSize(NanoVis::winWidth, NanoVis::winHeight);
2004    glutInitWindowPosition(10, 10);
2005    NanoVis::renderWindow = glutCreateWindow("nanovis");
2006    glutIdleFunc(NanoVis::idle);
2007
2008#ifndef XINETD
2009    glutMouseFunc(NanoVis::mouse);
2010    glutMotionFunc(NanoVis::motion);
2011    glutKeyboardFunc(NanoVis::keyboard);
2012    glutReshapeFunc(NanoVis::resize);
2013    glutDisplayFunc(NanoVis::render);
2014#else
2015    glutDisplayFunc(NanoVis::display);
2016    glutReshapeFunc(NanoVis::resizeOffscreenBuffer);
2017#endif
2018
2019    while (1) {
2020        static struct option long_options[] = {
2021            {"infile",  required_argument, NULL, 0},
2022            {"path",    required_argument, NULL, 2},
2023            {"debug",   no_argument,       NULL, 3},
2024            {"record",  required_argument, NULL, 4},
2025            {0, 0, 0, 0}
2026        };
2027        int option_index = 0;
2028        int c;
2029
2030        c = getopt_long(argc, argv, ":dp:i:l:r:", long_options, &option_index);
2031        if (c == -1) {
2032            break;
2033        }
2034        switch (c) {
2035        case '?':
2036            fprintf(stderr, "unknown option -%c\n", optopt);
2037            return 1;
2038        case ':':
2039            if (optopt < 4) {
2040                fprintf(stderr, "argument missing for --%s option\n",
2041                        long_options[optopt].name);
2042            } else {
2043                fprintf(stderr, "argument missing for -%c option\n", optopt);
2044            }
2045            return 1;
2046        case 2:
2047        case 'p':
2048            path = optarg;
2049            break;
2050        case 3:
2051        case 'd':
2052            NanoVis::debugFlag = true;
2053            break;
2054        case 0:
2055        case 'i':
2056            NanoVis::stdin = fopen(optarg, "r");
2057            if (NanoVis::stdin == NULL) {
2058                perror(optarg);
2059                return 2;
2060            }
2061            break;
2062        case 4:
2063        case 'r':
2064            Tcl_DString ds;
2065            char buf[200];
2066
2067            Tcl_DStringInit(&ds);
2068            Tcl_DStringAppend(&ds, optarg, -1);
2069            sprintf(buf, ".%d", getpid());
2070            Tcl_DStringAppend(&ds, buf, -1);
2071            NanoVis::recfile = fopen(Tcl_DStringValue(&ds), "w");
2072            if (NanoVis::recfile == NULL) {
2073                perror(optarg);
2074                return 2;
2075            }
2076            break;
2077        default:
2078            fprintf(stderr,"unknown option '%c'.\n", c);
2079            return 1;
2080        }
2081    }     
2082    if (path == NULL) {
2083        char *p;
2084
2085        // See if we can derive the path from the location of the program.
2086        // Assume program is in the form <path>/bin/nanovis.
2087
2088#ifdef XINETD
2089        path = argv[0];
2090        p = strrchr((char *)path, '/');
2091        if (p != NULL) {
2092            *p = '\0';
2093            p = strrchr((char *)path, '/');
2094        }
2095        if (p == NULL) {
2096            TRACE("path not specified\n");
2097            return 1;
2098        }
2099        *p = '\0';
2100        newPath = new char[(strlen(path) + 15) * 2 + 1];
2101        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", path, path);
2102        path = newPath;
2103#else
2104        char buff[256];
2105        getcwd(buff, 255);
2106        p = strrchr(buff, '/');
2107        if (p != NULL) {
2108            *p = '\0';
2109        }
2110        newPath = new char[(strlen(buff) + 15) * 2 + 1];
2111        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", buff, buff);
2112        path = newPath;
2113#endif
2114    }
2115
2116    R2FilePath::getInstance()->setWorkingDirectory(argc, (const char**) argv);
2117
2118#ifdef XINETD
2119#ifdef notdef
2120    signal(SIGPIPE, SIG_IGN);
2121#endif
2122    NvInitService();
2123#endif
2124
2125    NanoVis::init(path);
2126    if (newPath != NULL) {
2127        delete [] newPath;
2128    }
2129    NanoVis::initGL();
2130#ifdef EVENTLOG
2131    NvInitEventLog();
2132#endif
2133    NanoVis::interp = initTcl();
2134    NanoVis::resizeOffscreenBuffer(NanoVis::winWidth, NanoVis::winHeight);
2135
2136    glutMainLoop();
2137    doExit(80);
2138}
2139
2140void
2141NanoVis::removeVolume(Volume *volPtr)
2142{
2143    Tcl_HashEntry *hPtr;
2144    hPtr = Tcl_FindHashEntry(&volumeTable, volPtr->name());
2145    if (hPtr != NULL) {
2146        Tcl_DeleteHashEntry(hPtr);
2147    }
2148    delete volPtr;
2149}
Note: See TracBrowser for help on using the repository browser.