source: nanovis/branches/1.2/VelocityArrowsSlice.cpp @ 6632

Last change on this file since 6632 was 5588, checked in by ldelgass, 9 years ago

Merge support for VTK vector fields in nanovis to release branch

  • Property svn:eol-style set to native
File size: 19.0 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 "Volume.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    _slicePos(0.5f),
41    _axis(AXIS_Z),
42    _fbo(0),
43    _tex(0),
44    _maxPointSize(1.0f),
45    _renderTargetWidth(128),
46    _renderTargetHeight(128),
47    _velocities(NULL),
48    _projectionVector(1, 1, 0),
49    _tickCountForMinSizeAxis(10),
50    _tickCountX(0),
51    _tickCountY(0),
52    _tickCountZ(0),
53    _pointCount(0),
54    _maxVelocityScale(1, 1, 1),
55    _arrowColor(1, 1, 0),
56    _visible(false),
57    _dirty(true),
58    _vertexBufferGraphicsID(0),
59    _arrowsTex(NULL),
60    _renderMode(LINES)
61{
62    setSliceAxis(_axis);
63
64    _queryVelocityFP.loadFragmentProgram("queryvelocity.cg");
65
66    // Delay loading of shaders only required for glyph style rendering
67    if (_renderMode == GLYPHS) {
68        _particleShader.loadVertexProgram("velocityslicevp.cg");
69        _particleShader.loadFragmentProgram("velocityslicefp.cg");
70    }
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::setSliceAxis(FlowSliceAxis axis)
178{
179    _axis = axis;
180    switch (_axis) {
181    case AXIS_X:
182        _projectionVector.x = 0;
183        _projectionVector.y = 1;
184        _projectionVector.z = 1;
185        break;
186    case AXIS_Y:
187        _projectionVector.x = 1;
188        _projectionVector.y = 0;
189        _projectionVector.z = 1;
190        break;
191    case AXIS_Z:
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    glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
203    int fboOrig;
204    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fboOrig);
205
206    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
207
208    _queryVelocityFP.bind();
209    _queryVelocityFP.setFPTextureParameter("vfield", _vectorFieldGraphicsID);
210
211    glDisable(GL_DEPTH_TEST);
212    glViewport(0, 0, _renderTargetWidth, _renderTargetHeight);
213    glMatrixMode(GL_PROJECTION);
214    glPushMatrix();
215    glLoadIdentity();
216    glOrtho(0, _renderTargetWidth, 0, _renderTargetHeight, -10.0f, 10.0f);
217    glMatrixMode(GL_MODELVIEW);
218    glPushMatrix();
219    glLoadIdentity();
220
221    glBegin(GL_QUADS);
222    switch (_axis) {
223    case AXIS_X:
224        glTexCoord3f(_slicePos, 0, 0); glVertex2i(0,                  0);
225        glTexCoord3f(_slicePos, 1, 0); glVertex2i(_renderTargetWidth, 0);
226        glTexCoord3f(_slicePos, 1, 1); glVertex2i(_renderTargetWidth, _renderTargetHeight);
227        glTexCoord3f(_slicePos, 0, 1); glVertex2i(0,                  _renderTargetHeight);
228        break;
229    case AXIS_Y:
230        glTexCoord3f(0, _slicePos, 0); glVertex2i(0,                  0);
231        glTexCoord3f(1, _slicePos, 0); glVertex2i(_renderTargetWidth, 0);
232        glTexCoord3f(1, _slicePos, 1); glVertex2i(_renderTargetWidth, _renderTargetHeight);
233        glTexCoord3f(0, _slicePos, 1); glVertex2i(0,                  _renderTargetHeight);
234        break;
235    case AXIS_Z:
236    default:
237        glTexCoord3f(0, 0, _slicePos); glVertex2i(0,                  0);
238        glTexCoord3f(1, 0, _slicePos); glVertex2i(_renderTargetWidth, 0);
239        glTexCoord3f(1, 1, _slicePos); glVertex2i(_renderTargetWidth, _renderTargetHeight);
240        glTexCoord3f(0, 1, _slicePos); glVertex2i(0,                  _renderTargetHeight);
241        break;
242    }
243    glEnd();
244
245    _queryVelocityFP.disableFPTextureParameter("vfield");
246    _queryVelocityFP.unbind();
247
248    glReadPixels(0, 0, _renderTargetWidth, _renderTargetHeight, GL_RGB, GL_FLOAT, _velocities);
249
250    glMatrixMode(GL_PROJECTION);
251    glPopMatrix();
252    glMatrixMode(GL_MODELVIEW);
253    glPopMatrix();
254
255    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboOrig);
256
257    glPopAttrib();
258}
259
260static void drawLineArrow(FlowSliceAxis axis)
261{
262    glBegin(GL_LINES);
263    switch (axis) {
264    case AXIS_X: // ZY plane
265        glVertex3f(0.0, 0.0, 0.0);
266        glVertex3f(0.0, 0.0, 1.0);
267
268        glVertex3f(0.0, 0.0, 1.0);
269        glVertex3f(0.0, 0.25, 0.75);
270
271        glVertex3f(0.0, 0.0, 1.0);
272        glVertex3f(0.0, -0.25, 0.75);
273        break;
274    case AXIS_Y: // XZ plane
275        glVertex3f(0.0, 0.0, 0.0);
276        glVertex3f(1.0, 0.0, 0.0);
277
278        glVertex3f(1.0, 0.0, 0.0);
279        glVertex3f(0.75, 0.0, 0.25);
280
281        glVertex3f(1.0, 0.0, 0.0);
282        glVertex3f(0.75, 0.0, -0.25);
283        break;
284    case AXIS_Z: // XY plane
285    default:
286        glVertex3f(0.0, 0.0, 0.0);
287        glVertex3f(1.0, 0.0, 0.0);
288
289        glVertex3f(1.0, 0.0, 0.0);
290        glVertex3f(0.75, 0.25, 0.0);
291
292        glVertex3f(1.0, 0.0, 0.0);
293        glVertex3f(0.75, -0.25, 0.0);
294        break;
295    }
296    glEnd();
297}
298
299void VelocityArrowsSlice::render()
300{
301    if (!_visible)
302        return;
303
304    if (_dirty) {
305        computeSamplingTicks();
306        queryVelocity();
307        _dirty = false;
308    }
309
310    TRACE("_scale: %g %g %g", _scale.x, _scale.y, _scale.z);
311    TRACE("_maxVelocityScale: %g %g %g",
312          _maxVelocityScale.x, _maxVelocityScale.y, _maxVelocityScale.z);
313
314    glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
315
316    glMatrixMode(GL_MODELVIEW);
317    glPushMatrix();
318
319    glTranslatef(_origin.x, _origin.y, _origin.z);
320    glScalef(_scale.x, _scale.y, _scale.z);
321
322    if (_renderMode == LINES) {
323        glDisable(GL_TEXTURE_2D);
324        glDisable(GL_LIGHTING);
325        glLineWidth(2.0);
326        glColor3f(_arrowColor.x, _arrowColor.y, _arrowColor.z);
327 
328        Vector3f pos;
329        Vector3f vel;
330        Vector3f refVec;
331        Vector3f blue(0, 0, 1);
332        Vector3f red(1, 0, 0);
333
334        int index = 0, icount, jcount;
335        switch (_axis) {
336        case AXIS_X:
337            icount = _tickCountZ;
338            jcount = _tickCountY;
339            refVec.set(0, 0, 1);
340            break;
341        case AXIS_Y:
342            icount = _tickCountZ;
343            jcount = _tickCountX;
344            refVec.set(1, 0, 0);
345            break;
346        case AXIS_Z:
347        default:
348            icount = _tickCountY;
349            jcount = _tickCountX;
350            refVec.set(1, 0, 0);
351            break;
352        }
353
354        for (int i = 0; i < icount; ++i) {
355            for (int j = 0; j < jcount; ++j, ++index) {
356                pos = _samplingPositions[index];
357                // Normalized velocity: [-1,1] components
358                // Project 3D vector onto sample plane
359                vel = _velocities[index].scale(_projectionVector);
360                // Length: [0,1]
361                double length = vel.length();
362                if (length < 0.0 || length > 1.0) {
363                    TRACE("***vec: (%g, %g, %g) length: %g***", vel.x, vel.y, vel.z, length);
364                    continue;
365                }
366                if (length > 0.0) {
367                    Vector3f vnorm = vel.normalize();
368                    Vector3f rotationAxis = refVec.cross(vnorm);
369                    double angle = rad2deg(acos(refVec.dot(vnorm)));
370                    Vector3f color = blue * (1.0 - length) + red * length;
371                    float scale = length;
372                    if (scale < 0.10) scale = 0.10;
373                    glMatrixMode(GL_MODELVIEW);
374                    glPushMatrix();
375                    glColor3f(color.x, color.y, color.z);
376                    glTranslatef(pos.x, pos.y, pos.z);
377                    glScalef(2.0 * _maxVelocityScale.x,
378                             2.0 * _maxVelocityScale.y,
379                             2.0 * _maxVelocityScale.z);
380                    glScalef(scale, scale, scale);
381                    if (angle > 1.0e-6 || angle < -1.0e-6)
382                        glRotated(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
383                    drawLineArrow(_axis);
384                    glPopMatrix();
385                }
386            }
387        }
388
389        glLineWidth(1.0);
390    } else {
391        glColor4f(_arrowColor.x, _arrowColor.y, _arrowColor.z, 1.0f);
392        glEnable(GL_DEPTH_TEST);
393        glDisable(GL_LIGHTING);
394#if 0
395        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
396        glEnable(GL_BLEND);
397        glDepthMask(GL_FALSE);
398#else
399        glDisable(GL_BLEND);
400#endif
401        glAlphaFunc(GL_GREATER, 0.6);
402        glEnable(GL_ALPHA_TEST);
403        glEnable(GL_POINT_SPRITE_ARB);
404        glPointSize(20);
405        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
406
407        _arrowsTex->activate();
408        glEnable(GL_TEXTURE_2D);
409        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
410
411        GLfloat atten[] = {1, 0, 0};
412        glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, atten);
413        glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 0.0f);
414        glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1.0f);
415        glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, _maxPointSize);
416        glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
417
418        // FIXME: This vertex shader won't compile with ARB_vertex_program,
419        // so it should use GLSL
420        if (!_particleShader.isVertexProgramLoaded()) {
421            _particleShader.loadVertexProgram("velocityslicevp.cg");
422        }
423        if (!_particleShader.isFragmentProgramLoaded()) {
424            _particleShader.loadFragmentProgram("velocityslicefp.cg");
425        }
426
427        _particleShader.bind();
428        _particleShader.setVPTextureParameter("vfield", _vectorFieldGraphicsID);
429        _particleShader.setFPTextureParameter("arrows", _arrowsTex->id());
430        _particleShader.setVPParameter1f("tanHalfFOV",
431                                         tan(NanoVis::getCamera()->getFov() * 0.5) * NanoVis::winHeight * 0.5);
432        _particleShader.setGLStateMatrixVPParameter("modelview",
433                                                    Shader::MODELVIEW_MATRIX,
434                                                    Shader::MATRIX_IDENTITY);
435        _particleShader.setGLStateMatrixVPParameter("mvp",
436                                                    Shader::MODELVIEW_PROJECTION_MATRIX,
437                                                    Shader::MATRIX_IDENTITY);
438
439        glEnableClientState(GL_VERTEX_ARRAY);
440        glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
441        glVertexPointer(3, GL_FLOAT, 0, 0);
442        //glEnableClientState(GL_COLOR_ARRAY);
443
444        // TBD..
445        glDrawArrays(GL_POINTS, 0, _pointCount);
446        glPointSize(1);
447
448        glDisableClientState(GL_VERTEX_ARRAY);
449        glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
450        glDisable(GL_POINT_SPRITE_ARB);
451
452        _particleShader.disableVPTextureParameter("vfield");
453        _particleShader.disableFPTextureParameter("arrows");
454        _particleShader.unbind();
455
456        glActiveTexture(GL_TEXTURE0);
457        glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
458        _arrowsTex->deactivate();
459    }
460
461    glPopMatrix();
462    glPopAttrib();
463}
464
465void
466VelocityArrowsSlice::setVectorField(Volume *volume)
467{
468    _vectorFieldGraphicsID = volume->textureID();
469#ifdef USE_WORLD_COORDS
470    Vector3f bmin, bmax;
471    volume->getBounds(bmin, bmax);
472    _origin = bmin;
473    Vector3f scale(bmax.x-bmin.x, bmax.y-bmin.y, bmax.z-bmin.z);
474#else
475    _origin = volume->getPosition();
476    Vector3f scale = volume->getPhysicalScaling();
477#endif
478    _scale.set(scale.x, scale.y, scale.z);
479
480    _dirty = true;
481}
482
483void VelocityArrowsSlice::computeSamplingTicks()
484{
485    if (_scale.x < _scale.y) {
486        if (_scale.x < _scale.z || _scale.z == 0.0) {
487            // _scale.x
488            _tickCountX = _tickCountForMinSizeAxis;
489
490            float step = _scale.x / (_tickCountX + 1);
491            _tickCountY = (int)(_scale.y/step);
492            _tickCountZ = (int)(_scale.z/step);
493        } else {
494            // _scale.z
495            _tickCountZ = _tickCountForMinSizeAxis;
496
497            float step = _scale.z / (_tickCountZ + 1);
498            _tickCountX = (int)(_scale.x/step);
499            _tickCountY = (int)(_scale.y/step);
500        }
501    } else {
502        if (_scale.y < _scale.z || _scale.z == 0.0) {
503            // _scale.y
504            _tickCountY = _tickCountForMinSizeAxis;
505
506            float step = _scale.y / (_tickCountY + 1);
507            _tickCountX = (int)(_scale.x/step);
508            _tickCountZ = (int)(_scale.z/step);
509        } else {
510            // _scale.z
511            _tickCountZ = _tickCountForMinSizeAxis;
512
513            float step = _scale.z / (_tickCountZ + 1);
514            _tickCountX = (int)(_scale.x/step);
515            _tickCountY = (int)(_scale.y/step);
516        }
517    }
518
519    switch (_axis) {
520    case AXIS_X:
521        _tickCountX = 1;
522        _renderTargetWidth = _tickCountY;
523        _renderTargetHeight = _tickCountZ;
524        break;
525    case AXIS_Y:
526        _tickCountY = 1;
527        _renderTargetWidth = _tickCountX;
528        _renderTargetHeight = _tickCountZ;
529        break;
530    default:
531    case AXIS_Z:
532        _tickCountZ = 1;
533        _renderTargetWidth = _tickCountX;
534        _renderTargetHeight = _tickCountY;
535        break;
536    }
537
538    _maxVelocityScale.x = (1.0f / _tickCountX) * 0.8f;
539    _maxVelocityScale.y = (1.0f / _tickCountY) * 0.8f;
540    _maxVelocityScale.z = (1.0f / _tickCountZ) * 0.8f;
541
542    TRACE("Tick counts: %d %d %d", _tickCountX, _tickCountY, _tickCountZ);
543
544    int pointCount = _tickCountX * _tickCountY * _tickCountZ;
545    if (_pointCount != pointCount) {
546        _samplingPositions.clear();
547        _samplingPositions.reserve(pointCount);
548        _pointCount = pointCount;
549    }
550
551    createRenderTarget();
552
553    Vector3f pos;
554    Vector3f *pinfo = NULL;
555    if (_renderMode == GLYPHS) {
556        glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vertexBufferGraphicsID);
557        pinfo = (Vector3f *)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
558    }
559
560    if (_axis == AXIS_Z) {
561        for (int y = 1; y <= _tickCountY; ++y) {
562            for (int x = 1; x <= _tickCountX; ++x) {
563                pos.x = (1.0f / (_tickCountX + 1)) * x;
564                pos.y = (1.0f / (_tickCountY + 1)) * y;
565                pos.z = _slicePos;
566                if (_renderMode == LINES) {
567                    _samplingPositions.push_back(pos);
568                } else {
569                    *pinfo = pos;
570                    ++pinfo;
571                }
572            }
573        }
574    } else if (_axis == AXIS_Y) {
575        for (int z = 1; z <= _tickCountZ; ++z) {
576            for (int x = 1; x <= _tickCountX; ++x) {
577                pos.x = (1.0f / (_tickCountX + 1)) * x;
578                pos.y = _slicePos;
579                pos.z = (1.0f / (_tickCountZ + 1)) * z;
580                if (_renderMode == LINES) {
581                    _samplingPositions.push_back(pos);
582                } else {
583                    *pinfo = pos;
584                    ++pinfo;
585                }
586            }
587        }
588    } else if (_axis == AXIS_X) {
589        for (int z = 1; z <= _tickCountZ; ++z) {
590            for (int y = 1; y <= _tickCountY; ++y) {
591                pos.x = _slicePos;
592                pos.y = (1.0f / (_tickCountY + 1)) * y;
593                pos.z = (1.0f / (_tickCountZ + 1)) * z;
594                if (_renderMode == LINES) {
595                    _samplingPositions.push_back(pos);
596                } else {
597                    *pinfo = pos;
598                    ++pinfo;
599                }
600            }
601        }
602    }
603
604    if (_renderMode == GLYPHS) {
605        glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
606    }
607}
Note: See TracBrowser for help on using the repository browser.