PolyLineNodeT.cc 35.1 KB
Newer Older
Jan Möbius's avatar
 
Jan Möbius committed
1 2 3
/*===========================================================================*\
 *                                                                           *
 *                              OpenFlipper                                  *
Martin Schultz's avatar
Martin Schultz committed
4 5 6 7
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
 *           Department of Computer Graphics and Multimedia                  *
 *                          All rights reserved.                             *
 *                            www.openflipper.org                            *
Jan Möbius's avatar
 
Jan Möbius committed
8 9
 *                                                                           *
 *---------------------------------------------------------------------------*
Martin Schultz's avatar
Martin Schultz committed
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
 * This file is part of OpenFlipper.                                         *
 *---------------------------------------------------------------------------*
 *                                                                           *
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
Jan Möbius's avatar
 
Jan Möbius committed
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
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                       *
 *   $Author$                                                      *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/




//=============================================================================
//
//  CLASS PolyLineNodeT - IMPLEMENTATION
//
//=============================================================================

#define ACG_POLYLINENODET_C

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

#include "PolyLineNodeT.hh"
#include <ACG/GL/gl.hh>
Christopher Tenter's avatar
Christopher Tenter committed
65
#include <ACG/GL/ShaderCache.hh>
Jan Möbius's avatar
 
Jan Möbius committed
66 67 68 69 70 71 72 73 74 75
#include <ACG/Utils/VSToolsT.hh>
#include <vector>

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

namespace ACG {
namespace SceneGraph {

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

76 77 78 79 80
/// Constructor
template <class PolyLine>
PolyLineNodeT<PolyLine>::PolyLineNodeT(PolyLine& _pl, BaseNode* _parent, std::string _name) :
        BaseNode(_parent, _name),
        polyline_(_pl),
81 82
        updateVBO_(true),
        sphere_(0)
83

84 85
{

86 87 88 89 90 91 92 93 94
  // Initialize our local draw mode references
  POINTS_SPHERES = DrawModes::DrawMode(ACG::SceneGraph::DrawModes::addDrawMode("Points (as Spheres)",
                                                                               ACG::SceneGraph::DrawModes::DrawModeProperties(ACG::SceneGraph::DrawModes::PRIMITIVE_POLYGON,
                                                                               ACG::SceneGraph::DrawModes::LIGHTSTAGE_SMOOTH,
                                                                               ACG::SceneGraph::DrawModes::NORMAL_PER_VERTEX)));

  POINTS_SPHERES_SCREEN = DrawModes::DrawMode(ACG::SceneGraph::DrawModes::addDrawMode("Points (as Spheres, constant screen size)",
                                                                               ACG::SceneGraph::DrawModes::DrawModeProperties(ACG::SceneGraph::DrawModes::PRIMITIVE_POLYGON,
                                                                               ACG::SceneGraph::DrawModes::LIGHTSTAGE_SMOOTH,
95
                                                                               ACG::SceneGraph::DrawModes::NORMAL_PER_VERTEX)));
96 97 98

  // Initial default draw mode
  drawMode(DrawModes::WIREFRAME | DrawModes::POINTS );
99 100 101 102
}

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

103 104 105 106 107 108 109 110
template <class PolyLine>
PolyLineNodeT<PolyLine>::~PolyLineNodeT()
{
  delete sphere_;
}

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

Jan Möbius's avatar
 
Jan Möbius committed
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
boundingBox(Vec3d& _bbMin, Vec3d& _bbMax)
{
  for (unsigned int i=0; i< polyline_.n_vertices(); ++i)
  {
    _bbMin.minimize(polyline_.point(i));
    _bbMax.maximize(polyline_.point(i));
  }
}


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


template <class PolyLine>
DrawModes::DrawMode
PolyLineNodeT<PolyLine>::
130
availableDrawModes() const
Jan Möbius's avatar
 
Jan Möbius committed
131
{
132
  return (DrawModes::WIREFRAME | DrawModes::POINTS | DrawModes::POINTS_COLORED | POINTS_SPHERES | POINTS_SPHERES_SCREEN | DrawModes::EDGES_COLORED);
Jan Möbius's avatar
 
Jan Möbius committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
}


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


template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
draw(GLState& _state, const DrawModes::DrawMode& _drawMode)
{
  // Block if we do not have any vertices
  if ( polyline_.n_vertices() == 0 ) 
    return;

148 149 150 151
  // Update the vbo only if required.
  if ( updateVBO_ )
    updateVBO();

Jan Möbius's avatar
 
Jan Möbius committed
152 153 154 155
  ACG::GLState::disable(GL_LIGHTING);
  ACG::GLState::disable(GL_TEXTURE_2D);
  
  // Bind the vertex array
156
  vbo_.bind();
157

158
  ACG::Vec4f color = _state.ambient_color()  + _state.diffuse_color();
Jan Möbius's avatar
 
Jan Möbius committed
159 160

  // draw points
161
  if (_drawMode & DrawModes::POINTS || _drawMode & DrawModes::POINTS_COLORED)
Jan Möbius's avatar
 
Jan Möbius committed
162
  {
163 164
    vertexDecl_.activateFixedFunction();

Jan Möbius's avatar
 
Jan Möbius committed
165
    // draw selection
166
    if( polyline_.vertex_selections_available() && !selectedVertexIndexBuffer_.empty())
Jan Möbius's avatar
 
Jan Möbius committed
167 168 169
    {
      // save old values
      float point_size_old = _state.point_size();
170
      _state.set_color( Vec4f(1,0,0,1) );
Jan Möbius's avatar
 
Jan Möbius committed
171 172
      _state.set_point_size(point_size_old+4);

173
      glDrawElements(GL_POINTS, selectedVertexIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedVertexIndexBuffer_[0]));
Jan Möbius's avatar
 
Jan Möbius committed
174 175 176 177

      _state.set_point_size(point_size_old);
    }

178 179
    _state.set_color( color );

180 181 182 183 184 185 186

    if (_drawMode & DrawModes::POINTS_COLORED)
    {
      vertexDecl_.deactivateFixedFunction();
      vertexDeclVCol_.activateFixedFunction();
    }
    
187
    // Draw all vertices (don't care about selection)
188
    glDrawArrays(GL_POINTS, 0, polyline_.n_vertices());
Jan Möbius's avatar
 
Jan Möbius committed
189
    
190 191 192 193
    if (_drawMode & DrawModes::POINTS_COLORED)
      vertexDeclVCol_.deactivateFixedFunction();
    else
      vertexDecl_.deactivateFixedFunction();
Jan Möbius's avatar
 
Jan Möbius committed
194 195 196
  }

  // draw line segments
197
  if (_drawMode & DrawModes::WIREFRAME) {
198
    vertexDecl_.activateFixedFunction();
199

Jan Möbius's avatar
 
Jan Möbius committed
200
    // draw selection
201
    if (polyline_.edge_selections_available() && !selectedEdgeIndexBuffer_.empty()) {
Jan Möbius's avatar
 
Jan Möbius committed
202 203
      // save old values
      float line_width_old = _state.line_width();
204 205
      _state.set_color(Vec4f(1, 0, 0, 1));
      _state.set_line_width(2 * line_width_old);
Jan Möbius's avatar
 
Jan Möbius committed
206

207
      glDrawElements(GL_LINES, selectedEdgeIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedEdgeIndexBuffer_[0]));
Jan Möbius's avatar
 
Jan Möbius committed
208 209 210 211

      _state.set_line_width(line_width_old);
    }

212 213
    _state.set_color( color );

214 215 216 217
    if ( polyline_.is_closed() )
      glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices() + 1);
    else
      glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices());
218

219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
    vertexDecl_.deactivateFixedFunction();
  }


  if (_drawMode & DrawModes::EDGES_COLORED) {
    vertexDecl_.activateFixedFunction();

    // draw selection
    if (polyline_.edge_selections_available() && !selectedEdgeIndexBuffer_.empty()) {
      // save old values
      float line_width_old = _state.line_width();
      _state.set_color(Vec4f(1, 0, 0, 1));
      _state.set_line_width(2 * line_width_old);

      glDrawElements(GL_LINES, selectedEdgeIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedEdgeIndexBuffer_[0]));

      _state.set_line_width(line_width_old);
    }

    vertexDecl_.deactivateFixedFunction();

    _state.set_color(color);


    vertexDeclECol_.activateFixedFunction();
    if (polyline_.is_closed())
      glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices() + 1);
    else
      glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices());

    vertexDeclECol_.deactivateFixedFunction();
Jan Möbius's avatar
 
Jan Möbius committed
250
  }
251

252

Jan Möbius's avatar
 
Jan Möbius committed
253
  // draw normals
254
  if (polyline_.vertex_normals_available()) {
Jan Möbius's avatar
 
Jan Möbius committed
255 256
    double avg_len = polyline_.n_edges() > 0 ? (polyline_.length() / polyline_.n_edges() * 0.75) : 0;
    std::vector<Point> ps;
257
    for (unsigned int i = 0; i < polyline_.n_vertices(); ++i) {
Jan Möbius's avatar
 
Jan Möbius committed
258
      ps.push_back(polyline_.point(i));
259 260 261
      ps.push_back(polyline_.point(i) + polyline_.vertex_normal(i) * avg_len);
      if (polyline_.vertex_binormals_available())
        ps.push_back(polyline_.point(i) + polyline_.vertex_binormal(i) * avg_len);
Jan Möbius's avatar
 
Jan Möbius committed
262
    }
263 264

    // Disable the big buffer and switch to in memory buffer
265
    vbo_.unbind();
266 267
    ACG::GLState::vertexPointer(&ps[0]);

Jan Möbius's avatar
 
Jan Möbius committed
268
    float line_width_old = _state.line_width();
Matthias Möller's avatar
Matthias Möller committed
269
    _state.set_color( Vec4f(0.8f, 0.f, 0.f, 1.f) );
Jan Möbius's avatar
 
Jan Möbius committed
270 271 272 273
    _state.set_line_width(1);

    int stride = polyline_.vertex_binormals_available() ? 3 : 2;
    glBegin(GL_LINES);
274 275 276
    for (unsigned int i = 0; i < polyline_.n_vertices(); ++i) {
      glArrayElement(stride * i);
      glArrayElement(stride * i + 1);
Jan Möbius's avatar
 
Jan Möbius committed
277 278
    }
    glEnd();
279 280

    if (polyline_.vertex_binormals_available()) {
Matthias Möller's avatar
Matthias Möller committed
281
      _state.set_color( Vec4f(0.f, 0.f, 0.8f, 1.f) );
Jan Möbius's avatar
 
Jan Möbius committed
282
      glBegin(GL_LINES);
283 284 285
      for (unsigned int i = 0; i < polyline_.n_vertices(); ++i) {
        glArrayElement(stride * i);
        glArrayElement(stride * i + 2);
Jan Möbius's avatar
 
Jan Möbius committed
286 287 288 289 290 291 292
      }
      glEnd();
    }

    _state.set_line_width(line_width_old);
  }
  
293
  vbo_.unbind();
294

Jan Möbius's avatar
 
Jan Möbius committed
295 296
  //Disable the vertex array
  ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
297

298 299
  // draw vertices as spheres, using the radius given in the polyline
  if (_drawMode & POINTS_SPHERES)
300 301 302 303 304 305 306 307 308 309 310 311 312 313
  {
    // create sphere if not yet done
    if(!sphere_)
      sphere_ = new GLSphere(10,10);

    if( polyline_.vertex_selections_available())
    {
      for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
      {
        if(polyline_.vertex_selected(i))
          _state.set_color( Vec4f(1,0,0,1) );
        else
          _state.set_color( color );

314
        sphere_->draw(_state, _state.point_size(), (Vec3f)polyline_.point(i));
315 316 317 318 319 320
      }
    }
    else
    {
      _state.set_color( color );
      for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
321
        sphere_->draw(_state, _state.point_size(), (Vec3f)polyline_.point(i));
322 323
    }
  }
324 325 326 327 328 329 330 331
  // draw vertices as spheres with constant size on screen
  if (_drawMode & POINTS_SPHERES_SCREEN)
  {
    // create sphere if not yet done
    if(!sphere_)
      sphere_ = new GLSphere(10,10);

    // precompute desired radius of projected sphere
Christopher Tenter's avatar
Christopher Tenter committed
332
    double r = 0.5*_state.point_size() / double(_state.viewport_height()) * 2.0 * tan(0.5*_state.fovy());
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361

    if( polyline_.vertex_selections_available())
    {
      for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
      {
        if(polyline_.vertex_selected(i))
          _state.set_color( Vec4f(1,0,0,1) );
        else
          _state.set_color( color );

        // compute radius in 3D
        const Vec3d p = (Vec3d)polyline_.point(i) - _state.eye();
        const double l = (p|_state.viewing_direction());
        sphere_->draw(_state, r*l, (Vec3f)polyline_.point(i));
      }
    }
    else
    {
      _state.set_color( color );
      for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
      {
        // compute radius in 3D
        const Vec3d p = (Vec3d)polyline_.point(i) - _state.eye();
        const double l = (p|_state.viewing_direction());
        sphere_->draw(_state, r*l, (Vec3f)polyline_.point(i));
      }

    }
  }
Jan Möbius's avatar
 
Jan Möbius committed
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
}

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


template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
pick(GLState& _state, PickTarget _target)
{
  if (  polyline_.n_vertices() == 0 ) 
    return;
  
  // Bind the vertex array
  ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
  ACG::GLState::vertexPointer( &(polyline_.points())[0] );   
  ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
  
  unsigned int n_end = polyline_.n_edges()+1;
  if( !polyline_.is_closed()) --n_end;
  
  // (draw lines slightly in front of everything else)
  //disabled right now because of rendering artifacts.
  //This probably doesn't make sense anyways since the lines are drawn as cylinders and therefore have a width
  // glDepthRange(0.0,0.99)
387

Jan Möbius's avatar
 
Jan Möbius committed
388 389 390 391 392
  switch (_target)
  {
    case PICK_VERTEX:
    {
      _state.pick_set_maximum (polyline_.n_vertices());
David Bommes's avatar
David Bommes committed
393 394 395 396 397 398 399 400 401
      if (drawMode() & DrawModes::POINTS)
          pick_vertices( _state);

      if (drawMode() & POINTS_SPHERES)
          pick_spheres( _state);

      if (drawMode() & POINTS_SPHERES_SCREEN)
          pick_spheres_screen( _state);

Jan Möbius's avatar
 
Jan Möbius committed
402 403 404 405 406 407 408 409 410 411 412 413 414
      break;
    }

    case PICK_EDGE:
    {
      _state.pick_set_maximum (n_end);
      pick_edges(_state, 0);
      break;
    }

    case PICK_ANYTHING:
    {
      _state.pick_set_maximum (polyline_.n_vertices() + n_end);
415 416 417

      if (drawMode() & DrawModes::POINTS)
          pick_vertices( _state);
418

419
      if (drawMode() & POINTS_SPHERES)
420 421
          pick_spheres( _state);

David Bommes's avatar
David Bommes committed
422 423 424
      if (drawMode() & POINTS_SPHERES_SCREEN)
          pick_spheres_screen( _state);

Jan Möbius's avatar
 
Jan Möbius committed
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
      pick_edges( _state, polyline_.n_vertices());
      break;
    }

    default:
      break;
  }
   
  //see above
  // glDepthRange(0.0,1.0)
  
  //Disable the vertex array
  ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
  
}


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


template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
pick_vertices( GLState& _state )
{
Christopher Tenter's avatar
Christopher Tenter committed
450 451 452
  if (!polyline_.n_vertices())
    return;

Jan Möbius's avatar
 
Jan Möbius committed
453 454 455
  float point_size_old = _state.point_size();
  glPointSize(18);

Christopher Tenter's avatar
Christopher Tenter committed
456
  glDepthRange(0.0, 0.999999);
Jan Möbius's avatar
 
Jan Möbius committed
457

Christopher Tenter's avatar
Christopher Tenter committed
458
  GLSL::Program* pickShader = ACG::ShaderCache::getInstance()->getProgram("Picking/pick_vertices_vs.glsl", "Picking/pick_vertices_fs.glsl", 0, false);
Jan Möbius's avatar
 
Jan Möbius committed
459

Christopher Tenter's avatar
Christopher Tenter committed
460 461
  if (pickShader && pickShader->isLinked())
  {
462 463 464 465
    // Update the vbo only if required.
    if (updateVBO_)
      updateVBO();

Christopher Tenter's avatar
Christopher Tenter committed
466
    // Bind the vertex array
467
    vbo_.bind();
Christopher Tenter's avatar
Christopher Tenter committed
468

469
    int pickOffsetIndex = int(_state.pick_current_index());
Christopher Tenter's avatar
Christopher Tenter committed
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485

    vertexDecl_.activateShaderPipeline(pickShader);

    pickShader->use();

    ACG::GLMatrixf transform = _state.projection() * _state.modelview();

    pickShader->setUniform("mWVP", transform);
    pickShader->setUniform("pickVertexOffset", pickOffsetIndex);

    glDrawArrays(GL_POINTS, 0, polyline_.n_vertices());

    vertexDecl_.deactivateShaderPipeline(pickShader);
    pickShader->disable();


486
    vbo_.unbind();
Christopher Tenter's avatar
Christopher Tenter committed
487 488 489 490 491 492 493 494 495
  }
  else
  {
    for (unsigned int i = 0; i < polyline_.n_vertices(); ++i) {
      _state.pick_set_name(i);
      glBegin(GL_POINTS);
      glArrayElement(i);
      glEnd();
    }
Jan Möbius's avatar
 
Jan Möbius committed
496
  }
Christopher Tenter's avatar
Christopher Tenter committed
497

Jan Möbius's avatar
 
Jan Möbius committed
498 499
  glDepthRange(0.0, 1.0);
  
Christopher Tenter's avatar
Christopher Tenter committed
500

Jan Möbius's avatar
 
Jan Möbius committed
501 502 503 504 505 506 507 508
  
  glPointSize(point_size_old);
}


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


509 510 511 512 513 514 515 516 517 518 519 520 521
template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
pick_spheres( GLState& _state )
{
  if(!sphere_)
    sphere_ = new GLSphere(10,10);

  _state.pick_set_name(0);

  for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
  {
    _state.pick_set_name (i);
Christopher Tenter's avatar
Christopher Tenter committed
522
    sphere_->draw(_state, _state.point_size(), (Vec3f)polyline_.point(i));
523 524 525
  }
}

David Bommes's avatar
David Bommes committed
526 527 528 529 530 531 532 533 534 535 536 537 538 539
//----------------------------------------------------------------------------


template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
pick_spheres_screen( GLState& _state )
{
  if(!sphere_)
    sphere_ = new GLSphere(10,10);

  _state.pick_set_name(0);

  // precompute desired radius of projected sphere
Christopher Tenter's avatar
Christopher Tenter committed
540
  double r = 0.5*_state.point_size()/double(_state.viewport_height())*2.0*tan(0.5*_state.fovy());
David Bommes's avatar
David Bommes committed
541 542 543 544 545 546 547 548 549 550 551 552 553 554

  for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
  {
    _state.pick_set_name (i);
    // compute radius in 3D
    const Vec3d p = (Vec3d)polyline_.point(i) - _state.eye();
    double l = (p|_state.viewing_direction());
    sphere_->draw(_state, r*l, (Vec3f)polyline_.point(i));

//    ToFix: _state does still not provide the near_plane in picking mode!!!
//    std::cerr << "radius in picking: " << r*l << std::endl;
  }
}

555 556 557 558

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


Jan Möbius's avatar
 
Jan Möbius committed
559 560 561 562 563 564 565 566 567
template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
pick_edges( GLState& _state, unsigned int _offset)
{
  // Check if we have any edges to draw ( % 0 causes division by zero on windows)
  if ( polyline_.n_edges() == 0 )
    return;
  
Christopher Tenter's avatar
Christopher Tenter committed
568
  glDepthRange(0.0, 0.999999);
Jan Möbius's avatar
 
Jan Möbius committed
569

Christopher Tenter's avatar
Christopher Tenter committed
570
  GLSL::Program* pickShader = ACG::ShaderCache::getInstance()->getProgram("Picking/vertex.glsl", "Picking/pick_vertices_fs2.glsl", 0, false);
Jan Möbius's avatar
 
Jan Möbius committed
571

Christopher Tenter's avatar
Christopher Tenter committed
572 573
  if (pickShader && pickShader->isLinked())
  {
574 575 576 577
    // Update the vbo only if required.
    if (updateVBO_)
      updateVBO();

Christopher Tenter's avatar
Christopher Tenter committed
578
    // Bind the vertex array
579
    vbo_.bind();
Jan Möbius's avatar
 
Jan Möbius committed
580

Christopher Tenter's avatar
Christopher Tenter committed
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
    int pickOffsetIndex = int(_state.pick_current_index());

    vertexDecl_.activateShaderPipeline(pickShader);

    pickShader->use();

    ACG::GLMatrixf transform = _state.projection() * _state.modelview();

    pickShader->setUniform("mWVP", transform);
    pickShader->setUniform("pickVertexOffset", pickOffsetIndex);

    int numIndices = polyline_.n_vertices() + (polyline_.is_closed() ? 1 : 0);
    glDrawArrays(GL_LINE_STRIP, 0, numIndices);

    vertexDecl_.deactivateShaderPipeline(pickShader);
    pickShader->disable();

598
    vbo_.unbind();
Jan Möbius's avatar
 
Jan Möbius committed
599
  }
Christopher Tenter's avatar
Christopher Tenter committed
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
  else
  {
    // save old values
    float line_width_old = _state.line_width();
    //  _state.set_line_width(2*line_width_old);
    _state.set_line_width(14);

    unsigned int n_end = polyline_.n_edges() + 1;
    if (!polyline_.is_closed()) --n_end;

    for (unsigned int i = 0; i < n_end; ++i) {
      _state.pick_set_name(i + _offset);
      glBegin(GL_LINES);
      glArrayElement(i     % polyline_.n_vertices());
      glArrayElement((i + 1) % polyline_.n_vertices());
      glEnd();
    }

    _state.set_line_width(line_width_old);
  }

Jan Möbius's avatar
 
Jan Möbius committed
621
  glDepthRange(0.0, 1.0);
Christopher Tenter's avatar
Christopher Tenter committed
622

Jan Möbius's avatar
 
Jan Möbius committed
623 624
}

625 626
//----------------------------------------------------------------------------

627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
template <class PolyLine>
void 
PolyLineNodeT<PolyLine>::
setupVertexDeclaration(VertexDeclaration* _dst, int _colorSource) const {
  // Update the vertex declaration based on the input data:
  _dst->clear();


  // We always output vertex positions
  _dst->addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_POSITION);

  // current byte offset
  size_t curOffset = 12;

  // Use the normals if available
  if (polyline_.vertex_normals_available())
  {
    _dst->addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_NORMAL, curOffset);
    curOffset += 12;
  }

  // colors
  if (polyline_.vertex_colors_available())
  {
    if (_colorSource == 1)
      _dst->addElement(GL_UNSIGNED_BYTE, 4, ACG::VERTEX_USAGE_COLOR, curOffset);
    curOffset += 4;
  }

  if (polyline_.edge_colors_available())
  {
    if (_colorSource == 2)
      _dst->addElement(GL_UNSIGNED_BYTE, 4, ACG::VERTEX_USAGE_COLOR, curOffset);
    curOffset += 4;
  }


  // Add custom vertex elements to declaration
  for (size_t i = 0; i < customBuffers_.size(); ++i) {
    ACG::VertexElement tmp = customBuffers_[i].first;
    tmp.pointer_ = 0;
    tmp.usage_ = ACG::VERTEX_USAGE_SHADER_INPUT;
    tmp.setByteOffset(curOffset);
    _dst->addElement(&tmp);

    curOffset += VertexDeclaration::getElementSize(&tmp);
  }

  _dst->setVertexStride(curOffset);
}

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

680
template <class PolyLine>
681
size_t
682
PolyLineNodeT<PolyLine>::
683
fillVertexBuffer(void *_buf, size_t _bufSize, bool _addLineStripEndVertex) {
684

685 686 687 688 689 690
  // register custom properties defined in polyline

  for (unsigned int i = 0; i < polyline_.get_num_custom_properties(); ++i) {

    typename PolyLine::CustomPropertyHandle proph = polyline_.enumerate_custom_property_handles(i);

691

692

693 694 695 696 697 698 699 700 701 702
    const void* propDataBuf = polyline_.get_custom_property_buffer(proph);

    typename std::map< typename PolyLine::CustomPropertyHandle, int >::iterator mapEntry = polylinePropMap_.find(proph);

    // insert newly defined properties
    if (mapEntry == polylinePropMap_.end()) {

      // setup element description
      ACG::VertexElement desc;

Christopher Tenter's avatar
Christopher Tenter committed
703
      unsigned int propSize = 0;
704 705 706 707
      if (polyline_.get_custom_property_shader_binding(proph, &propSize, &desc.shaderInputName_, &desc.type_)) {
        // assume aligned memory without byte padding
        desc.numElements_ = propSize / VertexDeclaration::getGLTypeSize(desc.type_);
        desc.pointer_ = 0;
708

709 710
        polylinePropMap_[proph] = addCustomBuffer(desc, propDataBuf);
      }
711 712 713 714 715 716
    }
    else // otherwise update pointer of property data buffer
      setCustomBuffer(mapEntry->second, propDataBuf);
  }


717 718 719 720
  // Update vertex declarations
  setupVertexDeclaration(&vertexDecl_, 0);
  setupVertexDeclaration(&vertexDeclVCol_, 1);
  setupVertexDeclaration(&vertexDeclECol_, 2);
721

722 723 724

  // fill buffer

725
  const unsigned int stride = vertexDecl_.getVertexStride();
726

727 728 729
  char* data = static_cast<char*>(_buf);
  size_t bytesWritten = 0;

Christopher Tenter's avatar
Christopher Tenter committed
730
  for (unsigned int  i = 0 ; i < polyline_.n_vertices() && bytesWritten + stride <= _bufSize; ++i) {
731 732 733 734
    writeVertex(i, data + i * stride);
    bytesWritten += stride;
  }

Christopher Tenter's avatar
Christopher Tenter committed
735
  if (_addLineStripEndVertex && bytesWritten + stride <= _bufSize) {
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
    // First point is added to the end for a closed loop
    writeVertex(0, data + polyline_.n_vertices() * stride);
    bytesWritten += stride;
  }

  return bytesWritten;
}

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

template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
updateVBO() {

  setupVertexDeclaration(&vertexDecl_, 0);

  const unsigned int stride = vertexDecl_.getVertexStride();
754

755
  // size in bytes of vbo,  create additional vertex for closed loop indexing
756
  size_t bufferSize = stride * (polyline_.n_vertices() + 1);
757

758
  // Create the required array
759 760 761 762 763 764 765 766 767 768
  std::vector<char> vboData(bufferSize);

  if (bufferSize > 0) {
    size_t bytesWritten = fillVertexBuffer(&vboData[0], bufferSize, true);

    if (bytesWritten != bufferSize)
      std::cerr << "PolyLineNode: fill vertex buffer only wrote " << bytesWritten << " bytes instead of expected " << bufferSize << " bytes" << std::endl;

    // Move data to the buffer in gpu memory
    vbo_.upload(bufferSize, &vboData[0], GL_STATIC_DRAW);
769
    vbo_.unbind();
770
  }
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797

  // Index buffer for selected vertices
  selectedVertexIndexBuffer_.clear();

  // Index buffer for selected vertices
  selectedEdgeIndexBuffer_.clear();

  for (unsigned int  i = 0 ; i < polyline_.n_vertices(); ++i) {

    // Create an ibo in system memory for vertex selection
    if ( polyline_.vertex_selections_available() && polyline_.vertex_selected(i) )
      selectedVertexIndexBuffer_.push_back(i);

    // Create an ibo in system memory for edge selection
    if ( polyline_.edge_selections_available() && polyline_.edge_selected(i) ) {
      selectedEdgeIndexBuffer_.push_back(i);
      selectedEdgeIndexBuffer_.push_back( (i + 1) % polyline_.n_vertices() );
    }

  }

  // Update done.
  updateVBO_ = false;
}

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

798 799 800 801 802 803 804 805 806 807
template <class PolyLine>
void 
PolyLineNodeT<PolyLine>::
writeVertexColor(unsigned int _vertex, bool _colorSourceVertex, void* _dst) const
{
  const VertexDeclaration* declToUse = _colorSourceVertex ? &vertexDeclVCol_ : &vertexDeclECol_;

  unsigned int byteOffset = declToUse->findElementByUsage(VERTEX_USAGE_COLOR)->getByteOffset();
  unsigned char* ucdata = ((unsigned char*)_dst) + byteOffset;

808 809 810 811 812 813 814 815 816 817
  Point col;
  if (_colorSourceVertex)
    col = polyline_.vertex_color(_vertex); // per vertex
  else
  {
    // edge colors
    // use the 2nd vertex of each edge as the provoking vertex
    int edgeID = (_vertex + polyline_.n_edges() - 1) % polyline_.n_edges();
    col = polyline_.edge_color(edgeID);
  }
818 819 820 821 822 823 824 825 826 827 828 829 830 831

  // rgb
  for (int i = 0; i < 3; ++i)
  {
    // convert to normalized ubyte
    int ival = int(col[i] * 255.0);
    ival = std::min(std::max(ival, 0), 255);
    ucdata[i] = ival;
  }
  ucdata[3] = 0xff; // alpha
}

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

832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
writeVertex(unsigned int _vertex, void* _dst) {

  // position and normal in float
  float* fdata = (float*)_dst;

  // Copy from internal storage to VBO in CPU memory
  for ( unsigned int j = 0 ; j < 3 ; ++j)
    *(fdata++) = polyline_.point(_vertex)[j];

  // Also write normal into buffer if available
  if ( polyline_.vertex_normals_available()  )
    for ( unsigned int j = 0 ; j < 3 ; ++j)
      *(fdata++) = polyline_.vertex_normal(_vertex)[j];

849 850
  if (polyline_.vertex_colors_available())
    writeVertexColor(_vertex, true, _dst);
851

852 853
  if (polyline_.edge_colors_available())
    writeVertexColor(_vertex, false, _dst);
854

855
  int customElementOffset = vertexDeclVCol_.findElementIdByUsage(VERTEX_USAGE_SHADER_INPUT);
856

857 858 859 860
  if (customElementOffset >= 0)
  {
    // copy custom data byte-wise
    for (unsigned int i = 0; i < customBuffers_.size(); ++i) {
861

862 863 864 865
      // element in custom input buffer
      const ACG::VertexElement* veInput = &customBuffers_[i].first;
      unsigned int elementInputStride = veInput->getByteOffset();
      unsigned int elementSize = ACG::VertexDeclaration::getElementSize(veInput);
866

867 868
      if (!elementInputStride)
        elementInputStride = elementSize;
869

870 871
      // element in vertex buffer
      const ACG::VertexElement* ve = vertexDeclVCol_.getElement(i + static_cast<unsigned int>(customElementOffset));
872

873 874 875 876 877
      const char* src = (const char*)customBuffers_[i].second;

      memcpy((char*)_dst + ve->getByteOffset(), src + elementInputStride * _vertex, elementSize);
    }
  }
878 879 880 881
}

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

882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
getRenderObjects(ACG::IRenderer* _renderer, ACG::GLState&  _state , const ACG::SceneGraph::DrawModes::DrawMode&  _drawMode , const ACG::SceneGraph::Material* _mat) {

  // Block if we do not have any vertices
  if ( polyline_.n_vertices() == 0 )
    return;

  // init base render object
  ACG::RenderObject ro;

  _state.enable(GL_COLOR_MATERIAL);
  _state.enable(GL_LIGHTING);
  ro.initFromState(&_state);

  ro.setMaterial(_mat);

  // draw after scene-meshes
  ro.priority = 1;

  // Update the vbo only if required.
  if ( updateVBO_ )
    updateVBO();

  // Set to the right vbo
908
  ro.vertexBuffer = vbo_.id();
909 910 911 912 913 914 915 916 917 918

  // Set style
  ro.debugName = "PolyLine";
  ro.blending = false;
  ro.depthTest = true;

  // Default color
  ACG::Vec4f defaultColor   = _state.ambient_color()  + _state.diffuse_color();
  ACG::Vec4f selectionColor = ACG::Vec4f(1.0,0.0,0.0,1.0);

919 920 921
  // Viewport size
  ACG::Vec2f screenSize(float(_state.viewport_width()), float(_state.viewport_height()));

922 923 924 925 926 927
  for (unsigned int i = 0; i < _drawMode.getNumLayers(); ++i) {
    ACG::SceneGraph::Material localMaterial = *_mat;

    const ACG::SceneGraph::DrawModes::DrawModeProperties* props = _drawMode.getLayer(i);

    ro.setupShaderGenFromDrawmode(props);
928
    ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
929
    ro.vertexDecl = &vertexDecl_;
930 931 932 933 934 935 936 937

    //---------------------------------------------------
    // No lighting!
    // Therefore we need some emissive color
    //---------------------------------------------------
    localMaterial.baseColor(defaultColor);
    ro.setMaterial(&localMaterial);

938
  
939 940 941 942 943 944 945 946
    switch (props->primitive()) {

      case ACG::SceneGraph::DrawModes::PRIMITIVE_POINT:

        // Render all vertices which are selected via an index buffer
        ro.debugName = "polyline.Points.selected";
        localMaterial.baseColor(selectionColor);
        ro.setMaterial(&localMaterial);
947 948

        // Point Size geometry shader
949
        ro.setupPointRendering(_mat->pointSize(), screenSize);
950 951 952
        
        // selection without colors
        ro.shaderDesc.vertexColors = false;
953

954 955 956
        if (!selectedVertexIndexBuffer_.empty())
        {
          ro.glDrawElements(GL_POINTS, selectedVertexIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedVertexIndexBuffer_[0]));
957 958 959
          // apply user settings
          applyRenderObjectSettings(props->primitive(), &ro);

960 961
          _renderer->addRenderObject(&ro);
        }
962

963
        // Render all vertices (ignore selection here!)
964 965 966 967
        ro.debugName = "polyline.Points";
        localMaterial.baseColor(defaultColor);
        ro.setMaterial(&localMaterial);
        ro.glDrawArrays(GL_POINTS, 0, polyline_.n_vertices());
968

969 970 971 972 973 974 975
        if (props->colored() && polyline_.vertex_colors_available())
        {
          ro.vertexDecl = &vertexDeclVCol_;
          ro.shaderDesc.vertexColors = true;
        }


976
        // Point Size geometry shader
977
        ro.setupPointRendering(_mat->pointSize(), screenSize);
978

979 980 981
        // apply user settings
        applyRenderObjectSettings(props->primitive(), &ro);

982 983 984
        _renderer->addRenderObject(&ro);

        break;
Christopher Tenter's avatar
Christopher Tenter committed
985

986
      case ACG::SceneGraph::DrawModes::PRIMITIVE_WIREFRAME:
987
      case ACG::SceneGraph::DrawModes::PRIMITIVE_EDGE:
988 989 990 991 992

        // Render all edges which are selected via an index buffer
        ro.debugName = "polyline.Wireframe.selected";
        localMaterial.baseColor(selectionColor);
        ro.setMaterial(&localMaterial);
993 994

        // Line Width geometry shader
995
        ro.setupLineRendering(_state.line_width(), screenSize);
996

997 998 999
        // selection without colors
        ro.shaderDesc.vertexColors = false;

1000 1001 1002
        if (!selectedEdgeIndexBuffer_.empty())
        {
          ro.glDrawElements(GL_LINES, selectedEdgeIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedEdgeIndexBuffer_[0]));
1003 1004 1005 1006

          // apply user settings
          applyRenderObjectSettings(props->primitive(), &ro);

1007 1008
          _renderer->addRenderObject(&ro);
        }
1009 1010 1011 1012 1013 1014 1015

        ro.debugName = "polyline.Wireframe";
        localMaterial.baseColor(defaultColor);
        ro.setMaterial(&localMaterial);
        // The first point is mapped to an additional last point in buffer, so we can
        // just Render one point more to get a closed line
        if ( polyline_.is_closed() )
1016
          ro.glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices() + 1);
1017
        else
1018
          ro.glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices());
1019

1020 1021 1022 1023 1024 1025
        if (props->colored() && polyline_.edge_colors_available())
        {
          ro.vertexDecl = &vertexDeclECol_;
          ro.shaderDesc.vertexColors = true;
        }

1026
        // Line Width geometry shader
1027
        ro.setupLineRendering(_state.line_width(), screenSize);
1028 1029 1030 1031

        // apply user settings
        applyRenderObjectSettings(props->primitive(), &ro);

1032 1033 1034
        _renderer->addRenderObject(&ro);

        break;
Christopher Tenter's avatar
Christopher Tenter committed
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056


      case ACG::SceneGraph::DrawModes::PRIMITIVE_POLYGON:
        {
          // create sphere object for each vertex
          // potential optimization: create only one render object and use instancing 

          // use world space radius or screen space point size?
          bool screenScale = _drawMode & POINTS_SPHERES_SCREEN;

          // clear shaders used by thick line / point drawing
          ro.shaderDesc.vertexTemplateFile.clear();
          ro.shaderDesc.geometryTemplateFile.clear();
          ro.shaderDesc.fragmentTemplateFile.clear();

          // create sphere if not yet done
          if (!sphere_)
            sphere_ = new GLSphere(10, 10);

          // precompute desired radius of projected sphere
          double r = 1.0;
          if (screenScale)
Christopher Tenter's avatar
Christopher Tenter committed
1057
            r = 0.5*_state.point_size() / double(_state.viewport_height())*2.0*tan(0.5*_state.fovy());
Christopher Tenter's avatar
Christopher Tenter committed
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073

          // get eye position and view direction in world space
          Vec3d eyePos = _state.eye();
          Vec3d viewDir = _state.viewing_direction();

          // render-objects for the selected points with selection color
          if (polyline_.vertex_selections_available())
          {
            ro.debugName = "polyline.Sphere.selected";
            localMaterial.baseColor(selectionColor);
            ro.setMaterial(&localMaterial);

            for (unsigned int i = 0; i < polyline_.n_vertices(); ++i)
            {
              if (polyline_.vertex_selected(i))
              {
1074
                double radius = _state.point_size();
Christopher Tenter's avatar
Christopher Tenter committed
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
                if (screenScale)
                {
                  // compute radius in 3D
                  const Vec3d p = (Vec3d)polyline_.point(i) - eyePos;
                  radius = (p | viewDir) * r;
                }

                sphere_->addToRenderer(_renderer, &ro, radius, (Vec3f)polyline_.point(i));
              }
            }
          }

          // unselected points with default color
          ro.debugName = "polyline.Sphere";
          localMaterial.baseColor(defaultColor);
          ro.setMaterial(&localMaterial);

          for (unsigned int i = 0; i < polyline_.n_vertices(); ++i)
          {
            if (!polyline_.vertex_selections_available() || !polyline_.vertex_selected(i))
            {
1096
              double radius = _state.point_size();
Christopher Tenter's avatar
Christopher Tenter committed
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
              if (screenScale)
              {
                // compute radius in 3D
                const Vec3d p = (Vec3d)polyline_.point(i) - eyePos;
                radius = (p | viewDir) * r;
              }

              sphere_->addToRenderer(_renderer, &ro, radius, (Vec3f)polyline_.point(i));
            }
          }
        } break;


1110 1111 1112 1113 1114 1115 1116
      default:
        break;
    }

  }

}
Jan Möbius's avatar
 
Jan Möbius committed
1117

1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
//----------------------------------------------------------------------------

template <class PolyLine>
int
PolyLineNodeT<PolyLine>::
addCustomBuffer( const ACG::VertexElement& _desc, const void* _buffer) {

  if (_buffer) {
    customBuffers_.push_back( std::pair<ACG::VertexElement, const void*>(_desc, _buffer) );
    update();

    return int(customBuffers_.size()-1);
  }
  else
  {
    std::cerr << "PolyLineNodeT::addCustomBuffer - null pointer buffer" << std::endl;
    return -1;
  }
}

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

template <class PolyLine>
void
PolyLineNodeT<PolyLine>::
setCustomBuffer( int _id, const void* _buffer) {

  customBuffers_[_id].second = _buffer;
  update();
}
Jan Möbius's avatar
 
Jan Möbius committed
1148 1149 1150 1151 1152

//=============================================================================
} // namespace SceneGraph
} // namespace ACG
//=============================================================================