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

Last change on this file since 3611 was 3611, checked in by ldelgass, 12 years ago

Use nv namespace for classes in nanovis rather than prefixing class names with
Nv (still need to convert shader classes).

  • 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 "NvShader.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 (!NvShader::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    NvShader::initCg();
539    NvShader::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.