source: nanovis/branches/1.2/nanovis.cpp @ 5497

Last change on this file since 5497 was 5489, checked in by ldelgass, 9 years ago

Move cumulative flow min/max magnitude to Flow.

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