source: nanovis/tags/1.2.0/nanovis.cpp

Last change on this file was 4937, checked in by ldelgass, 9 years ago

merge threading

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