|
@@ -0,0 +1,517 @@
|
|
|
|
+/*
|
|
|
|
+Open Asset Import Library (assimp)
|
|
|
|
+----------------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+Copyright (c) 2006-2013, assimp team
|
|
|
|
+All rights reserved.
|
|
|
|
+
|
|
|
|
+Redistribution and use of this software in source and binary forms,
|
|
|
|
+with or without modification, are permitted provided that the
|
|
|
|
+following conditions are met:
|
|
|
|
+
|
|
|
|
+* Redistributions of source code must retain the above
|
|
|
|
+ copyright notice, this list of conditions and the
|
|
|
|
+ following disclaimer.
|
|
|
|
+
|
|
|
|
+* 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.
|
|
|
|
+
|
|
|
|
+* Neither the name of the assimp team, nor the names of its
|
|
|
|
+ contributors may be used to endorse or promote products
|
|
|
|
+ derived from this software without specific prior
|
|
|
|
+ written permission of the assimp team.
|
|
|
|
+
|
|
|
|
+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
|
|
|
|
+OWNER 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.
|
|
|
|
+
|
|
|
|
+----------------------------------------------------------------------
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+/** @file BlenderTessellator.cpp
|
|
|
|
+ * @brief A simple tessellation wrapper
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+#include "AssimpPCH.h"
|
|
|
|
+
|
|
|
|
+#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
|
|
|
+
|
|
|
|
+#include "BlenderDNA.h"
|
|
|
|
+#include "BlenderScene.h"
|
|
|
|
+#include "BlenderBMesh.h"
|
|
|
|
+#include "BlenderTessellator.h"
|
|
|
|
+
|
|
|
|
+#define BLEND_TESS_MAGIC ( 0x83ed9ac3 )
|
|
|
|
+
|
|
|
|
+#if ASSIMP_BLEND_WITH_GLU_TESSELLATE
|
|
|
|
+
|
|
|
|
+namespace Assimp
|
|
|
|
+{
|
|
|
|
+ template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+using namespace Assimp;
|
|
|
|
+using namespace Assimp::Blender;
|
|
|
|
+
|
|
|
|
+#ifndef CALLBACK
|
|
|
|
+#define CALLBACK
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+BlenderTessellatorGL::BlenderTessellatorGL( BlenderBMeshConverter& converter ):
|
|
|
|
+ converter( &converter )
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+BlenderTessellatorGL::~BlenderTessellatorGL( )
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
|
|
|
|
+{
|
|
|
|
+ AssertVertexCount( vertexCount );
|
|
|
|
+
|
|
|
|
+ std::vector< VertexGL > polyLoopGL;
|
|
|
|
+ GenerateLoopVerts( polyLoopGL, polyLoop, vertexCount, vertices );
|
|
|
|
+
|
|
|
|
+ TessDataGL tessData;
|
|
|
|
+ Tesssellate( polyLoopGL, tessData );
|
|
|
|
+
|
|
|
|
+ TriangulateDrawCalls( tessData );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::AssertVertexCount( int vertexCount )
|
|
|
|
+{
|
|
|
|
+ if ( vertexCount <= 4 )
|
|
|
|
+ {
|
|
|
|
+ ThrowException( "Expected more than 4 vertices for tessellation" );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::GenerateLoopVerts( std::vector< VertexGL >& polyLoopGL, const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
|
|
|
|
+{
|
|
|
|
+ for ( int i = 0; i < vertexCount; ++i )
|
|
|
|
+ {
|
|
|
|
+ const MLoop& loopItem = polyLoop[ i ];
|
|
|
|
+ const MVert& vertex = vertices[ loopItem.v ];
|
|
|
|
+ polyLoopGL.push_back( VertexGL( vertex.co[ 0 ], vertex.co[ 1 ], vertex.co[ 2 ], loopItem.v, BLEND_TESS_MAGIC ) );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::Tesssellate( std::vector< VertexGL >& polyLoopGL, TessDataGL& tessData )
|
|
|
|
+{
|
|
|
|
+ GLUtesselator* tessellator = gluNewTess( );
|
|
|
|
+ gluTessCallback( tessellator, GLU_TESS_BEGIN_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateBegin ) );
|
|
|
|
+ gluTessCallback( tessellator, GLU_TESS_END_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEnd ) );
|
|
|
|
+ gluTessCallback( tessellator, GLU_TESS_VERTEX_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateVertex ) );
|
|
|
|
+ gluTessCallback( tessellator, GLU_TESS_COMBINE_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateCombine ) );
|
|
|
|
+ gluTessCallback( tessellator, GLU_TESS_EDGE_FLAG_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEdgeFlag ) );
|
|
|
|
+ gluTessCallback( tessellator, GLU_TESS_ERROR_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateError ) );
|
|
|
|
+ gluTessProperty( tessellator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO );
|
|
|
|
+
|
|
|
|
+ gluTessBeginPolygon( tessellator, &tessData );
|
|
|
|
+ gluTessBeginContour( tessellator );
|
|
|
|
+
|
|
|
|
+ for ( unsigned int i = 0; i < polyLoopGL.size( ); ++i )
|
|
|
|
+ {
|
|
|
|
+ gluTessVertex( tessellator, reinterpret_cast< GLdouble* >( &polyLoopGL[ i ] ), &polyLoopGL[ i ] );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ gluTessEndContour( tessellator );
|
|
|
|
+ gluTessEndPolygon( tessellator );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::TriangulateDrawCalls( const TessDataGL& tessData )
|
|
|
|
+{
|
|
|
|
+ // NOTE - Because we are supplying a callback to GLU_TESS_EDGE_FLAG_DATA we don't technically
|
|
|
|
+ // need support for GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN but we'll keep it here in case
|
|
|
|
+ // GLU tessellate changes or tristrips and fans are wanted.
|
|
|
|
+ // See: http://www.opengl.org/sdk/docs/man2/xhtml/gluTessCallback.xml
|
|
|
|
+ for ( unsigned int i = 0; i < tessData.drawCalls.size( ); ++i )
|
|
|
|
+ {
|
|
|
|
+ const DrawCallGL& drawCallGL = tessData.drawCalls[ i ];
|
|
|
|
+ const VertexGL* vertices = &tessData.vertices[ drawCallGL.baseVertex ];
|
|
|
|
+ if ( drawCallGL.drawMode == GL_TRIANGLES )
|
|
|
|
+ {
|
|
|
|
+ MakeFacesFromTris( vertices, drawCallGL.vertexCount );
|
|
|
|
+ }
|
|
|
|
+ else if ( drawCallGL.drawMode == GL_TRIANGLE_STRIP )
|
|
|
|
+ {
|
|
|
|
+ MakeFacesFromTriStrip( vertices, drawCallGL.vertexCount );
|
|
|
|
+ }
|
|
|
|
+ else if ( drawCallGL.drawMode == GL_TRIANGLE_FAN )
|
|
|
|
+ {
|
|
|
|
+ MakeFacesFromTriFan( vertices, drawCallGL.vertexCount );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::MakeFacesFromTris( const VertexGL* vertices, int vertexCount )
|
|
|
|
+{
|
|
|
|
+ int triangleCount = vertexCount / 3;
|
|
|
|
+ for ( int i = 0; i < triangleCount; ++i )
|
|
|
|
+ {
|
|
|
|
+ int vertexBase = i * 3;
|
|
|
|
+ converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::MakeFacesFromTriStrip( const VertexGL* vertices, int vertexCount )
|
|
|
|
+{
|
|
|
|
+ int triangleCount = vertexCount - 2;
|
|
|
|
+ for ( int i = 0; i < triangleCount; ++i )
|
|
|
|
+ {
|
|
|
|
+ int vertexBase = i;
|
|
|
|
+ converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::MakeFacesFromTriFan( const VertexGL* vertices, int vertexCount )
|
|
|
|
+{
|
|
|
|
+ int triangleCount = vertexCount - 2;
|
|
|
|
+ for ( int i = 0; i < triangleCount; ++i )
|
|
|
|
+ {
|
|
|
|
+ int vertexBase = i;
|
|
|
|
+ converter->AddFace( vertices[ 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::TessellateBegin( GLenum drawModeGL, void* userData )
|
|
|
|
+{
|
|
|
|
+ TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
|
|
|
|
+ tessData.drawCalls.push_back( DrawCallGL( drawModeGL, tessData.vertices.size( ) ) );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::TessellateEnd( void* )
|
|
|
|
+{
|
|
|
|
+ // Do nothing
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::TessellateVertex( const void* vtxData, void* userData )
|
|
|
|
+{
|
|
|
|
+ TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
|
|
|
|
+
|
|
|
|
+ const VertexGL& vertex = *reinterpret_cast< const VertexGL* >( vtxData );
|
|
|
|
+ if ( vertex.magic != BLEND_TESS_MAGIC )
|
|
|
|
+ {
|
|
|
|
+ ThrowException( "Point returned by GLU Tessellate was probably not one of ours. This indicates we need a new way to store vertex information" );
|
|
|
|
+ }
|
|
|
|
+ tessData.vertices.push_back( vertex );
|
|
|
|
+ if ( tessData.drawCalls.size( ) == 0 )
|
|
|
|
+ {
|
|
|
|
+ ThrowException( "\"Vertex\" callback received before \"Begin\"" );
|
|
|
|
+ }
|
|
|
|
+ ++( tessData.drawCalls.back( ).vertexCount );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData )
|
|
|
|
+{
|
|
|
|
+ ThrowException( "Intersected polygon loops are not yet supported" );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::TessellateEdgeFlag( GLboolean, void* )
|
|
|
|
+{
|
|
|
|
+ // Do nothing
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* )
|
|
|
|
+{
|
|
|
|
+ ThrowException( reinterpret_cast< const char* >( gluErrorString( errorCode ) ) );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE
|
|
|
|
+
|
|
|
|
+#if ASSIMP_BLEND_WITH_POLY_2_TRI
|
|
|
|
+
|
|
|
|
+namespace Assimp
|
|
|
|
+{
|
|
|
|
+ template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: ";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+using namespace Assimp;
|
|
|
|
+using namespace Assimp::Blender;
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+BlenderTessellatorP2T::BlenderTessellatorP2T( BlenderBMeshConverter& converter ):
|
|
|
|
+ converter( &converter )
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+BlenderTessellatorP2T::~BlenderTessellatorP2T( )
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorP2T::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
|
|
|
|
+{
|
|
|
|
+ AssertVertexCount( vertexCount );
|
|
|
|
+
|
|
|
|
+ // NOTE - We have to hope that points in a Blender polygon are roughly on the same plane.
|
|
|
|
+ // There may be some triangulation artifacts if they are wildly different.
|
|
|
|
+
|
|
|
|
+ std::vector< PointP2T > points;
|
|
|
|
+ Copy3DVertices( polyLoop, vertexCount, vertices, points );
|
|
|
|
+
|
|
|
|
+ PlaneP2T plane = FindLLSQPlane( points );
|
|
|
|
+
|
|
|
|
+ aiMatrix4x4 transform = GeneratePointTransformMatrix( plane );
|
|
|
|
+
|
|
|
|
+ TransformAndFlattenVectices( transform, points );
|
|
|
|
+
|
|
|
|
+ std::vector< p2t::Point* > pointRefs;
|
|
|
|
+ ReferencePoints( points, pointRefs );
|
|
|
|
+
|
|
|
|
+ p2t::CDT cdt( pointRefs );
|
|
|
|
+
|
|
|
|
+ cdt.Triangulate( );
|
|
|
|
+ std::vector< p2t::Triangle* > triangles = cdt.GetTriangles( );
|
|
|
|
+
|
|
|
|
+ MakeFacesFromTriangles( triangles );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorP2T::AssertVertexCount( int vertexCount )
|
|
|
|
+{
|
|
|
|
+ if ( vertexCount <= 4 )
|
|
|
|
+ {
|
|
|
|
+ ThrowException( "Expected more than 4 vertices for tessellation" );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorP2T::Copy3DVertices( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices, std::vector< PointP2T >& points ) const
|
|
|
|
+{
|
|
|
|
+ points.resize( vertexCount );
|
|
|
|
+ for ( int i = 0; i < vertexCount; ++i )
|
|
|
|
+ {
|
|
|
|
+ const MLoop& loop = polyLoop[ i ];
|
|
|
|
+ const MVert& vert = vertices[ loop.v ];
|
|
|
|
+
|
|
|
|
+ PointP2T& point = points[ i ];
|
|
|
|
+ point.point3D.Set( vert.co[ 0 ], vert.co[ 1 ], vert.co[ 2 ] );
|
|
|
|
+ point.index = loop.v;
|
|
|
|
+ point.magic = BLEND_TESS_MAGIC;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+aiMatrix4x4 BlenderTessellatorP2T::GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const
|
|
|
|
+{
|
|
|
|
+ aiVector3D sideA( 1.0f, 0.0f, 0.0f );
|
|
|
|
+ if ( fabs( plane.normal * sideA ) > 0.999f )
|
|
|
|
+ {
|
|
|
|
+ sideA = aiVector3D( 0.0f, 1.0f, 0.0f );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ aiVector3D sideB( plane.normal ^ sideA );
|
|
|
|
+ sideB.Normalize( );
|
|
|
|
+ sideA = sideB ^ plane.normal;
|
|
|
|
+
|
|
|
|
+ aiMatrix4x4 result;
|
|
|
|
+ result.a1 = sideA.x;
|
|
|
|
+ result.a2 = sideA.y;
|
|
|
|
+ result.a3 = sideA.z;
|
|
|
|
+ result.b1 = sideB.x;
|
|
|
|
+ result.b2 = sideB.y;
|
|
|
|
+ result.b3 = sideB.z;
|
|
|
|
+ result.c1 = plane.normal.x;
|
|
|
|
+ result.c2 = plane.normal.y;
|
|
|
|
+ result.c3 = plane.normal.z;
|
|
|
|
+ result.a4 = plane.centre.x;
|
|
|
|
+ result.b4 = plane.centre.y;
|
|
|
|
+ result.c4 = plane.centre.z;
|
|
|
|
+ result.Inverse( );
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorP2T::TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const
|
|
|
|
+{
|
|
|
|
+ for ( unsigned int i = 0; i < vertices.size( ); ++i )
|
|
|
|
+ {
|
|
|
|
+ PointP2T& point = vertices[ i ];
|
|
|
|
+ point.point3D = transform * point.point3D;
|
|
|
|
+ point.point2D.set( point.point3D.y, point.point3D.z );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorP2T::ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const
|
|
|
|
+{
|
|
|
|
+ pointRefs.resize( points.size( ) );
|
|
|
|
+ for ( unsigned int i = 0; i < points.size( ); ++i )
|
|
|
|
+ {
|
|
|
|
+ pointRefs[ i ] = &points[ i ].point2D;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Yes this is filthy... but we have no choice
|
|
|
|
+#define OffsetOf( Class, Member ) ( reinterpret_cast< unsigned int >( &( reinterpret_cast< Class* >( NULL )->*( &Class::Member ) ) ) )
|
|
|
|
+inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const
|
|
|
|
+{
|
|
|
|
+ int pointOffset = OffsetOf( PointP2T, point2D );
|
|
|
|
+ PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
|
|
|
|
+ if ( pointStruct.magic != BLEND_TESS_MAGIC )
|
|
|
|
+ {
|
|
|
|
+ ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" );
|
|
|
|
+ }
|
|
|
|
+ return pointStruct;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const
|
|
|
|
+{
|
|
|
|
+ for ( unsigned int i = 0; i < triangles.size( ); ++i )
|
|
|
|
+ {
|
|
|
|
+ p2t::Triangle& Triangle = *triangles[ i ];
|
|
|
|
+
|
|
|
|
+ PointP2T& pointA = GetActualPointStructure( *Triangle.GetPoint( 0 ) );
|
|
|
|
+ PointP2T& pointB = GetActualPointStructure( *Triangle.GetPoint( 1 ) );
|
|
|
|
+ PointP2T& pointC = GetActualPointStructure( *Triangle.GetPoint( 2 ) );
|
|
|
|
+
|
|
|
|
+ converter->AddFace( pointA.index, pointB.index, pointC.index );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+inline float p2tMax( float a, float b )
|
|
|
|
+{
|
|
|
|
+ return a > b ? a : b;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
|
|
|
|
+float BlenderTessellatorP2T::FindLargestMatrixElem( const aiMatrix3x3& mtx ) const
|
|
|
|
+{
|
|
|
|
+ float result = 0.0f;
|
|
|
|
+
|
|
|
|
+ for ( int x = 0; x < 3; ++x )
|
|
|
|
+ {
|
|
|
|
+ for ( int y = 0; y < 3; ++y )
|
|
|
|
+ {
|
|
|
|
+ result = p2tMax( fabs( mtx[ x ][ y ] ), result );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Aparently Assimp doesn't have matrix scaling
|
|
|
|
+aiMatrix3x3 BlenderTessellatorP2T::ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const
|
|
|
|
+{
|
|
|
|
+ aiMatrix3x3 result;
|
|
|
|
+
|
|
|
|
+ for ( int x = 0; x < 3; ++x )
|
|
|
|
+ {
|
|
|
|
+ for ( int y = 0; y < 3; ++y )
|
|
|
|
+ {
|
|
|
|
+ result[ x ][ y ] = mtx[ x ][ y ] * scale;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
|
|
|
|
+aiVector3D BlenderTessellatorP2T::GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const
|
|
|
|
+{
|
|
|
|
+ float scale = FindLargestMatrixElem( mtx );
|
|
|
|
+ aiMatrix3x3 mc = ScaleMatrix( mtx, 1.0f / scale );
|
|
|
|
+ mc = mc * mc * mc;
|
|
|
|
+
|
|
|
|
+ aiVector3D v( 1.0f );
|
|
|
|
+ aiVector3D lastV = v;
|
|
|
|
+ for ( int i = 0; i < 100; ++i )
|
|
|
|
+ {
|
|
|
|
+ v = mc * v;
|
|
|
|
+ v.Normalize( );
|
|
|
|
+ if ( ( v - lastV ).SquareLength( ) < 1e-16f )
|
|
|
|
+ {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ lastV = v;
|
|
|
|
+ }
|
|
|
|
+ return v;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
|
|
|
|
+PlaneP2T BlenderTessellatorP2T::FindLLSQPlane( const std::vector< PointP2T >& points ) const
|
|
|
|
+{
|
|
|
|
+ PlaneP2T result;
|
|
|
|
+
|
|
|
|
+ aiVector3D sum( 0.0f );
|
|
|
|
+ for ( unsigned int i = 0; i < points.size( ); ++i )
|
|
|
|
+ {
|
|
|
|
+ sum += points[ i ].point3D;
|
|
|
|
+ }
|
|
|
|
+ result.centre = sum * ( 1.0f / points.size( ) );
|
|
|
|
+
|
|
|
|
+ float sumXX = 0.0f;
|
|
|
|
+ float sumXY = 0.0f;
|
|
|
|
+ float sumXZ = 0.0f;
|
|
|
|
+ float sumYY = 0.0f;
|
|
|
|
+ float sumYZ = 0.0f;
|
|
|
|
+ float sumZZ = 0.0f;
|
|
|
|
+ for ( unsigned int i = 0; i < points.size( ); ++i )
|
|
|
|
+ {
|
|
|
|
+ aiVector3D offset = points[ i ].point3D - result.centre;
|
|
|
|
+ sumXX += offset.x * offset.x;
|
|
|
|
+ sumXY += offset.x * offset.y;
|
|
|
|
+ sumXZ += offset.x * offset.z;
|
|
|
|
+ sumYY += offset.y * offset.y;
|
|
|
|
+ sumYZ += offset.y * offset.z;
|
|
|
|
+ sumZZ += offset.z * offset.z;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ aiMatrix3x3 mtx( sumXX, sumXY, sumXZ, sumXY, sumYY, sumYZ, sumXZ, sumYZ, sumZZ );
|
|
|
|
+
|
|
|
|
+ float det = mtx.Determinant( );
|
|
|
|
+ if ( det == 0.0f )
|
|
|
|
+ {
|
|
|
|
+ result.normal = aiVector3D( 0.0f );
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ aiMatrix3x3 invMtx = mtx;
|
|
|
|
+ invMtx.Inverse( );
|
|
|
|
+ result.normal = GetEigenVectorFromLargestEigenValue( invMtx );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#endif // ASSIMP_BLEND_WITH_POLY_2_TRI
|
|
|
|
+
|
|
|
|
+#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|