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

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

remove unused var

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