source: nanovis/branches/1.2/nanovis.cpp

Last change on this file was 5723, checked in by ldelgass, 4 years ago

Sync with nanovis trunk: merge r5722 and remove global bounds vars.

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