Visualization Library 2.1.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
Extrusions.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
34 #include <vlCore/glsl_math.hpp>
35 
36 using namespace vl;
37 
38 ref<Geometry> Extrusions::extrude( bool compatibilityProfile )
39 {
40  if ( silhouette().empty() || silhouettes().empty() )
41  {
42  Log::error( "Extrusion::extrude(): no silhouette defined.\n" );
43  return NULL;
44  }
45  if ( positionPath().empty() )
46  {
47  Log::error( "Extrusion::extrude() needs at least a non empty positionPath().\n" );
48  return NULL;
49  }
50  if ( !scalingPath().empty() && scalingPath().size() != positionPath().size() - 2 )
51  {
52  Log::error( "Extrusion::extrude(): scalingPath() must have the same number of control points as positionPath().\n" );
53  return NULL;
54  }
55  if ( !rotationPath().empty() && rotationPath().size() != positionPath().size() - 2 )
56  {
57  Log::error( "Extrusion::extrude(): rotationPath() must have the same number of control points as positionPath().\n" );
58  return NULL;
59  }
60  if ( !colorPath().empty() && colorPath().size() != positionPath().size() - 2 )
61  {
62  Log::error( "Extrusion::extrude(): colorPath() must have the same number of control points as positionPath().\n" );
63  return NULL;
64  }
65 
66  ref<Geometry> geom = new Geometry;
67 
68  int segments = int( positionPath().size() - 2 );
69 
70  std::vector<fvec3> verts;
71  verts.resize( silhouette().size() * segments );
72 
73  vl::fmat4 m = fmat4::getRotation( fvec3( 0, 1, 0 ), positionPath()[ 1 ] - positionPath()[ 0 ] );
74 
75  // initialize silhouette on the x/z plane
76  std::vector<vl::fvec3> projected_sil;
77  projected_sil.resize( silhouette().size() );
78  for ( unsigned i = 0; i < silhouette().size(); ++i )
79  {
80  projected_sil[ i ] = m * vl::fvec3( silhouette()[ i ].x(), 0, silhouette()[ i ].y() ) + positionPath()[ 0 ];
81  }
82 
83  // initialize plane normals from 1 to n-1 (end points are excluded)
84  std::vector<fvec3> plane_normals;
85  plane_normals.resize( positionPath().size() );
86  for ( unsigned i = 1; i < plane_normals.size() - 1; ++i )
87  {
88  fvec3 p0 = positionPath()[ i - 1 ] - positionPath()[ i ];
89  fvec3 p1 = positionPath()[ i + 1 ] - positionPath()[ i ];
90  p0.normalize();
91  p1.normalize();
92  plane_normals[ i ] = ( p1 - p0 ).normalize();
93  }
94 
95  for ( unsigned i = 1; i < positionPath().size() - 1; ++i )
96  {
97  for ( int j = 0; j < (int)silhouette().size(); ++j )
98  {
99  fvec3 V = ( positionPath()[ i ] - positionPath()[ i - 1 ] ).normalize();
100  const fvec3& P = projected_sil[ j ];
101  const fvec3& orig = positionPath()[ i ];
102  const fvec3& N = plane_normals[ i ];
103  float d = dot( N, orig );
104  float t = dot( V, N ) ? ( d - dot( P, N ) ) / dot( V, N ) : 0 /*error*/;
105  // project current projected_sil on next plane along p0->p1 vector
106  verts.at( j + silhouette().size() * ( i - 1 ) ) = projected_sil[ j ] = P + V * t;
107  }
108  }
109 
110  // rotation
111  if ( !rotationPath().empty() )
112  {
113  for ( unsigned i = 1; i < positionPath().size() - 1; ++i )
114  {
115  fvec3 r = ( positionPath()[ i + 1 ] - positionPath()[ i ] ).normalize();
116  fmat4 mat = vl::fmat4::getRotation( rotationPath()[ i - 1 ], r );
117  fvec3 c;
118  for ( int j = 0; j < (int)silhouette().size(); ++j )
119  c += verts.at( j + silhouette().size() * ( i - 1 ) );
120  c /= (float)silhouette().size();
121  for ( int j = 0; j < (int)silhouette().size(); ++j )
122  verts.at( j + silhouette().size() * ( i - 1 ) ) = ( mat * ( verts.at( j + silhouette().size() * ( i - 1 ) ) - c ) ) + c;
123  }
124  }
125 
126  // scaling
127  if ( !scalingPath().empty() )
128  {
129  for ( unsigned i = 1; i < positionPath().size() - 1; ++i )
130  {
131  float s = scalingPath()[ i - 1 ];
132  fvec3 c;
133  for ( int j = 0; j < (int)silhouette().size(); ++j )
134  c += verts.at( j + silhouette().size() * ( i - 1 ) );
135  c /= (float)silhouette().size();
136  for ( int j = 0; j < (int)silhouette().size(); ++j )
137  verts.at( j + silhouette().size() * ( i - 1 ) ) = ( s * ( verts.at( j + silhouette().size() * ( i - 1 ) ) - c ) ) + c;
138  }
139  }
140 
141  for ( unsigned int i = 0; i < silhouettes().size(); ++i )
142  {
143  int previousSilhouetteSize = ( i == 0 ) ? 0 : silhouettes().at( i - 1 );
144  int prof_count = silhouetteMode() == SilhouetteClosed ? (int)silhouettes().at( i ) : (int)silhouettes().at( i ) - 1;
146  geom->drawCalls().push_back( de.get() );
147  de->indexBuffer()->resize( 4 * prof_count * ( segments - 1 ) );
148  for ( int iseg = 0; iseg < segments - 1; ++iseg )
149  {
150  for ( int iquad = 0; iquad < prof_count; ++iquad )
151  {
152  de->indexBuffer()->at( ( iquad ) * 4 + iseg * 4 * prof_count + 3 ) = ( iseg + 0 ) * (GLuint)silhouette().size() + iquad + previousSilhouetteSize;
153  de->indexBuffer()->at( ( iquad ) * 4 + iseg * 4 * prof_count + 2 ) = ( iseg + 0 ) * (GLuint)silhouette().size() + ( iquad + 1 ) % silhouettes().at( i ) + previousSilhouetteSize; // % is used for loop
154  de->indexBuffer()->at( ( iquad ) * 4 + iseg * 4 * prof_count + 1 ) = ( iseg + 1 ) * (GLuint)silhouette().size() + ( iquad + 1 ) % silhouettes().at( i ) + previousSilhouetteSize; // % is used for loop
155  de->indexBuffer()->at( ( iquad ) * 4 + iseg * 4 * prof_count + 0 ) = ( iseg + 1 ) * (GLuint)silhouette().size() + iquad + previousSilhouetteSize;
156  }
157  }
158  }
159 
160  // bottom/top caps
161 
162  size_t tess_bottom_count = 0;
163  size_t tess_top_count = 0;
164 
165  if ( fillBottom() )
166  {
167  int start = int( verts.size() );
168  Tessellator tessellator;
169  for ( unsigned i = 0; i < silhouettes().size(); ++i )
170  tessellator.contours().push_back( silhouettes().at( i ) );
171  for ( unsigned i = 0; i < silhouette().size(); ++i )
172  tessellator.contourVerts().push_back( (dvec3)verts[ i ] );
173  tessellator.setWindingRule( vl::TW_TESS_WINDING_NONZERO );
174  tessellator.tessellate();
175  for ( unsigned i = 0; i < tessellator.tessellatedTris().size(); ++i )
176  verts.push_back( tessellator.tessellatedTris()[ i ] );
177  if ( tessellator.tessellatedTris().size() )
178  geom->drawCalls().push_back( new DrawArrays( PT_TRIANGLES, start, (int)tessellator.tessellatedTris().size() ) );
179  tess_bottom_count = tessellator.tessellatedTris().size();
180  }
181  if ( fillTop() )
182  {
183  int start = int( verts.size() );
184  Tessellator tessellator;
185  for ( size_t i = silhouettes().size() - 1; i >= 0; --i )
186  tessellator.contours().push_back( silhouettes().at( i ) );
187  for ( unsigned i = 0; i < silhouette().size(); ++i )
188  tessellator.contourVerts().push_back( (dvec3)verts[ verts.size() - i - 1 - tess_bottom_count ] );
189  tessellator.setWindingRule( vl::TW_TESS_WINDING_ODD );
190  tessellator.tessellate();
191  for ( unsigned i = 0; i < tessellator.tessellatedTris().size(); ++i )
192  verts.push_back( tessellator.tessellatedTris()[ i ] );
193  if ( tessellator.tessellatedTris().size() )
194  geom->drawCalls().push_back( new DrawArrays( PT_TRIANGLES, start, (int)tessellator.tessellatedTris().size() ) );
195  tess_top_count = tessellator.tessellatedTris().size();
196  }
197 
198  ref<ArrayFloat3> vert_array = new ArrayFloat3;
199  if ( compatibilityProfile )
200  geom->setVertexArray( vert_array.get() );
201  else
202  geom->setVertexAttribArray( VA_Position, vert_array.get() );
203  vert_array->initFrom( verts );
204 
205  if ( !colorPath().empty() )
206  {
207  ref<ArrayFloat4> col_array = new ArrayFloat4;
208  if ( compatibilityProfile )
209  geom->setColorArray( col_array.get() );
210  else
211  geom->setVertexAttribArray( VA_Color, col_array.get() );
212  col_array->resize( geom->vertexArray()->size() );
213  int offs = 0;
214  for ( int iseg = 0; iseg < segments; ++iseg )
215  {
216  for ( unsigned j = 0; j < silhouette().size(); ++j, ++offs )
217  col_array->at( offs ) = colorPath()[ iseg ];
218  }
219  if ( fillBottom() )
220  {
221  for ( unsigned j = 0; j < tess_bottom_count; ++j, ++offs )
222  col_array->at( offs ) = colorPath()[ 0 ];
223  }
224  if ( fillTop() )
225  {
226  for ( unsigned j = 0; j < tess_top_count; ++j, ++offs )
227  col_array->at( offs ) = colorPath().back();
228  }
229  }
230 
231  if ( !smooth() )
233 
234  geom->computeNormals();
235 
236  return geom;
237 }
238 
const std::vector< vl::fvec3 > & positionPath() const
The path along which the silhouette is extruded.
Definition: Extrusions.hpp:109
const std::vector< float > & scalingPath() const
The scaling to be applied along the extrusion.
Definition: Extrusions.hpp:116
Tessellates a complex polygon defined by a set of outlines into a set of triangles that can be render...
Definition: Tessellator.hpp:50
const Vector3 & normalize(T_Scalar *len=NULL)
Definition: Vector3.hpp:228
An array of vl::fvec4.
Definition: Array.hpp:416
Vector3< float > fvec3
A 3 components vector with float precision.
Definition: Vector3.hpp:253
bool fillBottom() const
Whether a set of triangles should be generated to fill the beginning of the extrusion (default is tru...
Definition: Extrusions.hpp:100
const T * get() const
Definition: Object.hpp:128
bool smooth() const
If true the normals of the geometry are smoothed.
Definition: Extrusions.hpp:95
const ArrayAbstract * vertexArray() const
Conventional vertex array.
Definition: Geometry.hpp:248
const std::vector< vl::fvec4 > & colorPath() const
The color to be applied to the extrusion.
Definition: Extrusions.hpp:132
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
void setVertexArray(ArrayAbstract *data)
Conventional vertex array.
Definition: Geometry.cpp:155
void resize(size_t dim)
Definition: Array.hpp:233
void setColorArray(const fvec4 &color)
Fills the color array with the given color.
Definition: Geometry.hpp:108
The Geometry class is a Renderable that implements a polygonal mesh made of polygons, lines and points.
Definition: Geometry.hpp:66
Visualization Library main namespace.
float dot(float a, float b)
Definition: glsl_math.hpp:1111
const std::vector< vl::fvec2 > & silhouette() const
Returns the silhouette to be extruded.
Definition: Extrusions.hpp:83
void initFrom(const std::vector< T_VectorType > &vector)
Definition: Array.hpp:395
vl::ref< vl::Geometry > extrude(bool compatibilityProfile=true)
Performs the actual extrusion.
Definition: Extrusions.cpp:38
See DrawElements.
ESilhouetteMode silhouetteMode() const
Wether the silhouette is considered closed, i.e. a line-loop, or open.
Definition: Extrusions.hpp:90
Implements the OpenGL Shading Language convenience functions for scalar and vector operations...
const std::vector< int > & contours() const
The contours that specify the complex polygon to be tessellated.
Definition: Tessellator.hpp:70
void convertDrawCallToDrawArrays()
Converts all the DrawCall objects bound to a Geometry into DrawArrays.
Definition: Geometry.cpp:766
void computeNormals(bool verbose=false)
Computes the normals in a "smooth" way, i.e.
Definition: Geometry.cpp:269
#define NULL
Definition: OpenGLDefs.hpp:81
arr_type * indexBuffer()
The BufferObject containing the indices used to render.
const std::vector< unsigned int > & silhouettes() const
Return the number of points in each silhouette.
Definition: Extrusions.hpp:76
static Matrix4 & getRotation(Matrix4 &out, float degrees, float x, float y, float z)
Definition: Matrix4.hpp:909
T_VectorType & at(size_t i)
Definition: Array.hpp:255
virtual size_t size() const =0
Returns the number of elements of an array.
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
An array of vl::fvec3.
Definition: Array.hpp:414
bool fillTop() const
Whether a set of triangles should be generated to fill the ending of the extrusion (default is true)...
Definition: Extrusions.hpp:105
Wraps the OpenGL function glDrawArrays().
Definition: DrawArrays.hpp:57
const std::vector< float > & rotationPath() const
The rotation to be applied along the extrusion.
Definition: Extrusions.hpp:124
T normalize(T)
Definition: glsl_math.hpp:1128
Collection< DrawCall > & drawCalls()
Returns the list of DrawCall objects bound to a Geometry.
Definition: Geometry.hpp:102
void setVertexAttribArray(int attrib_location, const ArrayAbstract *info)
Binds a generic vertex attribute.
Definition: Geometry.cpp:415