SplatCloudNode.cc 14.1 KB
Newer Older
Jan Möbius's avatar
Jan Möbius committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*===========================================================================*\
*                                                                            *
*                              OpenFlipper                                   *
*      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen       *
*                           www.openflipper.org                              *
*                                                                            *
*--------------------------------------------------------------------------- *
*  This file is part of OpenFlipper.                                         *
*                                                                            *
*  OpenFlipper is free software: you can redistribute it and/or modify       *
*  it under the terms of the GNU Lesser General Public License as            *
*  published by the Free Software Foundation, either version 3 of            *
*  the License, or (at your option) any later version with the               *
*  following exceptions:                                                     *
*                                                                            *
*  If other files instantiate templates or use macros                        *
*  or inline functions from this file, or you compile this file and          *
*  link it with other files to produce an executable, this file does         *
*  not by itself cause the resulting executable to be covered by the         *
*  GNU Lesser General Public License. This exception does not however        *
*  invalidate any other reasons why the executable file might be             *
*  covered by the GNU Lesser General Public License.                         *
*                                                                            *
*  OpenFlipper is distributed in the hope that it will be useful,            *
*  but WITHOUT ANY WARRANTY; without even the implied warranty of            *
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
*  GNU Lesser General Public License for more details.                       *
*                                                                            *
*  You should have received a copy of the GNU LesserGeneral Public           *
*  License along with OpenFlipper. If not,                                   *
*  see <http://www.gnu.org/licenses/>.                                       *
*                                                                            *
\*===========================================================================*/

/*===========================================================================*\
*                                                                            *
*   $Revision$                                                       *
*   $LastChangedBy$                                                *
*   $Date$                     *
*                                                                            *
\*===========================================================================*/

//================================================================
//
//  CLASS SplatCloudNode - IMPLEMENTATION
//
//================================================================


//== INCLUDES ====================================================


#include "SplatCloudNode.hh"


//== NAMESPACES ==================================================


namespace ACG {
namespace SceneGraph {


//== IMPLEMENTATION ==============================================


void SplatCloudNode::boundingBox( ACG::Vec3d &_bbMin, ACG::Vec3d &_bbMax )
{
68
69
    ACG::Vec3f bbMin( FLT_MAX, FLT_MAX, FLT_MAX );
    ACG::Vec3f bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX );
Jan Möbius's avatar
Jan Möbius committed
70

71
72
73
74
    PointVector::const_iterator pointIter;
    for ( pointIter = points_.begin(); pointIter != points_.end(); ++pointIter )
    {
        const Point &p = *pointIter;
Jan Möbius's avatar
Jan Möbius committed
75

76
        ACG::Vec3f acgp( p[0], p[1], p[2] );
Jan Möbius's avatar
Jan Möbius committed
77

78
79
80
        bbMin.minimize( acgp );
        bbMax.maximize( acgp );
    }
Jan Möbius's avatar
Jan Möbius committed
81

82
83
    ACG::Vec3d bbMind = ACG::Vec3d( bbMin );
    ACG::Vec3d bbMaxd = ACG::Vec3d( bbMax );
Jan Möbius's avatar
Jan Möbius committed
84

85
86
    _bbMin.minimize( bbMind );
    _bbMax.maximize( bbMaxd );
Jan Möbius's avatar
Jan Möbius committed
87
88
89
90
91
}


//----------------------------------------------------------------

92

Jan Möbius's avatar
Jan Möbius committed
93
94
void SplatCloudNode::draw( GLState &_state, const DrawModes::DrawMode &_drawMode )
{
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    static const int RENDERMODE_POINTS = 0;
    static const int RENDERMODE_DOTS   = 1;
    static const int RENDERMODE_SPLATS = 2;

    // check if drawmode is valid
    int rendermode;
    if ( _drawMode.containsAtomicDrawMode( splatsDrawMode_ ) )
        rendermode = RENDERMODE_SPLATS;
    else if ( _drawMode.containsAtomicDrawMode( dotsDrawMode_ ) )
        rendermode = RENDERMODE_DOTS;
    else if ( _drawMode.containsAtomicDrawMode( pointsDrawMode_ ) )
        rendermode = RENDERMODE_POINTS;
    else
        return;

    // set desired depth function
    ACG::GLState::depthFunc( _state.depthFunc() );

    // is vertex-buffer-object is invalid then rebuild
    if ( !vboValid_ )
Dominik Sibbing's avatar
Dominik Sibbing committed
115
        rebuildVBO( _state );
116
117
118
119
120
121
122
123
124

    // if vertex-buffer-object is valid now...
    // (if not it will be rebuilt the next time, but this should not happen)
    if ( vboValid_ )
    {
        // activate vertex-buffer-object
        ACG::GLState::bindBufferARB( GL_ARRAY_BUFFER_ARB, vboGlId_ );

        // tell GL where our data is (NULL = beginning of vertex-buffer-object)
Dominik Sibbing's avatar
Dominik Sibbing committed
125
        glInterleavedArrays( GL_T4F_C4F_N3F_V4F, 0, 0 );
126
127

        // arrays are automatically enabled by glInterleavedArrays()
Dominik Sibbing's avatar
Dominik Sibbing committed
128
129
130
131
        //glEnableClientState( GL_VERTEX_ARRAY         );
        //glEnableClientState( GL_NORMAL_ARRAY         );
        //glEnableClientState( GL_COLOR_ARRAY          );
        //glEnableClientState( GL_TEXTURE_COORD_ARRAY  );
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

        // Normals are always needed for backface culling, even in drawmode 'Points'!
        // Colors are always needed for pointsizes, even in color picking mode!

        // enable "pointsize by program" depending on current rendermode
        if ( rendermode != RENDERMODE_POINTS )
        {
            ACG::GLState::enable( GL_VERTEX_PROGRAM_POINT_SIZE );
        }

        // draw as GLpoints
        glDrawArrays( GL_POINTS, 0, numPoints() );

        // disable "pointsize by program" if it was enabled
        if ( rendermode != RENDERMODE_POINTS )
        {
            ACG::GLState::disable( GL_VERTEX_PROGRAM_POINT_SIZE );
        }

        // disable arrays
Dominik Sibbing's avatar
Dominik Sibbing committed
152
153
154
155
        ACG::GLState::disableClientState( GL_VERTEX_ARRAY        );
        ACG::GLState::disableClientState( GL_NORMAL_ARRAY        );
        ACG::GLState::disableClientState( GL_COLOR_ARRAY         );
        ACG::GLState::disableClientState( GL_TEXTURE_COORD_ARRAY );
156
157
158
159

        // deactivate vertex-buffer-object
        ACG::GLState::bindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
    }
Jan Möbius's avatar
Jan Möbius committed
160
161
162
163
164
165
166
167
168
}


//----------------------------------------------------------------


// TODO: hack, because pick() doesn't get a drawmode
static DrawModes::DrawMode g_pickDrawMode;
void SplatCloudNode::enterPick( GLState &_state, PickTarget _target, const DrawModes::DrawMode &_drawMode )
169
170
171
{
    g_pickDrawMode = _drawMode;
}
Jan Möbius's avatar
Jan Möbius committed
172
173
174
175
176

// ----

void SplatCloudNode::pick( GLState &_state, PickTarget _target )
{
Dominik Sibbing's avatar
Dominik Sibbing committed
177
178
179
180
181
182
	// if pick target is valid, ...
	if( _target == PICK_ANYTHING || _target == PICK_VERTEX )
	{
		// set number of pick colors used (each points gets a unique pick color)
		if( !_state.pick_set_maximum( points_.size() ) )
			return;
Jan Möbius's avatar
Jan Möbius committed
183

Dominik Sibbing's avatar
Dominik Sibbing committed
184
185
		// get first pick color
		Vec4uc pc = _state.pick_get_name_color( 0 );
Jan Möbius's avatar
Jan Möbius committed
186

Dominik Sibbing's avatar
Dominik Sibbing committed
187
188
189
190
191
192
		// if first pick color has changed, store this color and invalidate VBO (so VBO will be rebuilt and new pick colors will be used)
		if( firstPickColor_ != pc )
		{
			firstPickColor_ = pc;
			vboValid_ = false;
		}
Jan Möbius's avatar
Jan Möbius committed
193

Dominik Sibbing's avatar
Dominik Sibbing committed
194
195
196
		// TODO: see above ( enterPick() )
		draw( _state, g_pickDrawMode );
	}
Jan Möbius's avatar
Jan Möbius committed
197
198
199
200
201
202
203
204
}


//----------------------------------------------------------------


void SplatCloudNode::createVBO()
{
205
206
207
208
209
    // create a new vertex-buffer-object if not already existing
    if ( vboGlId_ == 0 )
    {
        glGenBuffersARB( 1, &vboGlId_ );
    }
Jan Möbius's avatar
Jan Möbius committed
210
211
212
213
214
215
216
217
}


//----------------------------------------------------------------


void SplatCloudNode::destroyVBO()
{
218
219
220
221
222
223
224
225
226
    // delete existing vertex-buffer-object
    if ( vboGlId_ != 0 )
    {
        glDeleteBuffersARB( 1, &vboGlId_ );
        vboGlId_ = 0;
    }

    // make vertex-buffer-object invalid so it will not be used
    vboValid_ = false;
Jan Möbius's avatar
Jan Möbius committed
227
228
229
230
231
232
233
234
}


//----------------------------------------------------------------


static void addFloatToBuffer( float _value, unsigned char *&_buffer )
{
235
236
237
238
239
240
241
242
    // get pointer
    unsigned char *v = (unsigned char *) &_value;

    // copy over 4 bytes
    *_buffer++ = *v++;
    *_buffer++ = *v++;
    *_buffer++ = *v++;
    *_buffer++ = *v;
Jan Möbius's avatar
Jan Möbius committed
243
244
245
246
247
248
}


//----------------------------------------------------------------


Dominik Sibbing's avatar
Dominik Sibbing committed
249
void SplatCloudNode::rebuildVBO( GLState &_state )
Jan Möbius's avatar
Jan Möbius committed
250
{
251
252
253
254
255
256
257
258
259
260
261
    // check if vertex-buffer-object has already been created (and not destroyed so far)
    if ( vboGlId_ == 0 )
        return;

    // check if there could be a valid vertex-buffer-object
    if ( numPoints() == 0 )
    {
        vboValid_ = false;
        return;
    }

Dominik Sibbing's avatar
Dominik Sibbing committed
262
263
    // we use GL_T4F_C4F_N3F_V4F as interleaved array type, so we have 4+4+3+4 = 15 floats per splat
    unsigned int size = numPoints() * 15 * sizeof(float);
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280

    // activate vertex-buffer-object
    ACG::GLState::bindBufferARB( GL_ARRAY_BUFFER_ARB, vboGlId_ );

    // tell GL that we are seldom updating the vertex-buffer-object but are often drawing it
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, 0, GL_STATIC_DRAW_ARB );

    // get pointer to vertex-buffer-object's memory
    unsigned char *buffer = (unsigned char *) glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );

    // if pointer is valid...
    if ( buffer )
    {
        bool hasNrm = hasNormals();
        bool hasPS  = hasPointsizes();
        bool hasCol = hasColors();

Dominik Sibbing's avatar
Dominik Sibbing committed
281
282
283
        // set number of pick colors used (each points gets a unique pick color)
        _state.pick_set_maximum( numPoints() );

284
285
286
287
288
289
        // for all points...
        int i, num = numPoints();
        for ( i=0; i<num; ++i )
        {
            static const float RCP255 = 1.0f / 255.0f;

Dominik Sibbing's avatar
Dominik Sibbing committed
290
            // add pick color
Dominik Sibbing's avatar
Dominik Sibbing committed
291
            Vec4uc pc = _state.pick_get_name_color( i );
Dominik Sibbing's avatar
Dominik Sibbing committed
292
293
294
295
296
            addFloatToBuffer( RCP255 * pc[0], buffer );
            addFloatToBuffer( RCP255 * pc[1], buffer );
            addFloatToBuffer( RCP255 * pc[2], buffer );
            addFloatToBuffer( RCP255 * pc[3], buffer );

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
            // add color
            const Color &c = hasCol ? colors_[i] : defaultColor_;
            addFloatToBuffer( RCP255 * c[0], buffer );
            addFloatToBuffer( RCP255 * c[1], buffer );
            addFloatToBuffer( RCP255 * c[2], buffer );

            // add pointsize (as alpha-component of color)
            const Pointsize &ps = hasPS ? pointsizes_[i] : defaultPointsize_;
            addFloatToBuffer( ps, buffer );

            // add normal
            const Normal &n = hasNrm ? normals_[i] : defaultNormal_;
            addFloatToBuffer( n[0], buffer );
            addFloatToBuffer( n[1], buffer );
            addFloatToBuffer( n[2], buffer );

            // add point
            const Point &p = points_[i];
            addFloatToBuffer( p[0], buffer );
            addFloatToBuffer( p[1], buffer );
            addFloatToBuffer( p[2], buffer );
Dominik Sibbing's avatar
Dominik Sibbing committed
318
            addFloatToBuffer( 1.0f, buffer );
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
        }
    }

    // release pointer to vertex-buffer-object's memory
    bool success = glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );

    // deactivate vertex-buffer-object
    ACG::GLState::bindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );

    // mark vertex-buffer-object as valid only if it was successfully updated and unmaped
    vboValid_ = (buffer != 0) && success;
}


//----------------------------------------------------------------


void SplatCloudNode::normalizeSize()
{
Dominik Sibbing's avatar
Dominik Sibbing committed
338
	// check if there is nothing to do
339
	if( points_.size() == 0 )
Jan Möbius's avatar
Jan Möbius committed
340
341
		return;

342
343
344
345
346
347
	// calculate center-of-gravety
	float cogX = 0.0f;
	float cogY = 0.0f;
	float cogZ = 0.0f;
	SplatCloudNode::PointVector::iterator pointIter;
	for( pointIter = points_.begin(); pointIter != points_.end(); ++pointIter )
Jan Möbius's avatar
Jan Möbius committed
348
	{
349
350
351
352
353
		const SplatCloudNode::Point &p = *pointIter;

		cogX += p[0];
		cogY += p[1];
		cogZ += p[2];
Jan Möbius's avatar
Jan Möbius committed
354
355
	}

356
357
358
359
	float rcp_count = 1.0f / (float) points_.size();
	cogX *= rcp_count;
	cogY *= rcp_count;
	cogZ *= rcp_count;
Dominik Sibbing's avatar
Dominik Sibbing committed
360
361

	cur_translation_ = Point( -cogX, -cogY, -cogZ );
362
363
	translate( cur_translation_ );
	std::cout << "SplatCloudNode::normalizeSize(): translate points by: " << cur_translation_ << std::endl;
Dominik Sibbing's avatar
Dominik Sibbing committed
364

365
366
367
368
369
370
371
	// calculate squared length
	float sqLength = 0.0f;
	for( pointIter = points_.begin(); pointIter != points_.end(); ++pointIter )
	{
		SplatCloudNode::Point &p = *pointIter;
		sqLength += p[0]*p[0] + p[1]*p[1] + p[2]*p[2];
	}
Jan Möbius's avatar
Jan Möbius committed
372

373
	float s = (float) sqrt( sqLength * rcp_count );
Jan Möbius's avatar
Jan Möbius committed
374

375
376
	if( s == 0.0f )
	  return;
Jan Möbius's avatar
Jan Möbius committed
377

Dominik Sibbing's avatar
Dominik Sibbing committed
378
	cur_scale_factor_ = 1.0f / s;
379
380
381
	scale( cur_scale_factor_ );
	std::cout << "SplatCloudNode::normalizeSize(): scaling points with factor: " << cur_scale_factor_ << std::endl;
}
Jan Möbius's avatar
Jan Möbius committed
382

Dominik Sibbing's avatar
Dominik Sibbing committed
383

384
385
386
//----------------------------------------------------------------


Dominik Sibbing's avatar
Dominik Sibbing committed
387
void SplatCloudNode::translate( const Point &_t )
388
{
Dominik Sibbing's avatar
Dominik Sibbing committed
389
390
	// translate points
	SplatCloudNode::PointVector::iterator pointIter;
391
	for( pointIter = points_.begin(); pointIter != points_.end(); ++pointIter )
Jan Möbius's avatar
Jan Möbius committed
392
	{
393
		SplatCloudNode::Point &p = *pointIter;
Dominik Sibbing's avatar
Dominik Sibbing committed
394

395
396
397
398
399
400
		p[0] += _t[0];
		p[1] += _t[1];
		p[2] += _t[2];
	}
}

Dominik Sibbing's avatar
Dominik Sibbing committed
401

402
//----------------------------------------------------------------
Jan Möbius's avatar
Jan Möbius committed
403

404

Dominik Sibbing's avatar
Dominik Sibbing committed
405
void SplatCloudNode::scale( float _s )
406
{
Dominik Sibbing's avatar
Dominik Sibbing committed
407
	// scale points (and pointsizes as well)
408
409
410
	if( pointsizes_.size() == points_.size() )
	{
		SplatCloudNode::PointsizeVector::iterator pointsizeIter = pointsizes_.begin();
Dominik Sibbing's avatar
Dominik Sibbing committed
411
		SplatCloudNode::PointVector::iterator     pointIter;
412
		for( pointIter = points_.begin(); pointIter != points_.end(); ++pointIter, ++pointsizeIter )
Jan Möbius's avatar
Jan Möbius committed
413
		{
414
415
416
			SplatCloudNode::Point     &p  = *pointIter;
			SplatCloudNode::Pointsize &ps = *pointsizeIter;

Dominik Sibbing's avatar
Dominik Sibbing committed
417
418
419
420
			p[0] *= _s;
			p[1] *= _s;
			p[2] *= _s;
			ps   *= _s; // scale pointsize as well
Jan Möbius's avatar
Jan Möbius committed
421
422
		}
	}
423
424
	else
	{
Dominik Sibbing's avatar
Dominik Sibbing committed
425
		SplatCloudNode::PointVector::iterator pointIter;
426
427
428
		for( pointIter = points_.begin(); pointIter != points_.end(); ++pointIter )
		{
			SplatCloudNode::Point &p = *pointIter;
Jan Möbius's avatar
Jan Möbius committed
429

Dominik Sibbing's avatar
Dominik Sibbing committed
430
431
432
			p[0] *= _s;
			p[1] *= _s;
			p[2] *= _s;
433
		}
Dominik Sibbing's avatar
Dominik Sibbing committed
434
	}	
Jan Möbius's avatar
Jan Möbius committed
435
436
}

Dominik Sibbing's avatar
Dominik Sibbing committed
437

Jan Möbius's avatar
Jan Möbius committed
438
439
440
441
442
//================================================================


} // namespace SceneGraph
} // namespace ACG