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

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

Remove unused Event logging, move init/exit service routines to nanovis.cpp

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