source: trunk/packages/vizservers/nanovis/VelocityArrowsSlice.cpp @ 3611

Last change on this file since 3611 was 3611, checked in by ldelgass, 12 years ago

Use nv namespace for classes in nanovis rather than prefixing class names with
Nv (still need to convert shader classes).

  • 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 "NvShader.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                                                    NvShader::MODELVIEW_MATRIX,
427                                                    NvShader::MATRIX_IDENTITY);
428        _particleShader.setGLStateMatrixVPParameter("mvp",
429                                                    NvShader::MODELVIEW_PROJECTION_MATRIX,
430                                                    NvShader::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.