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

Last change on this file since 3377 was 3377, checked in by gah, 12 years ago

rework of stats log file.

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