source: nanovis/tags/1.1.4/VelocityArrowsSlice.cpp @ 5401

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

Merge serveral changes from trunk. Does not include threading, world space
changes, etc.

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