Prechádzať zdrojové kódy

Add GLOB_MEASURE_TIME configuration option to profile the runtime of the postprocessing steps.
Start new documentation page for Performance/Profiling questions.
Migrate existing notes on multithreading to a new doc page, add more details.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@772 67173fc5-114c-0410-ac8e-9d2fd5bffc1f

aramis_acg 15 rokov pred
rodič
commit
aae8637666

+ 72 - 0
code/BoostWorkaround/boost/timer.hpp

@@ -0,0 +1,72 @@
+//  boost timer.hpp header file  ---------------------------------------------//
+
+//  Copyright Beman Dawes 1994-99.  Distributed under the Boost
+//  Software License, Version 1.0. (See accompanying file
+//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org/libs/timer for documentation.
+
+//  Revision History
+//  01 Apr 01  Modified to use new <boost/limits.hpp> header. (JMaddock)
+//  12 Jan 01  Change to inline implementation to allow use without library
+//             builds. See docs for more rationale. (Beman Dawes) 
+//  25 Sep 99  elapsed_max() and elapsed_min() added (John Maddock)
+//  16 Jul 99  Second beta
+//   6 Jul 99  Initial boost version
+
+#ifndef BOOST_TIMER_HPP
+#define BOOST_TIMER_HPP
+
+//#include <boost/config.hpp>
+#include <ctime>
+//#include <boost/limits.hpp>
+
+# ifdef BOOST_NO_STDC_NAMESPACE
+    namespace std { using ::clock_t; using ::clock; }
+# endif
+
+
+namespace boost {
+
+//  timer  -------------------------------------------------------------------//
+
+//  A timer object measures elapsed time.
+
+//  It is recommended that implementations measure wall clock rather than CPU
+//  time since the intended use is performance measurement on systems where
+//  total elapsed time is more important than just process or CPU time.
+
+//  Warnings: The maximum measurable elapsed time may well be only 596.5+ hours
+//  due to implementation limitations.  The accuracy of timings depends on the
+//  accuracy of timing information provided by the underlying platform, and
+//  this varies a great deal from platform to platform.
+
+class timer
+{
+ public:
+         timer() { _start_time = std::clock(); } // postcondition: elapsed()==0
+//         timer( const timer& src );      // post: elapsed()==src.elapsed()
+//        ~timer(){}
+//  timer& operator=( const timer& src );  // post: elapsed()==src.elapsed()
+  void   restart() { _start_time = std::clock(); } // post: elapsed()==0
+  double elapsed() const                  // return elapsed time in seconds
+    { return  double(std::clock() - _start_time) / CLOCKS_PER_SEC; }
+
+  double elapsed_max() const   // return estimated maximum value for elapsed()
+  // Portability warning: elapsed_max() may return too high a value on systems
+  // where std::clock_t overflows or resets at surprising values.
+  {
+    return (double((std::numeric_limits<std::clock_t>::max)())
+       - double(_start_time)) / double(CLOCKS_PER_SEC); 
+  }
+
+  double elapsed_min() const            // return minimum value for elapsed()
+   { return double(1)/double(CLOCKS_PER_SEC); }
+
+ private:
+  std::clock_t _start_time;
+}; // timer
+
+} // namespace boost
+
+#endif  // BOOST_TIMER_HPP

+ 2 - 0
code/CMakeLists.txt

@@ -141,6 +141,7 @@ SOURCE_GROUP( Common FILES
 	Vertex.h
 	LineSplitter.h
 	TinyFormatter.h
+	Profiler.h
 )
 
 SOURCE_GROUP( 3DS FILES 
@@ -720,6 +721,7 @@ ADD_LIBRARY( assimp SHARED
 	BlenderIntermediate.h
 	BlenderModifier.h
 	BlenderModifier.cpp
+	Profiler.h
 
 	# Necessary to show the headers in the project when using the VC++ generator:
 	BoostWorkaround/boost/math/common_factor_rt.hpp

+ 48 - 9
code/Importer.cpp

@@ -67,6 +67,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ProcessHelper.h"
 #include "ScenePreprocessor.h"
 #include "MemoryIOWrapper.h"
+#include "Profiler.h"
+
+using namespace Assimp::Profiling;
 
 // ------------------------------------------------------------------------------------------------
 // Importers
@@ -837,20 +840,25 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 	{
 		// Check whether this Importer instance has already loaded
 		// a scene. In this case we need to delete the old one
-		if (pimpl->mScene)
-		{
-			DefaultLogger::get()->debug("Deleting previous scene");
+		if (pimpl->mScene)	{
+
+			DefaultLogger::get()->debug("(Deleting previous scene)");
 			FreeScene();
 		}
 
 		// First check if the file is accessable at all
-		if( !pimpl->mIOHandler->Exists( pFile))
-		{
+		if( !pimpl->mIOHandler->Exists( pFile))	{
+
 			pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
 			DefaultLogger::get()->error(pimpl->mErrorString);
 			return NULL;
 		}
 
+		boost::scoped_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
+		if (profiler) {
+			profiler->BeginRegion("total");
+		}
+
 		// Find an worker class which can handle the file
 		BaseImporter* imp = NULL;
 		for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)	{
@@ -861,10 +869,9 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 			}
 		}
 
-		if (!imp)
-		{
+		if (!imp)	{
 			// not so bad yet ... try format auto detection.
-			std::string::size_type s = pFile.find_last_of('.');
+			const std::string::size_type s = pFile.find_last_of('.');
 			if (s != std::string::npos) {
 				DefaultLogger::get()->info("File extension now known, trying signature-based detection");
 				for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)	{
@@ -885,9 +892,18 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 
 		// Dispatch the reading to the worker class for this format
 		DefaultLogger::get()->info("Found a matching importer for this file format");
+
+		if (profiler) {
+			profiler->BeginRegion("import");
+		}
+
 		imp->SetupProperties( this );
 		pimpl->mScene = imp->ReadFile( pFile, pimpl->mIOHandler);
 
+		if (profiler) {
+			profiler->EndRegion("import");
+		}
+
 		// If successful, apply all active post processing steps to the imported data
 		if( pimpl->mScene)	{
 
@@ -904,9 +920,17 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 #endif // no validation
 
 			// Preprocess the scene and prepare it for post-processing 
+			if (profiler) {
+				profiler->BeginRegion("preprocess");
+			}
+
 			ScenePreprocessor pre(pimpl->mScene);
 			pre.ProcessScene();
 
+			if (profiler) {
+				profiler->EndRegion("preprocess");
+			}
+
 			// Ensure that the validation process won't be called twice
 			ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
 		}
@@ -917,6 +941,10 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 
 		// clear any data allocated by post-process steps
 		pimpl->mPPShared->Clean();
+
+		if (profiler) {
+			profiler->EndRegion("total");
+		}
 	}
 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 	catch (std::exception &e)
@@ -979,16 +1007,27 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 		pFlags |= aiProcess_ValidateDataStructure;
 	}
 #else
-	if (pimpl->bExtraVerbose)
+	if (pimpl->bExtraVerbose) {
 		DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
+	}
 #endif // ! DEBUG
+
+	boost::scoped_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
 	for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)	{
 
 		BaseProcess* process = pimpl->mPostProcessingSteps[a];
 		if( process->IsActive( pFlags))	{
 
+			if (profiler) {
+				profiler->BeginRegion("postprocess");
+			}
+
 			process->SetupProperties( this );
 			process->ExecuteOnScene	( this );
+
+			if (profiler) {
+				profiler->EndRegion("postprocess");
+			}
 		}
 		if( !pimpl->mScene) {
 			break; 

+ 97 - 0
code/Profiler.h

@@ -0,0 +1,97 @@
+/*
+Open Asset Import Library (ASSIMP)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2010, ASSIMP Development 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 Development 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 Profiler.h
+ *  @brief Utility to measure the respective runtime of each import step
+ */
+#ifndef INCLUDED_PROFILER_H
+#define INCLUDED_PROFILER_H
+
+#include "boost/timer.hpp"
+
+#include "../include/DefaultLogger.h"
+#include "TinyFormatter.h"
+
+namespace Assimp {
+	namespace Profiling {
+
+		using namespace Formatter;
+
+
+// ------------------------------------------------------------------------------------------------
+/** Simple wrapper around boost::timer to simplify reporting. Timings are automatically
+ *  dumped to the log file.
+ */
+class Profiler
+{
+
+public:
+
+	Profiler() {}
+
+public:
+	
+	/** Start a named timer */
+	void BeginRegion(const std::string& region) {
+		regions[region] = boost::timer();
+		DefaultLogger::get()->debug((format("START `"),region,"`"));
+	}
+	
+	
+	/** End a specific named timer and write its end time to the log */
+	void EndRegion(const std::string& region) {
+		RegionMap::const_iterator it = regions.find(region);
+		if (it == regions.end()) {
+			return;
+		}
+
+		DefaultLogger::get()->debug((format("END   `"),region,"`, dt= ",(*it).second.elapsed()," s"));
+	}
+
+private:
+
+	typedef std::map<std::string,boost::timer> RegionMap;
+	RegionMap regions;
+};
+
+	}
+}
+
+#endif

BIN
doc/AssimpDoc_Html/AssimpDoc.chm


+ 128 - 22
doc/dox.h

@@ -461,23 +461,6 @@ surely enough for almost any purpose. The process is simple:
 <li> .. and pass it as last parameter to #aiImportFileEx
 </ul>
 
-@section threadsafety Thread-safety and internal multi-threading
-
-The ASSIMP library can be accessed by multiple threads simultaneously, as long as the
-following prerequisites are fulfilled: 
-<ul>
-<li> When using the C++-API make sure you create a new Importer instance for each thread.
-   Constructing instances of Importer is expensive, so it might be a good idea to
-   let every thread maintain its own thread-local instance (use it to 
-   load as many models as you want).</li>
-<li> The C-API is threadsafe as long as AI_C_THREADSAFE is defined. That's the default. </li>
-<li> When supplying custom IO logic, make sure your underyling implementation is thead-safe.</li>
-<li> Custom log streams or logger replacements have to be thread-safe, too.</li>
-</ul>
-
-See the @ref assimp_st section @endlink to learn how to build a lightweight variant
-of ASSIMP which is not thread-safe and does not utilize multiple threads for loading.
-
 @section  logging Logging 
 
 The ASSIMP library provides an easy mechanism to log messages. For instance if you want to check the state of your 
@@ -1264,7 +1247,7 @@ mat->Get(AI_MATKEY_COLOR_DIFFUSE,color);
 @endcode
 
 <b>Note:</b> Get() is actually a template with explicit specializations for aiColor3D, aiColor4D, aiString, float, int and some others.
-Make sure that the type of the second parameter is matching the expected data type of the material property (no compile-time check yet!). 
+Make sure that the type of the second parameter matches the expected data type of the material property (no compile-time check yet!). 
 Don't follow this advice if you wish to encounter very strange results.
 
 @section C C-API
@@ -1466,16 +1449,139 @@ Build: alles von CustomBuild + DirectX + MFC?
 */
 
 
+/** 
+@page perf Performance
+
+@section perf_overview Overview
+
+This page discusses Assimps general performance and some ways to finetune and profile it. You will see that an
+intelligent choice of postprocessing steps is essential for quick loading.
+
+@section perf_profile Profiling
+
+Assimp has builtin support for basic profiling and reporting. To turn it on, set the <tt>GLOB_MEASURE_TIME</tt>
+configuration switch to <tt>true</tt> (nonzero). Results are dumped to the logfile, so you need to setup
+an appropriate logger implementation with at least one output stream first. See the @link logging Logging Page @endlink
+for the details.
+
+A sample report looks like this (some unrelated log messages omitted, grouped entries for clarity):
+
+@verbatim
+Debug, T5488: START `total`
+Info,  T5488: Found a matching importer for this file format
+

+Debug, T5488: START `import`
+Info,  T5488: BlendModifier: Applied the `Subdivision` modifier to `OBMonkey`
+Debug, T5488: END   `import`, dt= 3.516 s
+
+
+Debug, T5488: START `preprocess`
+Debug, T5488: END   `preprocess`, dt= 0.001 s
+Info,  T5488: Entering post processing pipeline
+

+Debug, T5488: START `postprocess`
+Debug, T5488: RemoveRedundantMatsProcess begin
+Debug, T5488: RemoveRedundantMatsProcess finished 
+Debug, T5488: END   `postprocess`, dt= 0.001 s
+

+Debug, T5488: START `postprocess`
+Debug, T5488: TriangulateProcess begin
+Info,  T5488: TriangulateProcess finished. All polygons have been triangulated.
+Debug, T5488: END   `postprocess`, dt= 3.415 s
+

+Debug, T5488: START `postprocess`
+Debug, T5488: SortByPTypeProcess begin
+Info,  T5488: Points: 0, Lines: 0, Triangles: 1, Polygons: 0 (Meshes, X = removed)
+Debug, T5488: SortByPTypeProcess finished

+Debug, T5488: START `postprocess`
+Debug, T5488: JoinVerticesProcess begin
+Debug, T5488: Mesh 0 (unnamed) | Verts in: 503808 out: 126345 | ~74.922
+Info,  T5488: JoinVerticesProcess finished | Verts in: 503808 out: 126345 | ~74.9
+Debug, T5488: END   `postprocess`, dt= 2.052 s

+Debug, T5488: START `postprocess`
+Debug, T5488: FlipWindingOrderProcess begin
+Debug, T5488: FlipWindingOrderProcess finished
+Debug, T5488: END   `postprocess`, dt= 0.006 s
+

+Debug, T5488: START `postprocess`
+Debug, T5488: LimitBoneWeightsProcess begin
+Debug, T5488: LimitBoneWeightsProcess end
+Debug, T5488: END   `postprocess`, dt= 0.001 s
+

+Debug, T5488: START `postprocess`
+Debug, T5488: ImproveCacheLocalityProcess begin
+Debug, T5488: Mesh 0 | ACMR in: 0.851622 out: 0.718139 | ~15.7
+Info,  T5488: Cache relevant are 1 meshes (251904 faces). Average output ACMR is 0.718139
+Debug, T5488: ImproveCacheLocalityProcess finished. 
+Debug, T5488: END   `postprocess`, dt= 1.903 s
+

+Info,  T5488: Leaving post processing pipeline
+Debug, T5488: END   `total`, dt= 11.269 s
+@endverbatim
+
+So, only one fourth of the total import time was used for the actual model import, while the rest of the
+time was consumed by the #aiProcess_Triangulate, #aiProcess_JoinIdenticalVertices and #aiProcess_ImproveCacheLocality 
+postprocessing steps. It is therefore not a good idea to specify *all* postprocessing flags just because they
+sound so nice.
+*/
+
+/** 
+@page threading Threading
+
+@section overview Overview
+
+This page discusses both Assimps scalability in threaded environments, the precautions to be taken in order to
+use it from multiple threads concurrently and finally its own ability to parallelize certain tasks internally.
+
+@section threadsafety Thread-safety / Using Assimp concurrently from several threads
+
+The library can be accessed by multiple threads simultaneously, as long as the
+following prerequisites are fulfilled: 
+<ul>
+<li> When using the C++-API make sure you create a new Importer instance for each thread.
+   Constructing instances of Importer is expensive, so it might be a good idea to
+   let every thread maintain its own thread-local instance (use it to 
+   load as many models as you want).</li>
+<li> The C-API is threadsafe as long as AI_C_THREADSAFE is defined. That's the default. </li>
+<li> When supplying custom IO logic, make sure your underyling implementation is thead-safe.</li>
+<li> Custom log streams or logger replacements have to be thread-safe, too.</li>
+</ul>
+
+
+
+Multiple concurrent imports may or may not be beneficial, however. For certain file formats in conjunction with 
+little postprocessing IO times tend to be the performance bottleneck, using multiple threads does therefore not 
+help. Intense postprocessing (especially the O(nlogn) steps #aiProcess_JoinIdenticalVertices,
+#aiProcess_GenSmoothNormals and #aiProcess_CalcTangentSpace) together with file formats like X or Collada, 
+which are slow to parse, might scale well with multiple concurrent imports. 
+
+
+@section automt Internal threading
+
+Automatic multi-threading is not currently implemented. 
+*/
 
 /**
 @page importer_notes Importer Notes
 
-@section ogre Ogre
+@section blender Blender
+@subsection bl_overview Overview
 
-@subsection overview Overview
-Ogre importer is currently optimized for the Blender Ogre exporter, because thats the only one that i use.
+Assimp provides a self-contained reimplementation of Blender's so called SDNA system (http://www.blender.org/development/architecture/notes-on-sdna/). 
+SDNA allows Blender to be fully backward AND forward compatible and to exchange
+files created on any of the various platforms blender runs on with any other. Quick processing is another design goal - 
+BLEND is a fully-fledged binary monster and Assimp tries to read the most of it. Naturally, if Blender is the only modelling tool 
+in your asset work flow, consider writing a custom exporter from Blender if Assimp's format coverage does not meet your requirements.
 
-You can find the Blender Ogre exporter at: http://www.ogre3d.org/forums/viewtopic.php?f=8&t=45922
+@subsection bl_status Current status
+
+@subsection bl_notes Notes
+
+
+
+@section ogre Ogre
+@subsection overview Overview
+Ogre importer is currently optimized for the Blender Ogre exporter, because thats the only one that i use. You can find the Blender Ogre exporter at: http://www.ogre3d.org/forums/viewtopic.php?f=8&t=45922
 
 @subsection what What will be loaded?
 

+ 51 - 12
include/aiConfig.h

@@ -59,6 +59,44 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define INCLUDED_AI_CONFIG_H
 
 
+// ###########################################################################
+// LIBRARY SETTINGS
+// General, global settings
+// ###########################################################################
+
+// ---------------------------------------------------------------------------
+/** @brief Enables time measurements.
+ *
+ *  If enabled, measures the time needed for each part of the loading
+ *  process (i.e. IO time, importing, postprocessing, ..) and dumps
+ *  these timings to the DefaultLogger. See the @link perf Performance
+ *  Page@endlink for more information on this topic.
+ * 
+ * Property type: bool. Default value: false.
+ */
+#define AI_CONFIG_GLOB_MEASURE_TIME  \
+	"GLOB_MEASURE_TIME"
+
+# if 0 // not implemented yet
+// ---------------------------------------------------------------------------
+/** @brief Set Assimp's multithreading policy.
+ *
+ * This setting is ignored if Assimp was built without boost.thread
+ * support (ASSIMP_BUILD_NO_THREADING, which is implied by ASSIMP_BUILD_BOOST_WORKAROUND).
+ * Possible values are: -1 to let Assimp decide what to do, 0 to disable
+ * multithreading entirely and any number larger than 0 to force a specific
+ * number of threads. Assimp is always free to ignore this settings, which is
+ * merely a hint. Usually, the default value (-1) will be fine. However, if
+ * Assimp is used concurrently from multiple user threads, it might be useful
+ * to limit each Importer instance to a specific number of cores.
+ *
+ * For more information, see the @link threading Threading page@endlink.
+ * Property type: int, default value: -1.
+ */
+#define AI_CONFIG_GLOB_MULTITHREADING  \
+	"GLOB_MULTITHREADING"
+#endif
+
 // ###########################################################################
 // POST PROCESSING SETTINGS
 // Various stuff to fine-tune the behavior of a specific post processing step.
@@ -136,7 +174,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * important additional information which you intend to parse. 
  * For rendering, you can still render all meshes in the scene without
  * any transformations.
- * Property type: integer (0: false; !0: true). Default value: false.
+ * Property type: bool. Default value: false.
  */
 #define AI_CONFIG_PP_PTV_KEEP_HIERARCHY		\
 	"PP_PTV_KEEP_HIERARCHY"
@@ -159,7 +197,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * degenerated lines to points. See the documentation to the
  * #aiProcess_FindDegenerates step for a detailed example of the various ways
  * to get rid of these lines and points if you don't want them.
- * Property type: integer (0: false; !0: true). Default value: false.
+ * Property type: bool. Default value: false.
  */
 #define AI_CONFIG_PP_FD_REMOVE \
 	"PP_FD_REMOVE"
@@ -402,7 +440,7 @@ enum aiComponent
 
 // ###########################################################################
 // IMPORTER SETTINGS
-// Various stuff to fine-tune the behaviour of a specific importer plugin.
+// Various stuff to fine-tune the behaviour of specific importer plugins.
 // ###########################################################################
 
 
@@ -433,7 +471,7 @@ enum aiComponent
 /** @brief  Configures the AC loader to collect all surfaces which have the
  *    "Backface cull" flag set in separate meshes. 
  *
- * Property type: integer (0: false; !0: true). Default value: true.
+ *  Property type: bool. Default value: true.
  */
 #define AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL	\
 	"IMPORT_AC_SEPARATE_BFCULL"
@@ -444,7 +482,7 @@ enum aiComponent
  *  default, Assimp performs the subdivision using the standard 
  *  Catmull-Clark algorithm
  *
- * Property type: integer (0: false; !0: true). Default value: true.
+ * * Property type: bool. Default value: true.
  */
 #define AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION	\
 	"IMPORT_AC_EVAL_SUBDIVISION"
@@ -453,7 +491,7 @@ enum aiComponent
 /** @brief  Configures the UNREAL 3D loader to separate faces with different
  *    surface flags (e.g. two-sided vs. single-sided).
  *
- * Property type: integer (0: false; !0: true). Default value: true.
+ * * Property type: bool. Default value: true.
  */
 #define AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS \
 	"UNREAL_HANDLE_FLAGS"
@@ -466,7 +504,7 @@ enum aiComponent
  * want to compute them on your own, if you need them. This option is intended
  * for model viewers which want to offer an easy way to apply textures to
  * terrains.
- * Property type: integer (0: false; !0: true). Default value: false.
+ * * Property type: bool. Default value: false.
  */
 #define AI_CONFIG_IMPORT_TER_MAKE_UVS \
 	"IMPORT_TER_MAKE_UVS"
@@ -475,19 +513,20 @@ enum aiComponent
 /** @brief  Configures the ASE loader to always reconstruct normal vectors
  *	basing on the smoothing groups loaded from the file.
  * 
- * Many ASE files have invalid normals (they're not orthonormal).
- * Property type: integer (0: false; !0: true). Default value: true.
+ * Some ASE files have carry invalid normals, other don't.
+ * * Property type: bool. Default value: true.
  */
 #define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS	\
 	"IMPORT_ASE_RECONSTRUCT_NORMALS"
 
 // ---------------------------------------------------------------------------
-/** @brief  Configures the M3D loader to process multi-part player models.
+/** @brief  Configures the M3D loader to detect and process multi-part 
+ *    Quake player models.
  *
  * These models usually consist of 3 files, lower.md3, upper.md3 and
  * head.md3. If this property is set to true, Assimp will try to load and
  * combine all three files if one of them is loaded. 
- * Property type: integer (0: false; !0: true). Default value: true.
+ * Property type: bool. Default value: true.
  */
 #define AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART \
 	"IMPORT_MD3_HANDLE_MULTIPART"
@@ -545,7 +584,7 @@ enum aiComponent
  * and combined with the MD5MESH file. This configuration option can be
  * used to disable this behaviour.
  * 
- * Property type: integer (0: false; !0: true). Default value: false.
+ * * Property type: bool. Default value: false.
  */
 #define AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD			\
 	"IMPORT_MD5_NO_ANIM_AUTOLOAD"

BIN
test/models/BLEND/MirroredCube_252.blend


+ 1 - 1
tools/assimp_view/assimp_view.cpp

@@ -151,7 +151,7 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
 	aiSetImportPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,g_smoothAngle);
 	aiSetImportPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,nopointslines ? aiPrimitiveType_LINE | aiPrimitiveType_POINT : 0 );
 
-	//aiSetImportPropertyInteger(AI_CONFIG_PP_FD_REMOVE,1);
+	aiSetImportPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,1);
 	//aiSetImportPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,1);
 
 	// Call ASSIMPs C-API to load the file

+ 4 - 0
workspaces/vc9/assimp.vcproj

@@ -2425,6 +2425,10 @@
 					RelativePath="..\..\code\ParsingUtils.h"
 					>
 				</File>
+				<File
+					RelativePath="..\..\code\Profiler.h"
+					>
+				</File>
 				<File
 					RelativePath="..\..\code\qnan.h"
 					>