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

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

Remove Nv prefix from shader classes now that they are in nv namespace.

  • Property svn:eol-style set to native
File size: 31.4 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * ----------------------------------------------------------------------
4 * Nanovis: Visualization of Nanoelectronics Data
5 *
6 * ======================================================================
7 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
8 *           Michael McLennan <mmclennan@purdue.edu>
9 *           Purdue Rendering and Perceptualization Lab (PURPL)
10 *
11 *  Copyright (c) 2004-2013  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 <sys/time.h>
19#include <cassert>
20#include <cstdio>
21
22#include <GL/glew.h>
23#include <GL/glut.h>
24
25#include <graphics/RenderContext.h>
26#include <vrmath/Vector3f.h>
27
28#include <util/FilePath.h>
29#include <util/Fonts.h>
30
31#include <BMPImageLoaderImpl.h>
32#include <ImageLoaderFactory.h>
33
34#include "config.h"
35#include "nanovis.h"
36#include "nanovisServer.h"
37#include "define.h"
38
39#include "Flow.h"
40#include "Grid.h"
41#include "HeightMap.h"
42#include "Camera.h"
43#include "LIC.h"
44#include "Shader.h"
45#include "OrientationIndicator.h"
46#include "PlaneRenderer.h"
47#include "PPMWriter.h"
48#include "Texture2D.h"
49#include "Trace.h"
50#include "TransferFunction.h"
51#include "Unirect.h"
52#include "VelocityArrowsSlice.h"
53#include "Volume.h"
54#include "VolumeInterpolator.h"
55#include "VolumeRenderer.h"
56
57using namespace nv;
58using namespace nv::graphics;
59using namespace nv::util;
60using namespace vrmath;
61
62// STATIC MEMBER DATA
63
64Tcl_Interp *NanoVis::interp = NULL;
65
66unsigned int NanoVis::flags = 0;
67bool NanoVis::debugFlag = false;
68
69int NanoVis::winWidth = NPIX;
70int NanoVis::winHeight = NPIX;
71int NanoVis::renderWindow = 0;
72unsigned char *NanoVis::screenBuffer = NULL;
73Texture2D *NanoVis::legendTexture = NULL;
74Fonts *NanoVis::fonts;
75int NanoVis::updir = Y_POS;
76Camera *NanoVis::cam = NULL;
77RenderContext *NanoVis::renderContext = NULL;
78
79NanoVis::TransferFunctionHashmap NanoVis::tfTable;
80NanoVis::VolumeHashmap NanoVis::volumeTable;
81NanoVis::FlowHashmap NanoVis::flowTable;
82NanoVis::HeightMapHashmap NanoVis::heightMapTable;
83
84double NanoVis::magMin = DBL_MAX;
85double NanoVis::magMax = -DBL_MAX;
86float NanoVis::xMin = FLT_MAX;
87float NanoVis::xMax = -FLT_MAX;
88float NanoVis::yMin = FLT_MAX;
89float NanoVis::yMax = -FLT_MAX;
90float NanoVis::zMin = FLT_MAX;
91float NanoVis::zMax = -FLT_MAX;
92float NanoVis::wMin = FLT_MAX;
93float NanoVis::wMax = -FLT_MAX;
94Vector3f NanoVis::sceneMin, NanoVis::sceneMax;
95
96VolumeRenderer *NanoVis::volRenderer = NULL;
97VelocityArrowsSlice *NanoVis::velocityArrowsSlice = NULL;
98LIC *NanoVis::licRenderer = NULL;
99PlaneRenderer *NanoVis::planeRenderer = NULL;
100OrientationIndicator *NanoVis::orientationIndicator = NULL;
101Grid *NanoVis::grid = NULL;
102
103// Image based flow visualization slice location
104// FLOW
105float NanoVis::_licSlice = 0.5f;
106int NanoVis::_licAxis = 2; // z axis
107
108//frame buffer for final rendering
109GLuint NanoVis::_finalFbo = 0;
110GLuint NanoVis::_finalColorTex = 0;
111GLuint NanoVis::_finalDepthRb = 0;
112
113// Default camera location.
114float def_eye_x = 0.0f;
115float def_eye_y = 0.0f;
116float def_eye_z = 2.5f;
117
118void
119NanoVis::removeAllData()
120{
121    TRACE("Enter");
122    if (grid != NULL) {
123        TRACE("Deleting grid");
124        delete grid;
125    }
126    if (cam != NULL) {
127        TRACE("Deleting cam");
128        delete cam;
129    }
130    if (volRenderer != NULL) {
131        TRACE("Deleting volRenderer");
132        delete volRenderer;
133    }
134    if (planeRenderer != NULL) {
135        TRACE("Deleting planeRenderer");
136        delete planeRenderer;
137    }
138    if (legendTexture != NULL) {
139        TRACE("Deleting legendTexture");
140        delete legendTexture;
141    }
142    TRACE("Deleting flows");
143    deleteFlows(interp);
144    if (licRenderer != NULL) {
145        TRACE("Deleting licRenderer");
146        delete licRenderer;
147    }
148    if (velocityArrowsSlice != NULL) {
149        TRACE("Deleting velocityArrowsSlice");
150        delete velocityArrowsSlice;
151    }
152    if (renderContext != NULL) {
153        TRACE("Deleting renderContext");
154        delete renderContext;
155    }
156    if (screenBuffer != NULL) {
157        TRACE("Deleting screenBuffer");
158        delete [] screenBuffer;
159        screenBuffer = NULL;
160    }
161    if (fonts != NULL) {
162        TRACE("Deleting fonts");
163        delete fonts;
164    }
165    TRACE("Leave");
166}
167
168void
169NanoVis::eventuallyRedraw(unsigned int flag)
170{
171    if (flag) {
172        flags |= flag;
173    }
174    if ((flags & REDRAW_PENDING) == 0) {
175        glutPostRedisplay();
176        flags |= REDRAW_PENDING;
177    }
178}
179
180void
181NanoVis::pan(float dx, float dy)
182{
183    /* Move the camera and its target by equal amounts along the x and y
184     * axes. */
185    TRACE("pan: x=%f, y=%f", dx, dy);
186
187    cam->x(def_eye_x - dx);
188    cam->y(def_eye_y + dy);
189    TRACE("set eye to %f %f", cam->x(), cam->y());
190}
191
192void
193NanoVis::zoom(float z)
194{
195    /* Move the camera and its target by equal amounts along the x and y
196     * axes. */
197    TRACE("zoom: z=%f", z);
198
199    cam->z(def_eye_z / z);
200
201    collectBounds();
202    cam->resetClippingRange(sceneMin, sceneMax);
203
204    TRACE("set cam z to %f", cam->z());
205}
206
207void
208NanoVis::resetCamera(bool resetOrientation)
209{
210    TRACE("Resetting all=%d", resetOrientation ? 1 : 0);
211
212    collectBounds();
213    cam->reset(sceneMin, sceneMax, resetOrientation);
214
215    def_eye_x = cam->x();
216    def_eye_y = cam->y();
217    def_eye_z = cam->z();
218}
219
220/** \brief Load a 3D volume
221 *
222 * \param name Volume ID
223 * \param width Number of samples in X direction
224 * \param height Number of samples in Y direction
225 * \param depth Number of samples in Z direction
226 * \param numComponents the number of scalars for each space point. All component
227 * scalars for a point are placed consequtively in data array
228 * width, height and depth: number of points in each dimension
229 * \param data Array of floats
230 * \param vmin Min value of field
231 * \param vmax Max value of field
232 * \param nonZeroMin Minimum non-zero value of field
233 * \param data pointer to an array of floats.
234 */
235Volume *
236NanoVis::loadVolume(const char *name, int width, int height, int depth,
237                    int numComponents, float *data, double vmin, double vmax,
238                    double nonZeroMin)
239{
240    VolumeHashmap::iterator itr = volumeTable.find(name);
241    if (itr != volumeTable.end()) {
242        WARN("volume \"%s\" already exists", name);
243        removeVolume(itr->second);
244    }
245
246    Volume *volume = new Volume(0.f, 0.f, 0.f,
247                                width, height, depth,
248                                numComponents,
249                                data, vmin, vmax, nonZeroMin);
250    Volume::updatePending = true;
251    volume->name(name);
252    volumeTable[name] = volume;
253
254    return volume;
255}
256
257// Gets a colormap 1D texture by name.
258TransferFunction *
259NanoVis::getTransferFunction(const TransferFunctionId& id)
260{
261    TransferFunctionHashmap::iterator itr = tfTable.find(id);
262    if (itr == tfTable.end()) {
263        TRACE("No transfer function named \"%s\" found", id.c_str());
264        return NULL;
265    } else {
266        return itr->second;
267    }
268}
269
270// Creates of updates a colormap 1D texture by name.
271TransferFunction *
272NanoVis::defineTransferFunction(const TransferFunctionId& id,
273                                size_t n, float *data)
274{
275    TransferFunction *tf = getTransferFunction(id);
276    if (tf == NULL) {
277        TRACE("Creating new transfer function \"%s\"", id.c_str());
278        tf = new TransferFunction(id.c_str(), n, data);
279        tfTable[id] = tf;
280    } else {
281        TRACE("Updating existing transfer function \"%s\"", id.c_str());
282        tf->update(n, data);
283    }
284    return tf;
285}
286
287int
288NanoVis::renderLegend(TransferFunction *tf, double min, double max,
289                      int width, int height, const char *volArg)
290{
291    TRACE("Enter");
292
293    int old_width = winWidth;
294    int old_height = winHeight;
295
296    planeRenderer->setScreenSize(width, height);
297    resizeOffscreenBuffer(width, height);
298
299    // generate data for the legend
300    float data[512];
301    for (int i=0; i < 256; i++) {
302        data[i] = data[i+256] = (float)(i/255.0);
303    }
304    legendTexture = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
305    int index = planeRenderer->addPlane(legendTexture, tf);
306    planeRenderer->setActivePlane(index);
307
308    bindOffscreenBuffer();
309    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
310    planeRenderer->render();
311
312    glPixelStorei(GL_PACK_ALIGNMENT, 1);
313    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screenBuffer);
314    {
315        char prefix[200];
316
317        TRACE("Sending ppm legend image %s min:%g max:%g", volArg, min, max);
318        sprintf(prefix, "nv>legend %s %g %g", volArg, min, max);
319#ifdef USE_THREADS
320        queuePPM(g_queue, prefix, screenBuffer, width, height);
321#else
322        writePPM(g_fdOut, prefix, screenBuffer, width, height);
323#endif
324    }
325    planeRenderer->removePlane(index);
326    resizeOffscreenBuffer(old_width, old_height);
327
328    delete legendTexture;
329    legendTexture = NULL;
330    TRACE("Leave");
331    return TCL_OK;
332}
333
334//initialize frame buffer objects for offscreen rendering
335bool
336NanoVis::initOffscreenBuffer()
337{
338    TRACE("Enter");
339    assert(_finalFbo == 0);
340    // Initialize a fbo for final display.
341    glGenFramebuffersEXT(1, &_finalFbo);
342
343    glGenTextures(1, &_finalColorTex);
344    glBindTexture(GL_TEXTURE_2D, _finalColorTex);
345
346    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
347    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
348    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
349
350#if defined(HAVE_FLOAT_TEXTURES) && defined(USE_HALF_FLOAT)
351    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, winWidth, winHeight, 0,
352                 GL_RGB, GL_INT, NULL);
353#elif defined(HAVE_FLOAT_TEXTURES)
354    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, winWidth, winHeight, 0,
355                 GL_RGB, GL_INT, NULL);
356#else
357    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, winWidth, winHeight, 0,
358                 GL_RGB, GL_INT, NULL);
359#endif
360
361    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _finalFbo);
362    glGenRenderbuffersEXT(1, &_finalDepthRb);
363    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
364    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24,
365                             winWidth, winHeight);
366    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
367                              GL_TEXTURE_2D, _finalColorTex, 0);
368    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
369                                 GL_RENDERBUFFER_EXT, _finalDepthRb);
370
371    GLenum status;
372    if (!CheckFBO(&status)) {
373        PrintFBOStatus(status, "finalFbo");
374        return false;
375    }
376
377    TRACE("Leave");
378    return true;
379}
380
381//resize the offscreen buffer
382bool
383NanoVis::resizeOffscreenBuffer(int w, int h)
384{
385    TRACE("Enter (%d, %d)", w, h);
386    if ((w == winWidth) && (h == winHeight)) {
387        return true;
388    }
389    winWidth = w;
390    winHeight = h;
391
392    if (fonts) {
393        fonts->resize(w, h);
394    }
395    TRACE("screenBuffer size: %d %d", w, h);
396
397    if (screenBuffer != NULL) {
398        delete [] screenBuffer;
399        screenBuffer = NULL;
400    }
401
402    screenBuffer = new unsigned char[3*winWidth*winHeight];
403    assert(screenBuffer != NULL);
404
405    //delete the current render buffer resources
406    glDeleteTextures(1, &_finalColorTex);
407    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
408    glDeleteRenderbuffersEXT(1, &_finalDepthRb);
409
410    TRACE("before deleteframebuffers");
411    glDeleteFramebuffersEXT(1, &_finalFbo);
412
413    TRACE("reinitialize FBO");
414    //Reinitialize final fbo for final display
415    glGenFramebuffersEXT(1, &_finalFbo);
416
417    glGenTextures(1, &_finalColorTex);
418    glBindTexture(GL_TEXTURE_2D, _finalColorTex);
419
420    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
421    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
422    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
423
424#if defined(HAVE_FLOAT_TEXTURES) && defined(USE_HALF_FLOAT)
425    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, winWidth, winHeight, 0,
426                 GL_RGB, GL_INT, NULL);
427#elif defined(HAVE_FLOAT_TEXTURES)
428    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, winWidth, winHeight, 0,
429                 GL_RGB, GL_INT, NULL);
430#else
431    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, winWidth, winHeight, 0,
432                 GL_RGB, GL_INT, NULL);
433#endif
434
435    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _finalFbo);
436    glGenRenderbuffersEXT(1, &_finalDepthRb);
437    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
438    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24,
439                             winWidth, winHeight);
440    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
441                              GL_TEXTURE_2D, _finalColorTex, 0);
442    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
443                                 GL_RENDERBUFFER_EXT, _finalDepthRb);
444
445    GLenum status;
446    if (!CheckFBO(&status)) {
447        PrintFBOStatus(status, "finalFbo");
448        return false;
449    }
450
451    TRACE("change camera");
452    //change the camera setting
453    cam->setScreenSize(0, 0, winWidth, winHeight);
454    planeRenderer->setScreenSize(winWidth, winHeight);
455
456    TRACE("Leave (%d, %d)", w, h);
457    return true;
458}
459
460static
461void cgErrorCallback(void)
462{
463    if (!Shader::printErrorInfo()) {
464        TRACE("Cg error, exiting...");
465        exit(1);
466    }
467}
468
469bool NanoVis::init(const char* path)
470{
471    // print OpenGL driver information
472    TRACE("-----------------------------------------------------------");
473    TRACE("OpenGL version: %s", glGetString(GL_VERSION));
474    TRACE("OpenGL vendor: %s", glGetString(GL_VENDOR));
475    TRACE("OpenGL renderer: %s", glGetString(GL_RENDERER));
476    TRACE("-----------------------------------------------------------");
477
478    if (path == NULL) {
479        ERROR("No path defined for shaders or resources");
480        return false;
481    }
482    GLenum err = glewInit();
483    if (GLEW_OK != err) {
484        ERROR("Can't init GLEW: %s", glewGetErrorString(err));
485        return false;
486    }
487    TRACE("Using GLEW %s", glewGetString(GLEW_VERSION));
488
489    // OpenGL 2.1 includes VBOs, PBOs, MRT, NPOT textures, point parameters, point sprites,
490    // GLSL 1.2, and occlusion queries.
491    if (!GLEW_VERSION_2_1) {
492        ERROR("OpenGL version 2.1 or greater is required");
493        return false;
494    }
495
496    // NVIDIA driver may report OpenGL 2.1, but not support PBOs in
497    // indirect GLX contexts
498    if (!GLEW_ARB_pixel_buffer_object) {
499        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).");
500        return false;
501    }
502
503    // Additional extensions not in 2.1 core
504
505    // Framebuffer objects were promoted in 3.0
506    if (!GLEW_EXT_framebuffer_object) {
507        ERROR("EXT_framebuffer_oject extension is required");
508        return false;
509    }
510    // Rectangle textures were promoted in 3.1
511    // FIXME: can use NPOT in place of rectangle textures
512    if (!GLEW_ARB_texture_rectangle) {
513        ERROR("ARB_texture_rectangle extension is required");
514        return false;
515    }
516#ifdef HAVE_FLOAT_TEXTURES
517    // Float color buffers and textures were promoted in 3.0
518    if (!GLEW_ARB_texture_float ||
519        !GLEW_ARB_color_buffer_float) {
520        ERROR("ARB_texture_float and ARB_color_buffer_float extensions are required");
521        return false;
522    }
523#endif
524    // FIXME: should use ARB programs or (preferably) a GLSL profile for portability
525    if (!GLEW_NV_vertex_program3 ||
526        !GLEW_NV_fragment_program2) {
527        ERROR("NV_vertex_program3 and NV_fragment_program2 extensions are required");
528        return false;
529    }
530
531    if (!FilePath::getInstance()->setPath(path)) {
532        ERROR("can't set file path to %s", path);
533        return false;
534    }
535
536    ImageLoaderFactory::getInstance()->addLoaderImpl("bmp", new BMPImageLoaderImpl());
537
538    Shader::initCg();
539    Shader::setErrorCallback(cgErrorCallback);
540
541    fonts = new Fonts();
542    fonts->addFont("verdana", "verdana.fnt");
543    fonts->setFont("verdana");
544
545    velocityArrowsSlice = new VelocityArrowsSlice;
546    licRenderer = new LIC(NMESH, NPIX, NPIX, _licAxis, _licSlice);
547
548    grid = new Grid();
549    grid->setFont(fonts);
550    return true;
551}
552
553bool
554NanoVis::initGL()
555{
556    TRACE("in initGL");
557    //buffer to store data read from the screen
558    if (screenBuffer) {
559        delete[] screenBuffer;
560        screenBuffer = NULL;
561    }
562    screenBuffer = new unsigned char[3*winWidth*winHeight];
563    assert(screenBuffer != NULL);
564
565    //create the camera with default setting
566    cam = new Camera(0, 0, winWidth, winHeight,
567                     def_eye_x, def_eye_y, def_eye_z);
568
569    glEnable(GL_TEXTURE_2D);
570    glShadeModel(GL_FLAT);
571    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
572    glClearColor(0, 0, 0, 1);
573    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
574
575    //initialize lighting
576    GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
577    GLfloat mat_shininess[] = {30.0};
578    GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
579    GLfloat green_light[] = {0.1, 0.5, 0.1, 1.0};
580
581    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
582    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
583    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
584    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
585    glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light);
586    glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
587
588    //frame buffer object for offscreen rendering
589    if (!initOffscreenBuffer()) {
590        return false;
591    }
592
593    volRenderer = new VolumeRenderer();
594
595    renderContext = new RenderContext();
596
597    planeRenderer = new PlaneRenderer(winWidth, winHeight);
598
599    orientationIndicator = new OrientationIndicator();
600
601    //assert(glGetError()==0);
602
603    TRACE("leaving initGL");
604    return true;
605}
606
607void NanoVis::update()
608{
609    VolumeInterpolator *volInterp = volRenderer->getVolumeInterpolator();
610    if (volInterp->isStarted()) {
611        struct timeval clock;
612        gettimeofday(&clock, NULL);
613        double elapsed_time;
614
615        elapsed_time = clock.tv_sec + clock.tv_usec/1000000.0 -
616            volInterp->getStartTime();
617
618        TRACE("%lf %lf", elapsed_time,
619              volInterp->getInterval());
620        float fraction;
621        float f;
622
623        f = fmod((float) elapsed_time, (float)volInterp->getInterval());
624        if (f == 0.0) {
625            fraction = 0.0f;
626        } else {
627            fraction = f / volInterp->getInterval();
628        }
629        TRACE("fraction : %f", fraction);
630        volInterp->update(fraction);
631    }
632}
633
634void
635NanoVis::setVolumeRanges()
636{
637    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
638
639    TRACE("Enter");
640    xMin = yMin = zMin = wMin = DBL_MAX;
641    xMax = yMax = zMax = wMax = -DBL_MAX;
642    VolumeHashmap::iterator itr;
643    for (itr = volumeTable.begin();
644         itr != volumeTable.end(); ++itr) {
645        Volume *volume = itr->second;
646        if (xMin > volume->xAxis.min()) {
647            xMin = volume->xAxis.min();
648        }
649        if (xMax < volume->xAxis.max()) {
650            xMax = volume->xAxis.max();
651        }
652        if (yMin > volume->yAxis.min()) {
653            yMin = volume->yAxis.min();
654        }
655        if (yMax < volume->yAxis.max()) {
656            yMax = volume->yAxis.max();
657        }
658        if (zMin > volume->zAxis.min()) {
659            zMin = volume->zAxis.min();
660        }
661        if (zMax < volume->zAxis.max()) {
662            zMax = volume->zAxis.max();
663        }
664        if (wMin > volume->wAxis.min()) {
665            wMin = volume->wAxis.min();
666        }
667        if (wMax < volume->wAxis.max()) {
668            wMax = volume->wAxis.max();
669        }
670    }
671    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
672        grid->xAxis.setScale(xMin, xMax);
673    }
674    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
675        grid->yAxis.setScale(yMin, yMax);
676    }
677    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
678        grid->zAxis.setScale(zMin, zMax);
679    }
680    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
681        Volume::valueMin = wMin;
682        Volume::valueMax = wMax;
683    }
684    Volume::updatePending = false;
685    TRACE("Leave");
686}
687
688void
689NanoVis::setHeightmapRanges()
690{
691    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
692
693    TRACE("Enter");
694    xMin = yMin = zMin = wMin = DBL_MAX;
695    xMax = yMax = zMax = wMax = -DBL_MAX;
696    HeightMapHashmap::iterator itr;
697    for (itr = heightMapTable.begin();
698         itr != heightMapTable.end(); ++itr) {
699        HeightMap *heightMap = itr->second;
700        if (xMin > heightMap->xAxis.min()) {
701            xMin = heightMap->xAxis.min();
702        }
703        if (xMax < heightMap->xAxis.max()) {
704            xMax = heightMap->xAxis.max();
705        }
706        if (yMin > heightMap->yAxis.min()) {
707            yMin = heightMap->yAxis.min();
708        }
709        if (yMax < heightMap->yAxis.max()) {
710            yMax = heightMap->yAxis.max();
711        }
712        if (zMin > heightMap->zAxis.min()) {
713            zMin = heightMap->zAxis.min();
714        }
715        if (zMax < heightMap->zAxis.max()) {
716            zMax = heightMap->zAxis.max();
717        }
718        if (wMin > heightMap->wAxis.min()) {
719            wMin = heightMap->wAxis.min();
720        }
721        if (wMax < heightMap->wAxis.max()) {
722            wMax = heightMap->wAxis.max();
723        }
724    }
725    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
726        grid->xAxis.setScale(xMin, xMax);
727    }
728    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
729        grid->yAxis.setScale(yMin, yMax);
730    }
731    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
732        grid->zAxis.setScale(zMin, zMax);
733    }
734    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
735        HeightMap::valueMin = grid->yAxis.min();
736        HeightMap::valueMax = grid->yAxis.max();
737    }
738    for (HeightMapHashmap::iterator itr = heightMapTable.begin();
739         itr != heightMapTable.end(); ++itr) {
740        itr->second->mapToGrid(grid);
741    }
742    HeightMap::updatePending = false;
743    TRACE("Leave");
744}
745
746void
747NanoVis::collectBounds(bool onlyVisible)
748{
749    if (flags & MAP_FLOWS) {
750        mapFlows();
751        grid->xAxis.setScale(xMin, xMax);
752        grid->yAxis.setScale(yMin, yMax);
753        grid->zAxis.setScale(zMin, zMax);
754    }
755
756    sceneMin.set(FLT_MAX, FLT_MAX, FLT_MAX);
757    sceneMax.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
758
759    for (VolumeHashmap::iterator itr = volumeTable.begin();
760         itr != volumeTable.end(); ++itr) {
761        Volume *volume = itr->second;
762
763        if (onlyVisible && !volume->visible())
764            continue;
765
766        Vector3f bmin, bmax;
767        volume->getWorldSpaceBounds(bmin, bmax);
768        if (bmin.x > bmax.x)
769            continue;
770
771        if (sceneMin.x > bmin.x) {
772            sceneMin.x = bmin.x;
773        }
774        if (sceneMax.x < bmax.x) {
775            sceneMax.x = bmax.x;
776        }
777        if (sceneMin.y > bmin.y) {
778            sceneMin.y = bmin.y;
779        }
780        if (sceneMax.y < bmax.y) {
781            sceneMax.y = bmax.y;
782        }
783        if (sceneMin.z > bmin.z) {
784            sceneMin.z = bmin.z;
785        }
786        if (sceneMax.z < bmax.z) {
787            sceneMax.z = bmax.z;
788        }
789    }
790
791    for (HeightMapHashmap::iterator itr = heightMapTable.begin();
792         itr != heightMapTable.end(); ++itr) {
793        HeightMap *heightMap = itr->second;
794
795        if (onlyVisible && !heightMap->isVisible())
796            continue;
797
798        Vector3f bmin, bmax;
799        heightMap->getWorldSpaceBounds(bmin, bmax);
800        if (bmin.x > bmax.x)
801            continue;
802
803        if (sceneMin.x > bmin.x) {
804            sceneMin.x = bmin.x;
805        }
806        if (sceneMax.x < bmax.x) {
807            sceneMax.x = bmax.x;
808        }
809        if (sceneMin.y > bmin.y) {
810            sceneMin.y = bmin.y;
811        }
812        if (sceneMax.y < bmax.y) {
813            sceneMax.y = bmax.y;
814        }
815        if (sceneMin.z > bmin.z) {
816            sceneMin.z = bmin.z;
817        }
818        if (sceneMax.z < bmax.z) {
819            sceneMax.z = bmax.z;
820        }
821    }
822
823    Vector3f flowMin, flowMax;
824    getFlowBounds(flowMin, flowMax, onlyVisible);
825    if (flowMin.x < flowMax.x) {
826        if (sceneMin.x > flowMin.x) {
827            sceneMin.x = flowMin.x;
828        }
829        if (sceneMax.x < flowMax.x) {
830            sceneMax.x = flowMax.x;
831        }
832        if (sceneMin.y > flowMin.y) {
833            sceneMin.y = flowMin.y;
834        }
835        if (sceneMax.y < flowMax.y) {
836            sceneMax.y = flowMax.y;
837        }
838        if (sceneMin.z > flowMin.z) {
839            sceneMin.z = flowMin.z;
840        }
841        if (sceneMax.z < flowMax.z) {
842            sceneMax.z = flowMax.z;
843        }
844    }
845
846    // TODO: Get Grid bounds
847
848    if (sceneMin.x > sceneMax.x) {
849        sceneMin.set(-0.5, -0.5, -0.5);
850        sceneMax.set( 0.5,  0.5,  0.5);
851    }
852
853    TRACE("Scene bounds: (%g,%g,%g) - (%g,%g,%g)",
854          sceneMin.x, sceneMin.y, sceneMin.z,
855          sceneMax.x, sceneMax.y, sceneMax.z);
856}
857
858void
859NanoVis::setBgColor(float color[3])
860{
861    TRACE("Setting bgcolor to %g %g %g", color[0], color[1], color[2]);
862    glClearColor(color[0], color[1], color[2], 1);
863}
864
865void
866NanoVis::removeVolume(Volume *volume)
867{
868    VolumeHashmap::iterator itr = volumeTable.find(volume->name());
869    if (itr != volumeTable.end()) {
870        volumeTable.erase(itr);
871    }
872    delete volume;
873}
874
875Flow *
876NanoVis::getFlow(const char *name)
877{
878    FlowHashmap::iterator itr = flowTable.find(name);
879    if (itr == flowTable.end()) {
880        TRACE("Can't find flow '%s'", name);
881        return NULL;
882    }
883    return itr->second;
884}
885
886Flow *
887NanoVis::createFlow(Tcl_Interp *interp, const char *name)
888{
889    FlowHashmap::iterator itr = flowTable.find(name);
890    if (itr != flowTable.end()) {
891        ERROR("Flow '%s' already exists", name);
892        return NULL;
893    }
894    Flow *flow = new Flow(interp, name);
895    flowTable[name] = flow;
896    return flow;
897}
898
899/**
900 * \brief Delete flow object and hash table entry
901 *
902 * This is called by the flow command instance delete callback
903 */
904void
905NanoVis::deleteFlow(const char *name)
906{
907    FlowHashmap::iterator itr = flowTable.find(name);
908    if (itr != flowTable.end()) {
909        delete itr->second;
910        flowTable.erase(itr);
911    }
912}
913
914/**
915 * \brief Delete all flow object commands
916 *
917 * This will also delete the flow objects and hash table entries
918 */
919void
920NanoVis::deleteFlows(Tcl_Interp *interp)
921{
922    FlowHashmap::iterator itr;
923    for (itr = flowTable.begin();
924         itr != flowTable.end(); ++itr) {
925        Tcl_DeleteCommandFromToken(interp, itr->second->getCommandToken());
926    }
927    flowTable.clear();
928}
929
930bool
931NanoVis::mapFlows()
932{
933    TRACE("Enter");
934
935    flags &= ~MAP_FLOWS;
936
937    /*
938     * Step 1. Get the overall min and max magnitudes of all the
939     *         flow vectors.
940     */
941    magMin = DBL_MAX, magMax = -DBL_MAX;
942
943    for (FlowHashmap::iterator itr = flowTable.begin();
944         itr != flowTable.end(); ++itr) {
945        Flow *flow = itr->second;
946        double min, max;
947        if (!flow->isDataLoaded()) {
948            continue;
949        }
950        Rappture::Unirect3d *data = flow->data();
951        min = data->magMin();
952        max = data->magMax();
953        if (min < magMin) {
954            magMin = min;
955        }
956        if (max > magMax) {
957            magMax = max;
958        }
959        if (data->xMin() < xMin) {
960            xMin = data->xMin();
961        }
962        if (data->yMin() < yMin) {
963            yMin = data->yMin();
964        }
965        if (data->zMin() < zMin) {
966            zMin = data->zMin();
967        }
968        if (data->xMax() > xMax) {
969            xMax = data->xMax();
970        }
971        if (data->yMax() > yMax) {
972            yMax = data->yMax();
973        }
974        if (data->zMax() > zMax) {
975            zMax = data->zMax();
976        }
977    }
978
979    TRACE("magMin=%g magMax=%g", NanoVis::magMin, NanoVis::magMax);
980
981    /*
982     * Step 2. Generate the vector field from each data set.
983     */
984    for (FlowHashmap::iterator itr = flowTable.begin();
985         itr != flowTable.end(); ++itr) {
986        Flow *flow = itr->second;
987        if (!flow->isDataLoaded()) {
988            continue; // Flow exists, but no data has been loaded yet.
989        }
990        if (flow->visible()) {
991            flow->initializeParticles();
992        }
993        if (!flow->scaleVectorField()) {
994            return false;
995        }
996        // FIXME: This doesn't work when there is more than one flow.
997        licRenderer->setOffset(flow->getRelativePosition());
998        velocityArrowsSlice->slicePos(flow->getRelativePosition());
999    }
1000    advectFlows();
1001    return true;
1002}
1003
1004void
1005NanoVis::getFlowBounds(Vector3f& min,
1006                       Vector3f& max,
1007                       bool onlyVisible)
1008{
1009    TRACE("Enter");
1010
1011    min.set(FLT_MAX, FLT_MAX, FLT_MAX);
1012    max.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
1013
1014    for (FlowHashmap::iterator itr = flowTable.begin();
1015         itr != flowTable.end(); ++itr) {
1016        itr->second->getBounds(min, max, onlyVisible);
1017    }
1018}
1019
1020void
1021NanoVis::renderFlows()
1022{
1023    for (FlowHashmap::iterator itr = flowTable.begin();
1024         itr != flowTable.end(); ++itr) {
1025        Flow *flow = itr->second;
1026        if (flow->isDataLoaded() && flow->visible()) {
1027            flow->render();
1028        }
1029    }
1030    flags &= ~REDRAW_PENDING;
1031}
1032
1033void
1034NanoVis::resetFlows()
1035{
1036    if (licRenderer->active()) {
1037        NanoVis::licRenderer->reset();
1038    }
1039    for (FlowHashmap::iterator itr = flowTable.begin();
1040         itr != flowTable.end(); ++itr) {
1041        Flow *flow = itr->second;
1042        if (flow->isDataLoaded() && flow->visible()) {
1043            flow->resetParticles();
1044        }
1045    }
1046}   
1047
1048void
1049NanoVis::advectFlows()
1050{
1051    for (FlowHashmap::iterator itr = flowTable.begin();
1052         itr != flowTable.end(); ++itr) {
1053        Flow *flow = itr->second;
1054        if (flow->isDataLoaded() && flow->visible()) {
1055            flow->advect();
1056        }
1057    }
1058}
1059
1060void
1061NanoVis::render()
1062{
1063    TRACE("Enter");
1064
1065    if (flags & MAP_FLOWS) {
1066#ifdef notdef
1067        xMin = yMin = zMin = wMin = FLT_MAX, magMin = DBL_MAX;
1068        xMax = yMax = zMax = wMax = -FLT_MAX, magMax = -DBL_MAX;
1069#endif
1070        mapFlows();
1071        grid->xAxis.setScale(xMin, xMax);
1072        grid->yAxis.setScale(yMin, yMax);
1073        grid->zAxis.setScale(zMin, zMax);
1074    }
1075    //assert(glGetError()==0);
1076    if (HeightMap::updatePending) {
1077        setHeightmapRanges();
1078    }
1079    if (Volume::updatePending) {
1080        setVolumeRanges();
1081    }
1082
1083    //start final rendering
1084
1085    // Need to reset fbo since it may have been changed to default (0)
1086    bindOffscreenBuffer();
1087
1088    //clear screen
1089    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1090
1091    glEnable(GL_DEPTH_TEST);
1092    glEnable(GL_COLOR_MATERIAL);
1093
1094    //camera setting activated
1095    cam->initialize();
1096
1097    //set up the orientation of items in the scene.
1098    glPushMatrix();
1099
1100    switch (updir) {
1101    case X_POS:
1102        glRotatef(90, 0, 0, 1);
1103        glRotatef(90, 1, 0, 0);
1104        break;
1105    case Y_POS:
1106        // this is the default
1107        break;
1108    case Z_POS:
1109        glRotatef(-90, 1, 0, 0);
1110        glRotatef(-90, 0, 0, 1);
1111        break;
1112    case X_NEG:
1113        glRotatef(-90, 0, 0, 1);
1114        break;
1115    case Y_NEG:
1116        glRotatef(180, 0, 0, 1);
1117        glRotatef(-90, 0, 1, 0);
1118        break;
1119    case Z_NEG:
1120        glRotatef(90, 1, 0, 0);
1121        break;
1122    }
1123
1124    //now render things in the scene
1125
1126    orientationIndicator->render();
1127    grid->render();
1128    if ((licRenderer != NULL) && (licRenderer->active())) {
1129        licRenderer->render();
1130    }
1131    if ((velocityArrowsSlice != NULL) && (velocityArrowsSlice->enabled())) {
1132        velocityArrowsSlice->render();
1133    }
1134    renderFlows();
1135    volRenderer->renderAll();
1136
1137    HeightMapHashmap::iterator itr;
1138    for (itr = heightMapTable.begin();
1139         itr != heightMapTable.end(); ++itr) {
1140        HeightMap *heightMap = itr->second;
1141        if (heightMap->isVisible()) {
1142            heightMap->render(renderContext);
1143        }
1144    }
1145    glPopMatrix();
1146
1147    CHECK_FRAMEBUFFER_STATUS();
1148    TRACE("Leave");
1149}
Note: See TracBrowser for help on using the repository browser.