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

Last change on this file since 3630 was 3630, checked in by ldelgass, 8 years ago

Nanovis refactoring to fix problems with scaling and multiple results.
Do rendering in world space to properly place and scale multiple data sets.
Also fix flows to reduce resets of animations. More work toward removing
Cg dependency. Fix panning to convert viewport coords to world coords.

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