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

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

minor change to sync with nanovis trunk

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