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

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

fix merge problem from r5489

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