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

Last change on this file since 3935 was 3935, checked in by ldelgass, 6 years ago

First pass at loading VTK vector data for flows in nanovis

  • Property svn:eol-style set to native
File size: 25.9 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 GLSL for portability
507#ifdef USE_ARB_PROGRAMS
508    if (!GLEW_ARB_vertex_program ||
509        !GLEW_ARB_fragment_program) {
510        ERROR("ARB_vertex_program and ARB_fragment_program extensions are required");
511        return false;
512    }
513#else
514    if (!GLEW_NV_vertex_program3 ||
515        !GLEW_NV_fragment_program2) {
516        ERROR("NV_vertex_program3 and NV_fragment_program2 extensions are required");
517        return false;
518    }
519#endif
520
521    if (!FilePath::getInstance()->setPath(path)) {
522        ERROR("can't set file path to %s", path);
523        return false;
524    }
525
526    ImageLoaderFactory::getInstance()->addLoaderImpl("bmp", new BMPImageLoaderImpl());
527
528    return true;
529}
530
531bool
532NanoVis::initGL()
533{
534    TRACE("in initGL");
535    //buffer to store data read from the screen
536    if (screenBuffer) {
537        delete[] screenBuffer;
538        screenBuffer = NULL;
539    }
540    screenBuffer = new unsigned char[3*winWidth*winHeight];
541    assert(screenBuffer != NULL);
542
543    //create the camera with default setting
544    _camera = new Camera(0, 0, winWidth, winHeight);
545
546    glEnable(GL_TEXTURE_2D);
547    glShadeModel(GL_FLAT);
548    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
549    glClearColor(0, 0, 0, 1);
550    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
551
552    //initialize lighting
553    GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
554    GLfloat mat_shininess[] = {30.0};
555    GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
556
557    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
558    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
559    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
560    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
561    glLightfv(GL_LIGHT1, GL_DIFFUSE, white_light);
562    glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
563
564    //frame buffer object for offscreen rendering
565    if (!initOffscreenBuffer()) {
566        return false;
567    }
568
569    fonts = new Fonts();
570    fonts->addFont("verdana", "verdana.fnt");
571    fonts->setFont("verdana");
572
573    renderContext = new RenderContext();
574
575    volRenderer = new VolumeRenderer();
576
577    planeRenderer = new PlaneRenderer(winWidth, winHeight);
578
579    velocityArrowsSlice = new VelocityArrowsSlice();
580
581    licRenderer = new LIC();
582
583    orientationIndicator = new OrientationIndicator();
584
585    grid = new Grid();
586    grid->setFont(fonts);
587
588    //assert(glGetError()==0);
589
590    TRACE("leaving initGL");
591    return true;
592}
593
594void NanoVis::update()
595{
596    VolumeInterpolator *volInterp = volRenderer->getVolumeInterpolator();
597    if (volInterp->isStarted()) {
598        struct timeval clock;
599        gettimeofday(&clock, NULL);
600        double elapsed_time;
601
602        elapsed_time = clock.tv_sec + clock.tv_usec/1000000.0 -
603            volInterp->getStartTime();
604
605        TRACE("%lf %lf", elapsed_time, 
606              volInterp->getInterval());
607        float fraction;
608        float f;
609
610        f = fmod((float) elapsed_time, (float)volInterp->getInterval());
611        if (f == 0.0) {
612            fraction = 0.0f;
613        } else {
614            fraction = f / volInterp->getInterval();
615        }
616        TRACE("fraction : %f", fraction);
617        volInterp->update(fraction);
618    }
619}
620
621/**
622 * \brief Called when new volumes are added to update ranges
623 */
624void
625NanoVis::setVolumeRanges()
626{
627    TRACE("Enter");
628
629    double valueMin = DBL_MAX, valueMax = -DBL_MAX;
630    VolumeHashmap::iterator itr;
631    for (itr = volumeTable.begin();
632         itr != volumeTable.end(); ++itr) {
633        Volume *volume = itr->second;
634        if (valueMin > volume->wAxis.min()) {
635            valueMin = volume->wAxis.min();
636        }
637        if (valueMax < volume->wAxis.max()) {
638            valueMax = volume->wAxis.max();
639        }
640    }
641    if ((valueMin < DBL_MAX) && (valueMax > -DBL_MAX)) {
642        Volume::valueMin = valueMin;
643        Volume::valueMax = valueMax;
644    }
645    Volume::updatePending = false;
646    TRACE("Leave");
647}
648
649/**
650 * \brief Called when new heightmaps are added to update ranges
651 */
652void
653NanoVis::setHeightmapRanges()
654{
655    TRACE("Enter");
656
657    double valueMin = DBL_MAX, valueMax = -DBL_MAX;
658    HeightMapHashmap::iterator itr;
659    for (itr = heightMapTable.begin();
660         itr != heightMapTable.end(); ++itr) {
661        HeightMap *heightMap = itr->second;
662        if (valueMin > heightMap->wAxis.min()) {
663            valueMin = heightMap->wAxis.min();
664        }
665        if (valueMax < heightMap->wAxis.max()) {
666            valueMax = heightMap->wAxis.max();
667        }
668    }
669    if ((valueMin < DBL_MAX) && (valueMax > -DBL_MAX)) {
670        HeightMap::valueMin = valueMin;
671        HeightMap::valueMax = valueMax;
672    }
673    for (HeightMapHashmap::iterator itr = heightMapTable.begin();
674         itr != heightMapTable.end(); ++itr) {
675        itr->second->mapToGrid(grid);
676    }
677    HeightMap::updatePending = false;
678    TRACE("Leave");
679}
680
681void
682NanoVis::collectBounds(bool onlyVisible)
683{
684    sceneBounds.makeEmpty();
685
686    for (VolumeHashmap::iterator itr = volumeTable.begin();
687         itr != volumeTable.end(); ++itr) {
688        Volume *volume = itr->second;
689
690        if (onlyVisible && !volume->visible())
691            continue;
692
693        BBox bbox;
694        volume->getBounds(bbox.min, bbox.max);
695        sceneBounds.extend(bbox);
696    }
697
698    for (HeightMapHashmap::iterator itr = heightMapTable.begin();
699         itr != heightMapTable.end(); ++itr) {
700        HeightMap *heightMap = itr->second;
701
702        if (onlyVisible && !heightMap->isVisible())
703            continue;
704
705        BBox bbox;
706        heightMap->getBounds(bbox.min, bbox.max);
707        sceneBounds.extend(bbox);
708    }
709
710    for (FlowHashmap::iterator itr = flowTable.begin();
711         itr != flowTable.end(); ++itr) {
712        Flow *flow = itr->second;
713
714        BBox bbox;
715        flow->getBounds(bbox.min, bbox.max, onlyVisible);
716        sceneBounds.extend(bbox);
717    }
718
719    if (!sceneBounds.isEmptyX()) {
720        grid->xAxis.setScale(sceneBounds.min.x, sceneBounds.max.x);
721    }
722    if (!sceneBounds.isEmptyY()) {
723        grid->yAxis.setScale(sceneBounds.min.y, sceneBounds.max.y);
724    }
725    if (!sceneBounds.isEmptyZ()) {
726        grid->zAxis.setScale(sceneBounds.min.z, sceneBounds.max.z);
727    }
728
729#if 0
730    if (!onlyVisible || grid->isVisible()) {
731        BBox bbox;
732        grid->getBounds(bbox.min, bbox.max);
733        sceneBounds.extend(bbox);
734    }
735#endif
736
737    if (sceneBounds.isEmpty()) {
738        sceneBounds.min.set(-0.5, -0.5, -0.5);
739        sceneBounds.max.set( 0.5,  0.5,  0.5);
740    }
741
742    TRACE("Scene bounds: (%g,%g,%g) - (%g,%g,%g)",
743          sceneBounds.min.x, sceneBounds.min.y, sceneBounds.min.z,
744          sceneBounds.max.x, sceneBounds.max.y, sceneBounds.max.z);
745}
746
747void
748NanoVis::setBgColor(float color[3])
749{
750    TRACE("Setting bgcolor to %g %g %g", color[0], color[1], color[2]);
751    glClearColor(color[0], color[1], color[2], 1);
752}
753
754void 
755NanoVis::removeVolume(Volume *volume)
756{
757    VolumeHashmap::iterator itr = volumeTable.find(volume->name());
758    if (itr != volumeTable.end()) {
759        volumeTable.erase(itr);
760    }
761    delete volume;
762}
763
764Flow *
765NanoVis::getFlow(const char *name)
766{
767    FlowHashmap::iterator itr = flowTable.find(name);
768    if (itr == flowTable.end()) {
769        TRACE("Can't find flow '%s'", name);
770        return NULL;
771    }
772    return itr->second;
773}
774
775Flow *
776NanoVis::createFlow(Tcl_Interp *interp, const char *name)
777{
778    FlowHashmap::iterator itr = flowTable.find(name);
779    if (itr != flowTable.end()) {
780        ERROR("Flow '%s' already exists", name);
781        return NULL;
782    }
783    Flow *flow = new Flow(interp, name);
784    flowTable[name] = flow;
785    return flow;
786}
787
788/**
789 * \brief Delete flow object and hash table entry
790 *
791 * This is called by the flow command instance delete callback
792 */
793void
794NanoVis::deleteFlow(const char *name)
795{
796    FlowHashmap::iterator itr = flowTable.find(name);
797    if (itr != flowTable.end()) {
798        delete itr->second;
799        flowTable.erase(itr);
800    }
801}
802
803/**
804 * \brief Delete all flow object commands
805 *
806 * This will also delete the flow objects and hash table entries
807 */
808void
809NanoVis::deleteFlows(Tcl_Interp *interp)
810{
811    FlowHashmap::iterator itr;
812    for (itr = flowTable.begin();
813         itr != flowTable.end(); ++itr) {
814        Tcl_DeleteCommandFromToken(interp, itr->second->getCommandToken());
815    }
816    flowTable.clear();
817}
818
819/**
820 * \brief Called when new flows are added to update ranges
821 */
822bool
823NanoVis::setFlowRanges()
824{
825    TRACE("Enter");
826
827    /*
828     * Step 1. Get the overall min and max magnitudes of all the
829     *         flow vectors.
830     */
831    Flow::magMin = DBL_MAX;
832    Flow::magMax = -DBL_MAX;
833
834    for (FlowHashmap::iterator itr = flowTable.begin();
835         itr != flowTable.end(); ++itr) {
836        Flow *flow = itr->second;
837        if (!flow->isDataLoaded()) {
838            continue;
839        }
840        double range[2];
841        flow->getVectorRange(range);
842        if (range[0] < Flow::magMin) {
843            Flow::magMin = range[0];
844        } 
845        if (range[1] > Flow::magMax) {
846            Flow::magMax = range[1];
847        }
848    }
849
850    TRACE("magMin=%g magMax=%g", Flow::magMin, Flow::magMax);
851
852    /*
853     * Step 2. Generate the vector field from each data set.
854     */
855    for (FlowHashmap::iterator itr = flowTable.begin();
856         itr != flowTable.end(); ++itr) {
857        Flow *flow = itr->second;
858        if (!flow->isDataLoaded()) {
859            continue; // Flow exists, but no data has been loaded yet.
860        }
861        if (flow->visible()) {
862            flow->initializeParticles();
863        }
864    }
865
866    Flow::updatePending = false;
867    return true;
868}
869
870void
871NanoVis::renderFlows()
872{
873    for (FlowHashmap::iterator itr = flowTable.begin();
874         itr != flowTable.end(); ++itr) {
875        Flow *flow = itr->second;
876        if (flow->isDataLoaded() && flow->visible()) {
877            flow->render();
878        }
879    }
880}
881
882void
883NanoVis::resetFlows()
884{
885    NanoVis::licRenderer->reset();
886    for (FlowHashmap::iterator itr = flowTable.begin();
887         itr != flowTable.end(); ++itr) {
888        Flow *flow = itr->second;
889        if (flow->isDataLoaded()) {
890            flow->resetParticles();
891        }
892    }
893}   
894
895void
896NanoVis::advectFlows()
897{
898    TRACE("Enter");
899    for (FlowHashmap::iterator itr = flowTable.begin();
900         itr != flowTable.end(); ++itr) {
901        Flow *flow = itr->second;
902        if (flow->isDataLoaded()) {
903            flow->advect();
904        }
905    }
906}
907
908void
909NanoVis::render()
910{
911    TRACE("Enter");
912
913    if (Flow::updatePending) {
914        setFlowRanges();
915    }
916    if (HeightMap::updatePending) {
917        setHeightmapRanges();
918    }
919    if (Volume::updatePending) {
920        setVolumeRanges();
921    }
922
923    collectBounds();
924
925    // Start final rendering
926
927    // Need to reset fbo since it may have been changed to default (0)
928    bindOffscreenBuffer();
929
930    //clear screen
931    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
932
933    glEnable(GL_DEPTH_TEST);
934    glEnable(GL_COLOR_MATERIAL);
935
936    // Emit modelview and projection matrices
937    _camera->initialize();
938
939    // Now render things in the scene
940
941    orientationIndicator->setPosition(sceneBounds.getCenter());
942    orientationIndicator->setScale(sceneBounds.getSize());
943    orientationIndicator->render();
944
945    grid->render();
946
947    licRenderer->render();
948
949    velocityArrowsSlice->render();
950
951    renderFlows();
952
953    volRenderer->renderAll();
954
955    for (HeightMapHashmap::iterator itr = heightMapTable.begin();
956         itr != heightMapTable.end(); ++itr) {
957        itr->second->render(renderContext);
958     }
959
960    CHECK_FRAMEBUFFER_STATUS();
961    TRACE("Leave");
962    redrawPending = false;
963}
Note: See TracBrowser for help on using the repository browser.