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

Last change on this file since 3452 was 3452, checked in by ldelgass, 7 years ago

Remove XINETD define from nanovis. We only support server mode now, no glut
interaction loop with mouse/keyboard handlers. Fixes for trace logging to make
output closer to vtkvis: inlcude function name for trace messages, remove
newlines from format strings in macros since newlines get added by syslog.

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