SplatCloudNode.cc 13.3 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
/*===========================================================================*\
*                                                                            *
*                              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 ==============================================


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
SplatCloudNode::SplatCloudNode( BaseNode *_parent, std::string _name ) : 
	BaseNode         ( _parent, _name ), 
	defaultNormal_   ( Normal(0.0f,0.0f,1.0f) ), 
	defaultPointsize_( Pointsize(0.01f) ), 
	defaultColor_    ( Color(255,255,255) ), 
	pickingBaseIndex_( 0 ), 
	vboGlId_         ( 0 ), 
	vboValid_        ( false )
{
	// allocate memory for splat cloud
	splatCloud_ = new SplatCloud;
	if( !splatCloud_ )
	{
		std::cerr << "SplatCloudNode::SplatCloudNode() : Out of memory." << std::endl;
	}

	// add (possibly) new drawmodes
	pointsDrawMode_ = DrawModes::addDrawMode( "Points" );
	dotsDrawMode_   = DrawModes::addDrawMode( "Dots"   );
	splatsDrawMode_ = DrawModes::addDrawMode( "Splats" );

	// create a new vertex-buffer-object (will be invalid and rebuilt the next time drawn (or picked))
	createVBO();
}


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


SplatCloudNode::~SplatCloudNode()
{
	destroyVBO();

	delete splatCloud_;
	splatCloud_ = 0;
}


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


Jan Möbius's avatar
Jan Möbius committed
107
108
void SplatCloudNode::boundingBox( ACG::Vec3d &_bbMin, ACG::Vec3d &_bbMax )
{
109
110
111
112
	// if something went wrong in the initialization, abort
	if( !splatCloud_ )
		return;

113
114
    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
115

116
117
    SplatCloud::PointVector::const_iterator pointIter, pointsEnd = splatCloud_->points().end();
    for ( pointIter = splatCloud_->points().begin(); pointIter != pointsEnd; ++pointIter )
118
119
    {
        const Point &p = *pointIter;
Jan Möbius's avatar
Jan Möbius committed
120

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

123
124
125
        bbMin.minimize( acgp );
        bbMax.maximize( acgp );
    }
Jan Möbius's avatar
Jan Möbius committed
126

127
128
    _bbMin.minimize( ACG::Vec3d( bbMin ) );
    _bbMax.maximize( ACG::Vec3d( bbMax ) );
Jan Möbius's avatar
Jan Möbius committed
129
130
131
132
133
}


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

134

Jan Möbius's avatar
Jan Möbius committed
135
136
void SplatCloudNode::draw( GLState &_state, const DrawModes::DrawMode &_drawMode )
{
137
138
139
140
	// if something went wrong in the initialization, abort
	if( !splatCloud_ )
		return;

141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    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
161
        rebuildVBO( _state );
162
163
164
165
166
167
168
169
170

    // 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
171
        glInterleavedArrays( GL_T4F_C4F_N3F_V4F, 0, 0 );
172
173

        // arrays are automatically enabled by glInterleavedArrays()
Dominik Sibbing's avatar
Dominik Sibbing committed
174
175
176
177
        //glEnableClientState( GL_VERTEX_ARRAY         );
        //glEnableClientState( GL_NORMAL_ARRAY         );
        //glEnableClientState( GL_COLOR_ARRAY          );
        //glEnableClientState( GL_TEXTURE_COORD_ARRAY  );
178
179
180
181
182
183
184
185
186
187
188

        // 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
189
        glDrawArrays( GL_POINTS, 0, splatCloud_->numPoints() );
190
191
192
193
194
195
196
197

        // 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
198
199
200
201
        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 );
202
203
204
205

        // deactivate vertex-buffer-object
        ACG::GLState::bindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
    }
Jan Möbius's avatar
Jan Möbius committed
206
207
208
209
210
211
212
213
214
}


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


// 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 )
215
216
217
{
    g_pickDrawMode = _drawMode;
}
Jan Möbius's avatar
Jan Möbius committed
218
219
220
221
222

// ----

void SplatCloudNode::pick( GLState &_state, PickTarget _target )
{
223
224
225
226
	// if something went wrong in the initialization, abort
	if( !splatCloud_ )
		return;

227
	// if pick target is valid...
Dominik Sibbing's avatar
Dominik Sibbing committed
228
229
230
	if( _target == PICK_ANYTHING || _target == PICK_VERTEX )
	{
		// set number of pick colors used (each points gets a unique pick color)
231
		if( !_state.pick_set_maximum( splatCloud_->numPoints() ) )
232
233
		{
			std::cerr << "SplatCloudNode::pick() : Color range too small, picking failed." << std::endl;
Dominik Sibbing's avatar
Dominik Sibbing committed
234
			return;
235
		}
Jan Möbius's avatar
Jan Möbius committed
236

237
238
		// if in color picking mode...
		if( _state.color_picking() )
Dominik Sibbing's avatar
Dominik Sibbing committed
239
		{
240
241
242
			// if picking base index has changed, rebuild VBO so new pick colors will be used
			if( pickingBaseIndex_ != _state.pick_current_index() )
				vboValid_ = false;
Jan Möbius's avatar
Jan Möbius committed
243

244
245
246
			// TODO: see above ( enterPick() )
			draw( _state, g_pickDrawMode );
		}
Dominik Sibbing's avatar
Dominik Sibbing committed
247
	}
Jan Möbius's avatar
Jan Möbius committed
248
249
250
251
252
253
}


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


254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
void SplatCloudNode::copySplatCloud( const SplatCloud &_splatCloud )
{
	delete splatCloud_;

	splatCloud_ = new SplatCloud( _splatCloud );
	if( !splatCloud_ )
	{
		std::cerr << "SplatCloudNode::copySplatCloud() : Out of memory." << std::endl;
	}
}


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


Jan Möbius's avatar
Jan Möbius committed
269
270
void SplatCloudNode::createVBO()
{
271
272
273
274
275
    // 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
276
277
278
279
280
281
282
283
}


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


void SplatCloudNode::destroyVBO()
{
284
285
286
287
288
289
290
291
292
    // 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
293
294
295
296
297
298
299
300
}


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


static void addFloatToBuffer( float _value, unsigned char *&_buffer )
{
301
302
303
304
305
306
307
308
    // 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
309
310
311
312
313
314
}


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


Dominik Sibbing's avatar
Dominik Sibbing committed
315
void SplatCloudNode::rebuildVBO( GLState &_state )
Jan Möbius's avatar
Jan Möbius committed
316
{
317
318
319
320
	// if something went wrong in the initialization, abort
	if( !splatCloud_ )
		return;

321
322
323
324
325
    // 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
326
    if ( splatCloud_->numPoints() == 0 )
327
328
329
330
331
    {
        vboValid_ = false;
        return;
    }

Dominik Sibbing's avatar
Dominik Sibbing committed
332
    // we use GL_T4F_C4F_N3F_V4F as interleaved array type, so we have 4+4+3+4 = 15 floats per splat
333
    unsigned int size = splatCloud_->numPoints() * 15 * sizeof(float);
334
335
336
337
338
339
340
341
342
343
344
345
346

    // 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 )
    {
347
348
349
350
351
352
        // if in color picking mode...
        if( _state.color_picking() )
        {
            // store picking base index
            pickingBaseIndex_ = _state.pick_current_index();
        }
Dominik Sibbing's avatar
Dominik Sibbing committed
353

354
        // for all points...
355
        int i, num = splatCloud_->numPoints();
356
357
358
359
        for ( i=0; i<num; ++i )
        {
            static const float RCP255 = 1.0f / 255.0f;

Dominik Sibbing's avatar
Dominik Sibbing committed
360
            // add pick color
Dominik Sibbing's avatar
Dominik Sibbing committed
361
            Vec4uc pc = _state.pick_get_name_color( i );
Dominik Sibbing's avatar
Dominik Sibbing committed
362
363
364
365
366
            addFloatToBuffer( RCP255 * pc[0], buffer );
            addFloatToBuffer( RCP255 * pc[1], buffer );
            addFloatToBuffer( RCP255 * pc[2], buffer );
            addFloatToBuffer( RCP255 * pc[3], buffer );

367
            // add color
368
            const Color &c = getColor( i );
369
370
371
372
373
            addFloatToBuffer( RCP255 * c[0], buffer );
            addFloatToBuffer( RCP255 * c[1], buffer );
            addFloatToBuffer( RCP255 * c[2], buffer );

            // add pointsize (as alpha-component of color)
374
            const Pointsize &ps = getPointsize( i );
375
376
377
            addFloatToBuffer( ps, buffer );

            // add normal
378
            const Normal &n = getNormal( i );
379
380
381
382
383
            addFloatToBuffer( n[0], buffer );
            addFloatToBuffer( n[1], buffer );
            addFloatToBuffer( n[2], buffer );

            // add point
384
            const Point &p = getPoint( i );
385
386
387
            addFloatToBuffer( p[0], buffer );
            addFloatToBuffer( p[1], buffer );
            addFloatToBuffer( p[2], buffer );
Dominik Sibbing's avatar
Dominik Sibbing committed
388
            addFloatToBuffer( 1.0f, buffer );
389
390
391
392
393
394
395
396
397
398
399
400
401
402
        }
    }

    // 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;
}


Jan Möbius's avatar
Jan Möbius committed
403
404
405
406
407
//================================================================


} // namespace SceneGraph
} // namespace ACG