source: nanovis/branches/1.1/VelocityArrowsSlice.cpp @ 4889

Last change on this file since 4889 was 4889, checked in by ldelgass, 5 years ago

Merge r3611:3618 from trunk

  • Property svn:eol-style set to native
File size: 18.4 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2004-2013  HUBzero Foundation, LLC
4 *
5 */
6#include "nvconf.h"
7
8#include <math.h>
9
10#include <GL/glew.h>
11#include <GL/gl.h>
12
13#include <vrmath/Vector3f.h>
14#include <util/FilePath.h>
15#include <Image.h>
16#include <ImageLoaderFactory.h>
17#include <ImageLoader.h>
18
19#include "nanovis.h"
20#include "VelocityArrowsSlice.h"
21#include "Shader.h"
22#include "Camera.h"
23
24using namespace nv;
25using namespace nv::util;
26using namespace vrmath;
27
28static inline float deg2rad(float deg)
29{
30    return ((deg * M_PI) / 180.);
31}
32
33static inline float rad2deg(float rad)
34{
35    return ((rad * 180.) / M_PI);
36}
37
38VelocityArrowsSlice::VelocityArrowsSlice() :
39    _vectorFieldGraphicsID(0),
40    _vfXscale(0),
41    _vfYscale(0),
42    _vfZscale(0),
43    _slicePos(0.5f),
44    _axis(2),
45    _fbo(0),
46    _tex(0),
47    _maxPointSize(1.0f),
48    _renderTargetWidth(128),
49    _renderTargetHeight(128),
50    _velocities(NULL),
51    _projectionVector(1, 1, 0),
52    _tickCountForMinSizeAxis(10),
53    _tickCountX(0),
54    _tickCountY(0),
55    _tickCountZ(0),
56    _pointCount(0),
57    _maxVelocityScale(1, 1, 1),
58    _arrowColor(1, 1, 0),
59    _enabled(false),
60    _dirty(true),
61    _vertexBufferGraphicsID(0),
62    _arrowsTex(NULL),
63    _renderMode(LINES)
64{
65    axis(2);
66
67    _queryVelocityFP.loadFragmentProgram("queryvelocity.cg", "main");
68
69    _particleShader.loadVertexProgram("velocityslicevp.cg", "vpmain");
70    _particleShader.loadFragmentProgram("velocityslicefp.cg", "fpmain");
71
72    createRenderTarget();
73
74    std::string path = FilePath::getInstance()->getPath("arrows.bmp");
75    if (!path.empty()) {
76        ImageLoader *loader = ImageLoaderFactory::getInstance()->createLoader("bmp");
77        if (loader != NULL) {
78            Image *image = loader->load(path.c_str(), Image::IMG_RGBA);
79            if (image != NULL) {
80                unsigned char *bytes = (unsigned char *)image->getImageBuffer();
81                if (bytes != NULL) {
82                    _arrowsTex = new Texture2D(image->getWidth(), image->getHeight(),
83                                               GL_UNSIGNED_BYTE, GL_LINEAR, 4, NULL);
84                    _arrowsTex->setWrapS(GL_MIRRORED_REPEAT);
85                    _arrowsTex->setWrapT(GL_MIRRORED_REPEAT);
86                    _arrowsTex->initialize(image->getImageBuffer());
87                }
88                delete image;
89            } else {
90                ERROR("Failed to load arrows image");
91            }
92            delete loader;
93        } else {
94            ERROR("Couldn't find loader for arrows image");
95        }
96    } else {
97        ERROR("Couldn't find arrows image");
98    }
99
100    GLfloat minMax[2];
101    glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, minMax);
102    TRACE("Aliased point size range: %g %g", minMax[0], minMax[1]);
103    _maxPointSize = minMax[1];
104    glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, minMax);
105    TRACE("Smooth point size range: %g %g", minMax[0], minMax[1]);
106    _maxPointSize = minMax[1] > _maxPointSize ? minMax[1] : _maxPointSize;
107    TRACE("Max point size: %g", _maxPointSize);
108
109    TRACE("Leaving VelocityArrowsSlice constructor");
110}
111
112VelocityArrowsSlice::~VelocityArrowsSlice()
113{
114    if (_tex != 0) {
115        glDeleteTextures(1, &_tex);
116    }
117    if (_fbo != 0) {
118        glDeleteFramebuffersEXT(1, &_fbo);
119    }
120    if (_arrowsTex != NULL) {
121        delete _arrowsTex;
122    }
123    if (_vertexBufferGraphicsID != 0) {
124        glDeleteBuffers(1, &_vertexBufferGraphicsID);
125    }
126    if (_velocities != NULL) {
127        delete [] _velocities;
128    }
129}
130
131void VelocityArrowsSlice::createRenderTarget()
132{
133    if (_velocities != NULL) {
134        delete [] _velocities;
135    }
136    _velocities = new Vector3f[_renderTargetWidth * _renderTargetHeight];
137
138    if (_vertexBufferGraphicsID != 0) {
139        glDeleteBuffers(1, &_vertexBufferGraphicsID);
140    }
141
142    glGenBuffers(1, &_vertexBufferGraphicsID);
143    glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
144    glBufferDataARB(GL_ARRAY_BUFFER_ARB, _renderTargetWidth * _renderTargetHeight * 3 * sizeof(float), 
145                    0, GL_DYNAMIC_DRAW_ARB);
146    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
147
148    if (_tex != 0) {
149        glDeleteTextures(1, &_tex);
150    }
151    if (_fbo != 0) {
152        glDeleteFramebuffersEXT(1, &_fbo);
153    }
154
155    glGenFramebuffersEXT(1, &_fbo);
156    glGenTextures(1, &_tex);
157    int fboOrig;
158    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
159    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
160
161    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _tex);
162    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
163    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
164    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
165    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
166
167    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, 
168                 _renderTargetWidth, _renderTargetHeight, 0,
169                 GL_RGBA, GL_FLOAT, NULL);
170
171    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
172                              GL_TEXTURE_RECTANGLE_ARB, _tex, 0);
173
174    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
175}
176
177void VelocityArrowsSlice::axis(int axis)
178{
179    _axis = axis;
180    switch (_axis) {
181    case 0:
182        _projectionVector.x = 0;
183        _projectionVector.y = 1;
184        _projectionVector.z = 1;
185        break;
186    case 1 :
187        _projectionVector.x = 1;
188        _projectionVector.y = 0;
189        _projectionVector.z = 1;
190        break;
191    case 2:
192        _projectionVector.x = 1;
193        _projectionVector.y = 1;
194        _projectionVector.z = 0;
195        break;
196    }
197    _dirty = true;
198}
199
200void VelocityArrowsSlice::queryVelocity()
201{
202    if (!_enabled) return;
203
204    glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
205    int fboOrig;
206    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
207
208    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
209
210    _queryVelocityFP.bind();
211    _queryVelocityFP.setFPTextureParameter("vfield", _vectorFieldGraphicsID);
212
213    glDisable(GL_DEPTH_TEST);
214    glViewport(0, 0, _renderTargetWidth, _renderTargetHeight);
215    glMatrixMode(GL_PROJECTION);
216    glPushMatrix();
217    glLoadIdentity();
218    glOrtho(0, _renderTargetWidth, 0, _renderTargetHeight, -10.0f, 10.0f);
219    glMatrixMode(GL_MODELVIEW);
220    glPushMatrix();
221    glLoadIdentity();
222
223    glBegin(GL_QUADS);
224    switch (_axis) {
225    case 0:
226        glTexCoord3f(_slicePos, 0, 0); glVertex2i(0,                  0);
227        glTexCoord3f(_slicePos, 1, 0); glVertex2i(_renderTargetWidth, 0);
228        glTexCoord3f(_slicePos, 1, 1); glVertex2i(_renderTargetWidth, _renderTargetHeight);
229        glTexCoord3f(_slicePos, 0, 1); glVertex2i(0,                  _renderTargetHeight);
230        break;
231    case 1:
232        glTexCoord3f(0, _slicePos, 0); glVertex2i(0,                  0);
233        glTexCoord3f(1, _slicePos, 0); glVertex2i(_renderTargetWidth, 0);
234        glTexCoord3f(1, _slicePos, 1); glVertex2i(_renderTargetWidth, _renderTargetHeight);
235        glTexCoord3f(0, _slicePos, 1); glVertex2i(0,                  _renderTargetHeight);
236        break;
237    case 2:
238    default:
239        glTexCoord3f(0, 0, _slicePos); glVertex2i(0,                  0);
240        glTexCoord3f(1, 0, _slicePos); glVertex2i(_renderTargetWidth, 0);
241        glTexCoord3f(1, 1, _slicePos); glVertex2i(_renderTargetWidth, _renderTargetHeight);
242        glTexCoord3f(0, 1, _slicePos); glVertex2i(0,                  _renderTargetHeight);
243        break;
244    }
245    glEnd();
246
247    _queryVelocityFP.disableFPTextureParameter("vfield");
248    _queryVelocityFP.unbind();
249
250    glReadPixels(0, 0, _renderTargetWidth, _renderTargetHeight, GL_RGB, GL_FLOAT, _velocities);
251
252    glMatrixMode(GL_PROJECTION);
253    glPopMatrix();
254    glMatrixMode(GL_MODELVIEW);
255    glPopMatrix();
256
257    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
258
259    glPopAttrib();
260}
261
262static void drawLineArrow(int axis)
263{
264    glBegin(GL_LINES);
265    switch (axis) {
266    case 0: // ZY plane
267        glVertex3f(0.0, 0.0, 0.0);
268        glVertex3f(0.0, 0.0, 1.0);
269
270        glVertex3f(0.0, 0.0, 1.0);
271        glVertex3f(0.0, 0.25, 0.75);
272
273        glVertex3f(0.0, 0.0, 1.0);
274        glVertex3f(0.0, -0.25, 0.75);
275        break;
276    case 1: // XZ plane
277        glVertex3f(0.0, 0.0, 0.0);
278        glVertex3f(1.0, 0.0, 0.0);
279
280        glVertex3f(1.0, 0.0, 0.0);
281        glVertex3f(0.75, 0.0, 0.25);
282
283        glVertex3f(1.0, 0.0, 0.0);
284        glVertex3f(0.75, 0.0, -0.25);
285        break;
286    case 2: // XY plane
287    default:
288        glVertex3f(0.0, 0.0, 0.0);
289        glVertex3f(1.0, 0.0, 0.0);
290
291        glVertex3f(1.0, 0.0, 0.0);
292        glVertex3f(0.75, 0.25, 0.0);
293
294        glVertex3f(1.0, 0.0, 0.0);
295        glVertex3f(0.75, -0.25, 0.0);
296        break;
297    }
298    glEnd();
299}
300
301void VelocityArrowsSlice::render()
302{
303    if (!_enabled)
304        return;
305
306    if (_dirty) {
307        computeSamplingTicks();
308        queryVelocity();
309        _dirty = false;
310    }
311
312    TRACE("_vf: %g %g %g", _vfXscale,_vfYscale, _vfZscale);
313    TRACE("_maxVelocityScale: %g %g %g",
314          _maxVelocityScale.x, _maxVelocityScale.y, _maxVelocityScale.z);
315
316    glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
317
318    glMatrixMode(GL_MODELVIEW);
319    glPushMatrix();
320
321    glScalef(_vfXscale,_vfYscale, _vfZscale);
322    glTranslatef(-0.5f, -0.5f, -0.5f);
323
324    if (_renderMode == LINES) {
325        glDisable(GL_TEXTURE_2D);
326        glDisable(GL_LIGHTING);
327        glLineWidth(2.0);
328        glColor3f(_arrowColor.x, _arrowColor.y, _arrowColor.z);
329 
330        Vector3f pos;
331        Vector3f vel;
332        Vector3f refVec;
333        Vector3f blue(0, 0, 1);
334        Vector3f red(1, 0, 0);
335
336        int index = 0, icount, jcount;
337        switch (_axis) {
338        case 0:
339            icount = _tickCountZ;
340            jcount = _tickCountY;
341            refVec.set(0, 0, 1);
342            break;
343        case 1:
344            icount = _tickCountZ;
345            jcount = _tickCountX;
346            refVec.set(1, 0, 0);
347            break;
348        case 2:
349        default:
350            icount = _tickCountY;
351            jcount = _tickCountX;
352            refVec.set(1, 0, 0);
353            break;
354        }
355
356        for (int i = 0; i < icount; ++i) {
357            for (int j = 0; j < jcount; ++j, ++index) {
358                pos = _samplingPositions[index];
359                // Normalized velocity: [-1,1] components
360                // Project 3D vector onto sample plane
361                vel = _velocities[index].scale(_projectionVector);
362                // Length: [0,1]
363                double length = vel.length();
364                if (length < 0.0 || length > 1.0) {
365                    TRACE("***vec: (%g, %g, %g) length: %g***", vel.x, vel.y, vel.z, length);
366                    continue;
367                }
368                if (length > 1.0e-6) {
369                    Vector3f vnorm = vel.normalize();
370                    Vector3f rotationAxis = refVec.cross(vnorm);
371                    double angle = rad2deg(acos(refVec.dot(vnorm)));
372                    Vector3f color = blue * (1.0 - length) + red * length;
373                    float scale = length;
374                    if (scale < 0.10) scale = 0.10;
375                    glMatrixMode(GL_MODELVIEW);
376                    glPushMatrix();
377                    glColor3f(color.x, color.y, color.z);
378                    glTranslatef(pos.x, pos.y, pos.z);
379                    glScalef(2.0 * _maxVelocityScale.x,
380                             2.0 * _maxVelocityScale.y,
381                             2.0 * _maxVelocityScale.z);
382                    glScalef(scale, scale, scale);
383                    if (angle > 1.0e-6 || angle < -1.0e-6)
384                        glRotated(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
385                    drawLineArrow(_axis);
386                    glPopMatrix();
387                }
388            }
389        }
390
391        glLineWidth(1.0);
392    } else {
393        glColor4f(_arrowColor.x, _arrowColor.y, _arrowColor.z, 1.0f);
394        glEnable(GL_DEPTH_TEST);
395        glDisable(GL_LIGHTING);
396#if 0
397        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
398        glEnable(GL_BLEND);
399        glDepthMask(GL_FALSE);
400#else
401        glDisable(GL_BLEND);
402#endif
403        glAlphaFunc(GL_GREATER, 0.6);
404        glEnable(GL_ALPHA_TEST);
405        glEnable(GL_POINT_SPRITE_ARB);
406        glPointSize(20);
407        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
408
409        _arrowsTex->activate();
410        glEnable(GL_TEXTURE_2D);
411        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
412
413        GLfloat atten[] = {1, 0, 0};
414        glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, atten);
415        glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 0.0f);
416        glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1.0f);
417        glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, _maxPointSize);
418        glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
419
420        _particleShader.bind();
421        _particleShader.setVPTextureParameter("vfield", _vectorFieldGraphicsID);
422        _particleShader.setFPTextureParameter("arrows", _arrowsTex->id());
423        _particleShader.setVPParameter1f("tanHalfFOV",
424                                         tan(NanoVis::getCamera()->fov() * 0.5) * NanoVis::winHeight * 0.5);
425        _particleShader.setGLStateMatrixVPParameter("modelview",
426                                                    Shader::MODELVIEW_MATRIX,
427                                                    Shader::MATRIX_IDENTITY);
428        _particleShader.setGLStateMatrixVPParameter("mvp",
429                                                    Shader::MODELVIEW_PROJECTION_MATRIX,
430                                                    Shader::MATRIX_IDENTITY);
431
432        glEnableClientState(GL_VERTEX_ARRAY);
433        glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
434        glVertexPointer(3, GL_FLOAT, 0, 0);
435        //glEnableClientState(GL_COLOR_ARRAY);
436
437        // TBD..
438        glDrawArrays(GL_POINTS, 0, _pointCount);
439        glPointSize(1);
440
441        glDisableClientState(GL_VERTEX_ARRAY);
442        glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
443        glDisable(GL_POINT_SPRITE_ARB);
444
445        _particleShader.disableVPTextureParameter("vfield");
446        _particleShader.disableFPTextureParameter("arrows");
447        _particleShader.unbind();
448
449        glActiveTexture(GL_TEXTURE0);
450        glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
451        _arrowsTex->deactivate();
452    }
453
454    glPopMatrix();
455    glPopAttrib();
456}
457
458void 
459VelocityArrowsSlice::setVectorField(unsigned int vfGraphicsID, const Vector3f& origin,
460                                    float xScale, float yScale, float zScale, float max)
461{
462    _vectorFieldGraphicsID = vfGraphicsID;
463    _vfXscale = xScale;
464    _vfYscale = yScale;
465    _vfZscale = zScale;
466
467    _dirty = true;
468}
469
470void VelocityArrowsSlice::computeSamplingTicks()
471{
472    if (_vfXscale < _vfYscale) {
473        if (_vfXscale < _vfZscale || _vfZscale == 0.0) {
474            // vfXscale
475            _tickCountX = _tickCountForMinSizeAxis;
476
477            float step = _vfXscale / (_tickCountX + 1);
478
479            _tickCountY = (int)(_vfYscale/step);
480            _tickCountZ = (int)(_vfZscale/step);
481        } else {
482            // vfZscale
483            _tickCountZ = _tickCountForMinSizeAxis;
484
485            float step = _vfZscale / (_tickCountZ + 1);
486            _tickCountX = (int)(_vfXscale/step);
487            _tickCountY = (int)(_vfYscale/step);
488        }
489    } else {
490        if (_vfYscale < _vfZscale || _vfZscale == 0.0) {
491            // _vfYscale
492            _tickCountY = _tickCountForMinSizeAxis;
493
494            float step = _vfYscale / (_tickCountY + 1);
495            _tickCountX = (int)(_vfXscale/step);
496            _tickCountZ = (int)(_vfZscale/step);
497        } else {
498            // vfZscale
499            _tickCountZ = _tickCountForMinSizeAxis;
500
501            float step = _vfZscale / (_tickCountZ + 1);
502            _tickCountX = (int)(_vfXscale/step);
503            _tickCountY = (int)(_vfYscale/step);
504        }
505    }
506
507    switch (_axis) {
508    case 0:
509        _tickCountX = 1;
510        _renderTargetWidth = _tickCountY;
511        _renderTargetHeight = _tickCountZ;
512        break;
513    case 1:
514        _tickCountY = 1;
515        _renderTargetWidth = _tickCountX;
516        _renderTargetHeight = _tickCountZ;
517        break;
518    default:
519    case 2:
520        _tickCountZ = 1;
521        _renderTargetWidth = _tickCountX;
522        _renderTargetHeight = _tickCountY;
523        break;
524    }
525
526    _maxVelocityScale.x = (1.0f / _tickCountX) * 0.8f;
527    _maxVelocityScale.y = (1.0f / _tickCountY) * 0.8f;
528    _maxVelocityScale.z = (1.0f / _tickCountZ) * 0.8f;
529
530    TRACE("Tick counts: %d %d %d", _tickCountX, _tickCountY, _tickCountZ);
531
532    int pointCount = _tickCountX * _tickCountY * _tickCountZ;
533    if (_pointCount != pointCount) {
534        _samplingPositions.clear();
535        _samplingPositions.reserve(pointCount);
536        _pointCount = pointCount;
537    }
538
539    createRenderTarget();
540
541    Vector3f pos;
542    Vector3f *pinfo = NULL;
543    if (_renderMode == GLYPHS) {
544        glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
545        pinfo = (Vector3f *)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
546    }
547
548    if (_axis == 2) {
549        for (int y = 1; y <= _tickCountY; ++y) {
550            for (int x = 1; x <= _tickCountX; ++x) {
551                pos.x = (1.0f / (_tickCountX + 1)) * x;
552                pos.y = (1.0f / (_tickCountY + 1)) * y;
553                pos.z = _slicePos;
554                if (_renderMode == LINES) {
555                    _samplingPositions.push_back(pos);
556                } else {
557                    *pinfo = pos;
558                    ++pinfo;
559                }
560            }
561        }
562    } else if (_axis == 1) {
563        for (int z = 1; z <= _tickCountZ; ++z) {
564            for (int x = 1; x <= _tickCountX; ++x) {
565                pos.x = (1.0f / (_tickCountX + 1)) * x;
566                pos.y = _slicePos;
567                pos.z = (1.0f / (_tickCountZ + 1)) * z;
568                if (_renderMode == LINES) {
569                    _samplingPositions.push_back(pos);
570                } else {
571                    *pinfo = pos;
572                    ++pinfo;
573                }
574            }
575        }
576    } else if (_axis == 0) {
577        for (int z = 1; z <= _tickCountZ; ++z) {
578            for (int y = 1; y <= _tickCountY; ++y) {
579                pos.x = _slicePos;
580                pos.y = (1.0f / (_tickCountY + 1)) * y;
581                pos.z = (1.0f / (_tickCountZ + 1)) * z;
582                if (_renderMode == LINES) {
583                    _samplingPositions.push_back(pos);
584                } else {
585                    *pinfo = pos;
586                    ++pinfo;
587                }
588            }
589        }
590    }
591
592    if (_renderMode == GLYPHS) {
593        glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
594    }
595}
Note: See TracBrowser for help on using the repository browser.