Просмотр исходного кода

Updated to physfs 2.0.3 for 64-bit support, fixed player on Windows

Ivan Safrin 13 лет назад
Родитель
Сommit
9996ea0295

+ 2 - 2
CMake/ExternalAssimp.cmake

@@ -25,8 +25,8 @@ ExternalProject_Add(assimp
 
     DOWNLOAD_DIR ${POLYCODE_DEPS_DOWNLOAD_DIR}
 
-    PATCH_COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PolycodeDependencies_SOURCE_DIR}/../CMake/assimp.cmake <SOURCE_DIR>/code/CMakeLists.txt
-
+    PATCH_COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PolycodeDependencies_SOURCE_DIR}/../CMake/assimp.cmake <SOURCE_DIR>/code/CMakeLists.txt && ${CMAKE_COMMAND} -E copy_if_different ${PolycodeDependencies_SOURCE_DIR}/../CMake/assimp_patch/Vertex.h <SOURCE_DIR>/code/Vertex.h  && ${CMAKE_COMMAND} -E copy_if_different ${PolycodeDependencies_SOURCE_DIR}/../CMake/assimp_patch/BlenderModifier.cpp <SOURCE_DIR>/code/BlenderModifier.cpp  && ${CMAKE_COMMAND} -E copy_if_different ${PolycodeDependencies_SOURCE_DIR}/../CMake/assimp_patch/LWOAnimation.cpp <SOURCE_DIR>/code/LWOAnimation.cpp
+    
     URL http://download.sourceforge.net/assimp/assimp--2.0.863-sdk.zip
     URL_MD5 9f41662501bd9d9533c4cf03b7c25d5b
 

+ 1 - 0
CMake/ExternalBullet.cmake

@@ -9,6 +9,7 @@ SET(bullet_CMAKE_ARGS
     -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
     -DCMAKE_DEBUG_POSTFIX=_d
     -DINSTALL_LIBS=ON
+    -DUSE_MSVC_RUNTIME_LIBRARY_DLL=ON
     -DBUILD_DEMOS=OFF
     -DBUILD_EXTRAS=OFF
     -DBUILD_UNIT_TESTS=OFF

+ 2 - 2
CMake/ExternalPhysFS.cmake

@@ -19,8 +19,8 @@ ExternalProject_Add(physfs
 
     DOWNLOAD_DIR ${POLYCODE_DEPS_DOWNLOAD_DIR}
 
-    URL http://offload1.icculus.org:9090/physfs/downloads/physfs-2.0.2.tar.gz
-    URL_MD5 4e8927c3d30279b03e2592106eb9184a
+    URL http://icculus.org/physfs/downloads/physfs-2.0.3.tar.bz2
+    URL_MD5 c2c727a8a8deb623b521b52d0080f613
 
     PATCH_COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PolycodeDependencies_SOURCE_DIR}/../CMake/physfs.cmake <SOURCE_DIR>/CMakeLists.txt
 

+ 313 - 0
CMake/assimp_patch/BlenderModifier.cpp

@@ -0,0 +1,313 @@
+/*
+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  BlenderModifier.cpp
+ *  @brief Implementation of some blender modifiers (i.e subdivision, mirror).
+ */
+
+#include <functional>
+#include "AssimpPCH.h"
+
+#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
+#include "BlenderModifier.h"
+#include "SceneCombiner.h"
+#include "Subdivision.h"
+
+using namespace Assimp;
+using namespace Assimp::Blender;
+
+template <typename T> BlenderModifier* god() {
+	return new T();
+}
+
+// add all available modifiers here
+typedef BlenderModifier* (*fpCreateModifier)();
+static const fpCreateModifier creators[] = {
+		&god<BlenderModifier_Mirror>,
+		&god<BlenderModifier_Subdivision>,
+
+		NULL // sentinel
+};
+
+// ------------------------------------------------------------------------------------------------
+// just testing out some new macros to simplify logging
+#define ASSIMP_LOG_WARN_F(string,...)\
+	DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
+
+#define ASSIMP_LOG_ERROR_F(string,...)\
+	DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
+
+#define ASSIMP_LOG_DEBUG_F(string,...)\
+	DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
+
+#define ASSIMP_LOG_INFO_F(string,...)\
+	DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
+
+
+#define ASSIMP_LOG_WARN(string)\
+	DefaultLogger::get()->warn(string)
+
+#define ASSIMP_LOG_ERROR(string)\
+	DefaultLogger::get()->error(string)
+
+#define ASSIMP_LOG_DEBUG(string)\
+	DefaultLogger::get()->debug(string)
+
+#define ASSIMP_LOG_INFO(string)\
+	DefaultLogger::get()->info(string)
+
+
+// ------------------------------------------------------------------------------------------------
+struct SharedModifierData : ElemBase
+{
+	ModifierData modifier;
+};
+
+// ------------------------------------------------------------------------------------------------
+void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object ) 
+{
+	size_t cnt = 0u, ful = 0u;
+
+	// NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
+	// we're allowed to dereference the pointers without risking to crash. We might still be
+	// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
+	// structures is at offset sizeof(vftable) with no padding.
+	const SharedModifierData* cur = boost::static_pointer_cast<const SharedModifierData> ( orig_object.modifiers.first.get() );
+	for (; cur; cur =  boost::static_pointer_cast<const SharedModifierData> ( cur->modifier.next.get() ), ++ful) {
+		ai_assert(cur->dna_type);
+
+		const Structure* s = conv_data.db.dna.Get( cur->dna_type );
+		if (!s) {
+			ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
+			continue;
+		}
+
+		// this is a common trait of all XXXMirrorData structures in BlenderDNA
+		const Field* f = s->Get("modifier");
+		if (!f || f->offset != 0) {
+			ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
+			continue;
+		}
+
+		s = conv_data.db.dna.Get( f->type );
+		if (!s || s->name != "ModifierData") {
+			ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
+			continue;
+		}
+
+		// now, we can be sure that we should be fine to dereference *cur* as
+		// ModifierData (with the above note).
+		const ModifierData& dat = cur->modifier;
+
+		const fpCreateModifier* curgod = creators;
+		std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
+
+		for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
+			if (curmod == endmod) {
+				cached_modifiers->push_back((*curgod)());
+
+				endmod = cached_modifiers->end();
+				curmod = endmod-1;
+			}
+
+			BlenderModifier* const modifier = *curmod;
+			if(modifier->IsActive(dat)) {
+				modifier->DoIt(out,conv_data,*boost::static_pointer_cast<const ElemBase>(cur),in,orig_object);
+				cnt++;
+
+				curgod = NULL;
+				break;
+			}
+		}
+		if (curgod) {
+			ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
+		}
+	}
+
+	// Even though we managed to resolve some or all of the modifiers on this
+	// object, we still can't say whether our modifier implementations were
+	// able to fully do their job.
+	if (ful) {
+		ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
+			"`, check log messages above for errors");
+	}
+}
+
+
+
+// ------------------------------------------------------------------------------------------------
+bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
+{
+	return modin.type == ModifierData::eModifierType_Mirror;
+}
+
+// ------------------------------------------------------------------------------------------------
+void  BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data,  const ElemBase& orig_modifier, 
+	const Scene& in,
+	const Object& orig_object ) 
+{
+	// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
+	const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
+	ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
+
+	// XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
+
+	// take all input meshes and clone them
+	for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
+		aiMesh* mesh;
+		SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
+
+		const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
+		const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
+		const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
+
+		if (mir.mirror_ob) {
+			const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
+			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+				aiVector3D& v = mesh->mVertices[i];
+		
+				v.x = center.x + xs*(center.x - v.x);
+				v.y = center.y + ys*(center.y - v.y);
+				v.z = center.z + zs*(center.z - v.z);
+			}
+		}
+		else {
+			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+				aiVector3D& v = mesh->mVertices[i];
+				v.x *= xs;v.y *= ys;v.z *= zs;
+			}
+		}
+
+		if (mesh->mNormals) {
+			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+				aiVector3D& v = mesh->mNormals[i];
+				v.x *= xs;v.y *= ys;v.z *= zs;
+			}
+		}
+
+		if (mesh->mTangents) {
+			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+				aiVector3D& v = mesh->mTangents[i];
+				v.x *= xs;v.y *= ys;v.z *= zs;
+			}
+		}
+
+		if (mesh->mBitangents) {
+			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+				aiVector3D& v = mesh->mBitangents[i];
+				v.x *= xs;v.y *= ys;v.z *= zs;
+			}
+		}
+
+		const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f;
+		const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
+
+		for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
+			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+				aiVector3D& v = mesh->mTextureCoords[n][i];
+				v.x *= us;v.y *= vs;
+			}
+		}
+
+		conv_data.meshes->push_back(mesh);
+	}
+	unsigned int* nind = new unsigned int[out.mNumMeshes*2];
+
+	std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
+	std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
+		std::bind1st(std::plus< unsigned int >(),out.mNumMeshes));
+
+	delete[] out.mMeshes;
+	out.mMeshes = nind;
+	out.mNumMeshes *= 2;
+
+	ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
+		orig_object.id.name,"`");
+}
+
+
+
+
+// ------------------------------------------------------------------------------------------------
+bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
+{
+	return modin.type == ModifierData::eModifierType_Subsurf;
+}
+
+// ------------------------------------------------------------------------------------------------
+void  BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data,  const ElemBase& orig_modifier, 
+	const Scene& in,
+	const Object& orig_object ) 
+{
+	// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
+	const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
+	ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
+
+	Subdivider::Algorithm algo;
+	switch (mir.subdivType) 
+	{
+	case SubsurfModifierData::TYPE_CatmullClarke:
+		algo = Subdivider::CATMULL_CLARKE;
+		break;
+
+	case SubsurfModifierData::TYPE_Simple:
+		ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
+		algo = Subdivider::CATMULL_CLARKE;
+		break;
+
+	default:
+		ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
+		return;
+	};
+
+	boost::scoped_ptr<Subdivider> subd(Subdivider::Create(algo));
+	ai_assert(subd);
+
+	aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
+	boost::scoped_array<aiMesh*> tempmeshes(new aiMesh*[out.mNumMeshes]());
+
+	subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
+	std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
+
+	ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
+		orig_object.id.name,"`");
+}
+
+#endif

+ 586 - 0
CMake/assimp_patch/LWOAnimation.cpp

@@ -0,0 +1,586 @@
+/*
+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  LWOAnimation.cpp
+ *  @brief LWOAnimationResolver utility class 
+ *
+ *  It's a very generic implementation of LightWave's system of
+ *  componentwise-animated stuff. The one and only fully free
+ *  implementation of LightWave envelopes of which I know.
+*/
+
+#include <functional>
+#include "AssimpPCH.h"
+#if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER) && (!defined ASSIMP_BUILD_NO_LWS_IMPORTER)
+
+// internal headers
+#include "LWOFileData.h"
+
+using namespace Assimp;
+using namespace Assimp::LWO;
+
+// ------------------------------------------------------------------------------------------------
+// Construct an animation resolver from a given list of envelopes
+AnimResolver::AnimResolver(std::list<Envelope>& _envelopes,double tick)
+	: envelopes   (_envelopes)
+	, sample_rate (0.)
+{
+	trans_x = trans_y = trans_z = NULL;
+	rotat_x = rotat_y = rotat_z = NULL;
+	scale_x = scale_y = scale_z = NULL;
+
+	first = last = 150392.;
+
+	// find transformation envelopes
+	for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
+
+		(*it).old_first = 0;
+		(*it).old_last  = (*it).keys.size()-1;
+
+		if ((*it).keys.empty()) continue;
+		switch ((*it).type) {
+
+			// translation
+			case LWO::EnvelopeType_Position_X:
+				trans_x = &*it;break;
+			case LWO::EnvelopeType_Position_Y:
+				trans_y = &*it;break;
+			case LWO::EnvelopeType_Position_Z:
+				trans_z = &*it;break;
+
+				// rotation
+			case LWO::EnvelopeType_Rotation_Heading:
+				rotat_x = &*it;break;
+			case LWO::EnvelopeType_Rotation_Pitch:
+				rotat_y = &*it;break;
+			case LWO::EnvelopeType_Rotation_Bank:
+				rotat_z = &*it;break;
+
+				// scaling
+			case LWO::EnvelopeType_Scaling_X:
+				scale_x = &*it;break;
+			case LWO::EnvelopeType_Scaling_Y:
+				scale_y = &*it;break;
+			case LWO::EnvelopeType_Scaling_Z:
+				scale_z = &*it;break;
+			default:
+				continue;
+		};
+
+		// convert from seconds to ticks
+		for (std::vector<LWO::Key>::iterator d = (*it).keys.begin(); d != (*it).keys.end(); ++d)
+			(*d).time *= tick;
+
+		// set default animation range (minimum and maximum time value for which we have a keyframe)
+		first = std::min(first, (*it).keys.front().time );
+		last  = std::max(last,  (*it).keys.back().time );
+	}
+
+	// deferred setup of animation range to increase performance.
+	// typically the application will want to specify its own.
+	need_to_setup = true;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reset all envelopes to their original contents
+void AnimResolver::ClearAnimRangeSetup()
+{
+	for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
+		
+		(*it).keys.erase((*it).keys.begin(),(*it).keys.begin()+(*it).old_first);
+		(*it).keys.erase((*it).keys.begin()+(*it).old_last+1,(*it).keys.end());
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Insert additional keys to match LWO's pre& post behaviours.
+void AnimResolver::UpdateAnimRangeSetup()
+{
+	// XXX doesn't work yet (hangs if more than one envelope channels needs to be interpolated)
+
+	for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
+		if ((*it).keys.empty()) continue;
+	
+		const double my_first = (*it).keys.front().time;
+		const double my_last  = (*it).keys.back().time;
+
+		const double delta = my_last-my_first;
+		const size_t old_size = (*it).keys.size();
+
+		const float value_delta = (*it).keys.back().value - (*it).keys.front().value; 
+
+		// NOTE: We won't handle reset, linear and constant here.
+		// See DoInterpolation() for their implementation.
+
+		// process pre behaviour
+		switch ((*it).pre) {
+			case LWO::PrePostBehaviour_OffsetRepeat:
+			case LWO::PrePostBehaviour_Repeat:
+			case LWO::PrePostBehaviour_Oscillate:
+				{
+				const double start_time = delta - fmod(my_first-first,delta);
+				std::vector<LWO::Key>::iterator n = std::find_if((*it).keys.begin(),(*it).keys.end(), 
+					std::bind1st(std::greater<double>(),start_time)),m;
+
+				size_t ofs = 0;
+				if (n != (*it).keys.end()) {
+					// copy from here - don't use iterators, insert() would invalidate them
+					ofs = (*it).keys.end()-n;
+					(*it).keys.insert((*it).keys.begin(),ofs,LWO::Key());
+
+					std::copy((*it).keys.end()-ofs,(*it).keys.end(),(*it).keys.begin());
+				}
+
+				// do full copies. again, no iterators
+				const unsigned int num = (unsigned int)((my_first-first) / delta);
+				(*it).keys.resize((*it).keys.size() + num*old_size);
+
+				n = (*it).keys.begin()+ofs;
+				bool reverse = false;
+				for (unsigned int i = 0; i < num; ++i) {
+					m = n+old_size*(i+1);
+					std::copy(n,n+old_size,m);
+
+					if ((*it).pre == LWO::PrePostBehaviour_Oscillate && (reverse = !reverse))
+						std::reverse(m,m+old_size-1);
+				}
+
+				// update time values 
+				n = (*it).keys.end() - (old_size+1);
+				double cur_minus = delta;
+				unsigned int tt = 1;
+				for (const double tmp =  delta*(num+1);cur_minus <= tmp;cur_minus += delta,++tt) {
+					m = (delta == tmp ? (*it).keys.begin() :  n - (old_size+1));
+					for (;m != n; --n) {
+						(*n).time -= cur_minus;
+					
+						// offset repeat? add delta offset to key value
+						if ((*it).pre == LWO::PrePostBehaviour_OffsetRepeat) {
+							(*n).value += tt * value_delta;
+						}
+					}
+				}
+				break;
+				}
+			default:
+				// silence compiler warning
+				break;
+		}
+
+		// process post behaviour
+		switch ((*it).post) {
+			
+			case LWO::PrePostBehaviour_OffsetRepeat:
+			case LWO::PrePostBehaviour_Repeat:
+			case LWO::PrePostBehaviour_Oscillate:
+
+				break;
+
+			default:
+				// silence compiler warning
+				break;
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Extract bind pose matrix
+void AnimResolver::ExtractBindPose(aiMatrix4x4& out)
+{
+	// If we have no envelopes, return identity
+	if (envelopes.empty()) {
+		out = aiMatrix4x4();
+		return;
+	}
+	aiVector3D angles, scaling(1.f,1.f,1.f), translation;
+
+	if (trans_x) translation.x = trans_x->keys[0].value;
+	if (trans_y) translation.y = trans_y->keys[0].value;
+	if (trans_z) translation.z = trans_z->keys[0].value;
+
+	if (rotat_x) angles.x = rotat_x->keys[0].value;
+	if (rotat_y) angles.y = rotat_y->keys[0].value;
+	if (rotat_z) angles.z = rotat_z->keys[0].value;
+
+	if (scale_x) scaling.x = scale_x->keys[0].value;
+	if (scale_y) scaling.y = scale_y->keys[0].value;
+	if (scale_z) scaling.z = scale_z->keys[0].value;
+
+	// build the final matrix
+	aiMatrix4x4 s,r,t;
+	
+	r.FromEulerAnglesXYZ(angles);
+	//aiMatrix4x4::RotationY(angles.y,r);
+	// fixme: make FromEulerAngles static, too
+	aiMatrix4x4::Translation(translation,t);
+	aiMatrix4x4::Scaling(scaling,s);
+	out = s*r*t;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Do a single interpolation on a channel 
+void AnimResolver::DoInterpolation(std::vector<LWO::Key>::const_iterator cur, 
+	LWO::Envelope* envl,double time, float& fill)
+{
+	if (envl->keys.size() == 1) {
+		fill = envl->keys[0].value;
+		return;
+	}
+
+	// check whether we're at the beginning of the animation track
+	if (cur == envl->keys.begin()) {
+	
+		// ok ... this depends on pre behaviour now
+		// we don't need to handle repeat&offset repeat&oszillate here, see UpdateAnimRangeSetup()
+		switch (envl->pre)
+		{
+		case LWO::PrePostBehaviour_Linear:
+			DoInterpolation2(cur,cur+1,time,fill);
+			return;
+
+		case LWO::PrePostBehaviour_Reset:
+			fill = 0.f;
+			return;
+
+		default : //case LWO::PrePostBehaviour_Constant:
+			fill = (*cur).value;
+			return;
+		}
+	}
+	// check whether we're at the end of the animation track
+	else if (cur == envl->keys.end()-1 && time > envl->keys.rbegin()->time) {
+		// ok ... this depends on post behaviour now
+		switch (envl->post)
+		{
+		case LWO::PrePostBehaviour_Linear:
+			DoInterpolation2(cur,cur-1,time,fill);
+			return;
+
+		case LWO::PrePostBehaviour_Reset:
+			fill = 0.f;
+			return;
+
+		default : //case LWO::PrePostBehaviour_Constant:
+			fill = (*cur).value;
+			return;
+		}
+	}
+
+	// Otherwise do a simple interpolation
+	DoInterpolation2(cur-1,cur,time,fill);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Almost the same, except we won't handle pre/post conditions here
+void AnimResolver::DoInterpolation2(std::vector<LWO::Key>::const_iterator beg, 
+	std::vector<LWO::Key>::const_iterator end,double time, float& fill)
+{
+	switch ((*end).inter) {
+		
+		case LWO::IT_STEP:
+			// no interpolation at all - take the value of the last key
+			fill = (*beg).value;
+			return;
+		default:
+
+			// silence compiler warning
+			break;
+	}
+	// linear interpolation - default
+	fill = (*beg).value + ((*end).value - (*beg).value)*(float)(((time - (*beg).time) / ((*end).time - (*beg).time)));
+}
+
+// ------------------------------------------------------------------------------------------------
+// Subsample animation track by given key values
+void AnimResolver::SubsampleAnimTrack(std::vector<aiVectorKey>& /*out*/,
+	double /*time*/ ,double /*sample_delta*/ )
+{
+	//ai_assert(out.empty() && sample_delta);
+
+	//const double time_start = out.back().mTime;
+//	for ()
+}
+
+// ------------------------------------------------------------------------------------------------
+// Track interpolation
+void AnimResolver::InterpolateTrack(std::vector<aiVectorKey>& out,aiVectorKey& fill,double time)
+{
+	// subsample animation track?
+	if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) {
+		SubsampleAnimTrack(out,time, sample_delta);
+	}
+
+	fill.mTime = time;
+
+	// get x
+	if ((*cur_x).time == time) {
+		fill.mValue.x = (*cur_x).value;
+
+		if (cur_x != envl_x->keys.end()-1) /* increment x */
+			++cur_x;
+		else end_x = true;
+	}
+	else DoInterpolation(cur_x,envl_x,time,(float&)fill.mValue.x);
+
+	// get y
+	if ((*cur_y).time == time) {
+		fill.mValue.y = (*cur_y).value;
+
+		if (cur_y != envl_y->keys.end()-1) /* increment y */
+			++cur_y;
+		else end_y = true;
+	}
+	else DoInterpolation(cur_y,envl_y,time,(float&)fill.mValue.y);
+
+	// get z
+	if ((*cur_z).time == time) {
+		fill.mValue.z = (*cur_z).value;
+
+		if (cur_z != envl_z->keys.end()-1) /* increment z */
+			++cur_z;
+		else end_x = true;
+	}
+	else DoInterpolation(cur_z,envl_z,time,(float&)fill.mValue.z);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Build linearly subsampled keys from three single envelopes, one for each component (x,y,z)
+void AnimResolver::GetKeys(std::vector<aiVectorKey>& out, 
+	LWO::Envelope* _envl_x,
+	LWO::Envelope* _envl_y,
+	LWO::Envelope* _envl_z,
+	unsigned int _flags)
+{
+	envl_x = _envl_x;
+	envl_y = _envl_y;
+	envl_z = _envl_z;
+	flags  = _flags;
+
+	// generate default channels if none are given
+	LWO::Envelope def_x, def_y, def_z;
+	LWO::Key key_dummy;
+	key_dummy.time = 0.f;
+	if ((envl_x && envl_x->type == LWO::EnvelopeType_Scaling_X) ||
+		(envl_y && envl_y->type == LWO::EnvelopeType_Scaling_Y) || 
+		(envl_z && envl_z->type == LWO::EnvelopeType_Scaling_Z)) {
+		key_dummy.value = 1.f;
+	}
+	else key_dummy.value = 0.f;
+
+	if (!envl_x) {
+		envl_x = &def_x;
+		envl_x->keys.push_back(key_dummy);
+	}
+	if (!envl_y) {
+		envl_y = &def_y;
+		envl_y->keys.push_back(key_dummy);
+	}
+	if (!envl_z) {
+		envl_z = &def_z;
+		envl_z->keys.push_back(key_dummy);
+	}
+
+	// guess how many keys we'll get
+	size_t reserve;
+	double sr = 1.;
+	if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) {
+		if (!sample_rate)
+			sr = 100.f;
+		else sr = sample_rate;
+		sample_delta = 1.f / sr; 
+
+		reserve = (size_t)(
+			std::max( envl_x->keys.end()->time,
+			std::max( envl_y->keys.end()->time, envl_z->keys.end()->time )) * sr);
+	}
+	else reserve = std::max(envl_x->keys.size(),std::max(envl_x->keys.size(),envl_z->keys.size()));
+	out.reserve(reserve+(reserve>>1));
+
+	// Iterate through all three arrays at once - it's tricky, but 
+	// rather interesting to implement.
+	double lasttime = std::min(envl_x->keys[0].time,std::min(envl_y->keys[0].time,envl_z->keys[0].time));
+	
+	cur_x = envl_x->keys.begin();
+	cur_y = envl_y->keys.begin();
+	cur_z = envl_z->keys.begin();
+
+	end_x = end_y = end_z = false;
+	while (1) {
+
+		aiVectorKey fill;
+
+		if ((*cur_x).time == (*cur_y).time && (*cur_x).time == (*cur_z).time ) {
+
+			// we have a keyframe for all of them defined .. great,
+			// we don't need to fucking interpolate here ...
+			fill.mTime = (*cur_x).time;
+
+			fill.mValue.x = (*cur_x).value;
+			fill.mValue.y = (*cur_y).value;
+			fill.mValue.z = (*cur_z).value;
+
+			// subsample animation track
+			if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) {
+				//SubsampleAnimTrack(out,cur_x, cur_y, cur_z, d, sample_delta);
+			}
+
+			if (cur_x != envl_x->keys.end()-1)
+				++cur_x;
+			else end_x = true;
+			if (cur_y != envl_y->keys.end()-1)
+				++cur_y;
+			else end_y = true;
+			if (cur_z != envl_z->keys.end()-1)
+				++cur_z;
+			else end_z = true;
+		}
+
+		// Find key with lowest time value
+		else if ((*cur_x).time <= (*cur_y).time && !end_x) {
+
+			if ((*cur_z).time <= (*cur_x).time && !end_z) {
+				InterpolateTrack(out,fill,(*cur_z).time);
+			}
+			else {
+				InterpolateTrack(out,fill,(*cur_x).time);
+			}
+		}
+		else if ((*cur_z).time <= (*cur_y).time && !end_z)	{
+			InterpolateTrack(out,fill,(*cur_z).time);
+		}
+		else if (!end_y) {
+			// welcome on the server, y
+			InterpolateTrack(out,fill,(*cur_y).time);
+		}
+		else {
+			// we have reached the end of at least 2 channels,
+			// only one is remaining. Extrapolate the 2.
+			if (end_y) {
+				InterpolateTrack(out,fill,(end_x ? (*cur_z) : (*cur_x)).time);
+			}
+			else if (end_x) {
+				InterpolateTrack(out,fill,(end_z ? (*cur_y) : (*cur_z)).time);
+			}
+			else { // if (end_z) 
+				InterpolateTrack(out,fill,(end_y ? (*cur_x) : (*cur_y)).time);
+			}
+		}
+		lasttime = fill.mTime;
+		out.push_back(fill);
+
+		if( end_x && end_y && end_z ) /* finished? */
+			break;
+	}
+
+	if (flags & AI_LWO_ANIM_FLAG_START_AT_ZERO) {
+		for (std::vector<aiVectorKey>::iterator it = out.begin(); it != out.end(); ++it)
+			(*it).mTime -= first;
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Extract animation channel
+void AnimResolver::ExtractAnimChannel(aiNodeAnim** out, unsigned int flags /*= 0*/)
+{
+	*out = NULL;
+
+
+	//FIXME: crashes if more than one component is animated at different timings, to be resolved.
+	return;
+
+#if 0
+	// If we have no envelopes, return NULL
+	if (envelopes.empty()) {
+		return;
+	}
+
+	// We won't spawn an animation channel if we don't have at least one envelope with more than one keyframe defined.
+	const bool trans = (trans_x && trans_x->keys.size() > 1 || trans_y && trans_y->keys.size() > 1 || trans_z && trans_z->keys.size() > 1);
+	const bool rotat = (rotat_x && rotat_x->keys.size() > 1 || rotat_y && rotat_y->keys.size() > 1 || rotat_z && rotat_z->keys.size() > 1);
+	const bool scale = (scale_x && scale_x->keys.size() > 1 || scale_y && scale_y->keys.size() > 1 || scale_z && scale_z->keys.size() > 1);
+	if (!trans && !rotat && !scale)
+		return;
+
+	// Allocate the output animation 
+	aiNodeAnim* anim = *out = new aiNodeAnim();
+
+	// Setup default animation setup if necessary
+	if (need_to_setup) {
+		UpdateAnimRangeSetup();
+		need_to_setup = false;
+	}
+
+	// copy translation keys
+	if (trans) {
+		std::vector<aiVectorKey> keys;
+		GetKeys(keys,trans_x,trans_y,trans_z,flags);
+
+		anim->mPositionKeys = new aiVectorKey[ anim->mNumPositionKeys = keys.size() ];
+		std::copy(keys.begin(),keys.end(),anim->mPositionKeys);
+	}
+
+	// copy rotation keys
+	if (rotat) {
+		std::vector<aiVectorKey> keys;
+		GetKeys(keys,rotat_x,rotat_y,rotat_z,flags);
+
+		anim->mRotationKeys = new aiQuatKey[ anim->mNumRotationKeys = keys.size() ];
+		
+		// convert heading, pitch, bank to quaternion
+		for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
+			aiQuatKey& qk = anim->mRotationKeys[i];
+			qk.mTime  = keys[i].mTime;
+			qk.mValue = aiQuaternion( keys[i].mValue.x ,keys[i].mValue.z ,keys[i].mValue.y );
+		}
+	}
+
+	// copy scaling keys
+	if (scale) {
+		std::vector<aiVectorKey> keys;
+		GetKeys(keys,scale_x,scale_y,scale_z,flags);
+
+		anim->mScalingKeys = new aiVectorKey[ anim->mNumScalingKeys = keys.size() ];
+		std::copy(keys.begin(),keys.end(),anim->mScalingKeys);
+	}
+#endif
+}
+
+
+#endif // no lwo or no lws

+ 304 - 0
CMake/assimp_patch/Vertex.h

@@ -0,0 +1,304 @@
+/*
+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.
+
+----------------------------------------------------------------------/
+*/
+
+#include <functional>
+
+/** @file Defines a helper class to represent an interleaved vertex */
+#ifndef AI_VERTEX_H_INC
+#define AI_VERTEX_H_INC
+namespace Assimp	{
+	
+	///////////////////////////////////////////////////////////////////////////
+	// std::plus-family operates on operands with identical types - we need to
+	// support all the (vectype op float) combinations in vector maths. 
+	// Providing T(float) would open the way to endless implicit conversions.
+	///////////////////////////////////////////////////////////////////////////
+	namespace Intern {
+		template <typename T0, typename T1, typename TRES = T0> struct plus {
+			TRES operator() (const T0& t0, const T1& t1) const {
+				return t0+t1;
+			}
+		};
+		template <typename T0, typename T1, typename TRES = T0> struct minus {
+			TRES operator() (const T0& t0, const T1& t1) const {
+				return t0-t1;
+			}
+		};
+		template <typename T0, typename T1, typename TRES = T0> struct multiplies {
+			TRES operator() (const T0& t0, const T1& t1) const {
+				return t0*t1;
+			}
+		};
+		template <typename T0, typename T1, typename TRES = T0> struct divides {
+			TRES operator() (const T0& t0, const T1& t1) const {
+				return t0/t1;
+			}
+		};
+	}
+
+// ------------------------------------------------------------------------------------------------
+/** Intermediate description a vertex with all possible components. Defines a full set of 
+ *  operators, so you may use such a 'Vertex' in basic arithmetics. All operators are applied
+ *  to *all* vertex components equally. This is useful for stuff like interpolation
+ *  or subdivision, but won't work if special handling is required for some vertex components. */
+// ------------------------------------------------------------------------------------------------
+class Vertex
+{
+	friend Vertex operator + (const Vertex&,const Vertex&);
+	friend Vertex operator - (const Vertex&,const Vertex&);
+
+	friend Vertex operator + (const Vertex&,float);
+	friend Vertex operator - (const Vertex&,float);
+	friend Vertex operator * (const Vertex&,float);
+	friend Vertex operator / (const Vertex&,float);
+
+	friend Vertex operator + (float, const Vertex&);
+	friend Vertex operator - (float, const Vertex&);
+	friend Vertex operator * (float, const Vertex&);
+	friend Vertex operator / (float, const Vertex&);
+
+public:
+
+	Vertex() {}
+
+	// ----------------------------------------------------------------------------
+	/** Extract a particular vertex from a mesh and interleave all components */
+	explicit Vertex(const aiMesh* msh, unsigned int idx) {
+		ai_assert(idx < msh->mNumVertices);
+		position = msh->mVertices[idx];
+
+		if (msh->HasNormals()) {
+			normal = msh->mNormals[idx];
+		}
+
+		if (msh->HasTangentsAndBitangents()) {
+			tangent = msh->mTangents[idx];
+			bitangent = msh->mBitangents[idx];
+		}
+
+		for (unsigned int i = 0; msh->HasTextureCoords(i); ++i) {
+			texcoords[i] = msh->mTextureCoords[i][idx];
+		}
+
+		for (unsigned int i = 0; msh->HasVertexColors(i); ++i) {
+			colors[i] = msh->mColors[i][idx];
+		}
+	}
+
+public:
+
+	Vertex& operator += (const Vertex& v) {
+		*this = *this+v;
+		return *this;
+	}
+
+	Vertex& operator -= (const Vertex& v) {
+		*this = *this-v;
+		return *this;
+	}
+
+
+
+	Vertex& operator += (float v) {
+		*this = *this+v;
+		return *this;
+	}
+
+	Vertex& operator -= (float v) {
+		*this = *this-v;
+		return *this;
+	}
+
+	Vertex& operator *= (float v) {
+		*this = *this*v;
+		return *this;
+	}
+
+	Vertex& operator /= (float v) {
+		*this = *this/v;
+		return *this;
+	}
+
+public:
+
+	// ----------------------------------------------------------------------------
+	/** Convert back to non-interleaved storage */
+	void SortBack(aiMesh* out, unsigned int idx) const {
+
+		ai_assert(idx<out->mNumVertices);
+		out->mVertices[idx] = position;
+
+		if (out->HasNormals()) {
+			out->mNormals[idx] = normal;
+		}
+
+		if (out->HasTangentsAndBitangents()) {
+			out->mTangents[idx] = tangent;
+			out->mBitangents[idx] = bitangent;
+		}
+
+		for(unsigned int i = 0; out->HasTextureCoords(i); ++i) {
+			out->mTextureCoords[i][idx] = texcoords[i];
+		}
+
+		for(unsigned int i = 0; out->HasVertexColors(i); ++i) {
+			out->mColors[i][idx] = colors[i];
+		}
+	}
+
+private:
+
+	// ----------------------------------------------------------------------------
+	/** Construct from two operands and a binary operation to combine them */
+	template <template <typename t> class op> static Vertex BinaryOp(const Vertex& v0, const Vertex& v1) {
+		// this is a heavy task for the compiler to optimize ... *pray*
+
+		Vertex res;
+		res.position  = op<aiVector3D>()(v0.position,v1.position);
+		res.normal    = op<aiVector3D>()(v0.normal,v1.normal);
+		res.tangent   = op<aiVector3D>()(v0.tangent,v1.tangent);
+		res.bitangent = op<aiVector3D>()(v0.bitangent,v1.bitangent);
+
+		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+			res.texcoords[i] = op<aiVector3D>()(v0.texcoords[i],v1.texcoords[i]);
+		}
+		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
+			res.colors[i] = op<aiColor4D>()(v0.colors[i],v1.colors[i]);
+		}
+		return res;
+	}
+
+	// ----------------------------------------------------------------------------
+	/** This time binary arithmetics of v0 with a floating-point number */
+	template <template <typename, typename, typename> class op> static Vertex BinaryOp(const Vertex& v0, float f) {
+		// this is a heavy task for the compiler to optimize ... *pray*
+
+		Vertex res;
+		res.position  = op<aiVector3D,float,aiVector3D>()(v0.position,f);
+		res.normal    = op<aiVector3D,float,aiVector3D>()(v0.normal,f);
+		res.tangent   = op<aiVector3D,float,aiVector3D>()(v0.tangent,f);
+		res.bitangent = op<aiVector3D,float,aiVector3D>()(v0.bitangent,f);
+
+		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+			res.texcoords[i] = op<aiVector3D,float,aiVector3D>()(v0.texcoords[i],f);
+		}
+		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
+			res.colors[i] = op<aiColor4D,float,aiColor4D>()(v0.colors[i],f);
+		}
+		return res;
+	}
+
+	// ----------------------------------------------------------------------------
+	/** This time binary arithmetics of v0 with a floating-point number */
+	template <template <typename, typename, typename> class op> static Vertex BinaryOp(float f, const Vertex& v0) {
+		// this is a heavy task for the compiler to optimize ... *pray*
+
+		Vertex res;
+		res.position  = op<float,aiVector3D,aiVector3D>()(f,v0.position);
+		res.normal    = op<float,aiVector3D,aiVector3D>()(f,v0.normal);
+		res.tangent   = op<float,aiVector3D,aiVector3D>()(f,v0.tangent);
+		res.bitangent = op<float,aiVector3D,aiVector3D>()(f,v0.bitangent);
+
+		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+			res.texcoords[i] = op<float,aiVector3D,aiVector3D>()(f,v0.texcoords[i]);
+		}
+		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
+			res.colors[i] = op<float,aiColor4D,aiColor4D>()(f,v0.colors[i]);
+		}
+		return res;
+	}
+
+public:
+
+	aiVector3D position;
+	aiVector3D normal;
+	aiVector3D tangent, bitangent;
+
+	aiVector3D texcoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+	aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
+};
+
+
+
+// ------------------------------------------------------------------------------------------------
+AI_FORCE_INLINE Vertex operator + (const Vertex& v0,const Vertex& v1) {
+	return Vertex::BinaryOp<std::plus>(v0,v1);
+}
+
+AI_FORCE_INLINE Vertex operator - (const Vertex& v0,const Vertex& v1) {
+	return Vertex::BinaryOp<std::minus>(v0,v1);
+}
+
+// ------------------------------------------------------------------------------------------------
+AI_FORCE_INLINE Vertex operator + (const Vertex& v0,float f) {
+	return Vertex::BinaryOp<Intern::plus>(v0,f);
+}
+
+AI_FORCE_INLINE Vertex operator - (const Vertex& v0,float f) {
+	return Vertex::BinaryOp<Intern::minus>(v0,f);
+}
+
+AI_FORCE_INLINE Vertex operator * (const Vertex& v0,float f) {
+	return Vertex::BinaryOp<Intern::multiplies>(v0,f);
+}
+
+AI_FORCE_INLINE Vertex operator / (const Vertex& v0,float f) {
+	return Vertex::BinaryOp<Intern::divides>(v0,f);
+}
+
+// ------------------------------------------------------------------------------------------------
+AI_FORCE_INLINE Vertex operator + (float f,const Vertex& v0) {
+	return Vertex::BinaryOp<Intern::plus>(f,v0);
+}
+
+AI_FORCE_INLINE Vertex operator - (float f,const Vertex& v0) {
+	return Vertex::BinaryOp<Intern::minus>(f,v0);
+}
+
+AI_FORCE_INLINE Vertex operator * (float f,const Vertex& v0) {
+	return Vertex::BinaryOp<Intern::multiplies>(f,v0);
+}
+
+AI_FORCE_INLINE Vertex operator / (float f,const Vertex& v0) {
+	return Vertex::BinaryOp<Intern::divides>(f,v0);
+}
+
+}
+#endif

+ 1 - 1
Player/Build/MSVC/PolycodePlayer/main.cpp

@@ -64,7 +64,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
 	PolycodeWindowsPlayer *player = new PolycodeWindowsPlayer(view, "main.polyapp", false);
 #else
 	PolycodePlayerView *view = new PolycodePlayerView(false, hInstance, nCmdShow, L"Polycode Player");
-	PolycodeWindowsPlayer *player = new PolycodeWindowsPlayer(view, fileName.c_str(), false);
+	PolycodeWindowsPlayer *player = new PolycodeWindowsPlayer(view, fileName.c_str(), false, true);
 #endif
 	player->addEventListener(view, PolycodeDebugEvent::EVENT_ERROR);
 	player->addEventListener(view, PolycodeDebugEvent::EVENT_PRINT);

+ 46 - 1
Player/Contents/CMakeLists.txt

@@ -7,8 +7,16 @@ IF(MSVC OR MINGW)
 INCLUDE_DIRECTORIES(
     ${LUA_INCLUDE_DIR}
     ${Polycode_SOURCE_DIR}/Bindings/Contents/LUA/Include
+ 
+    ${Polycode_SOURCE_DIR}/Modules/Contents/UI/Include
     ${Polycode_SOURCE_DIR}/Modules/Bindings/UI/Include
+
+    ${BOX2D_INCLUDE_DIR}
+    ${Polycode_SOURCE_DIR}/Modules/Contents/2DPhysics/Include
     ${Polycode_SOURCE_DIR}/Modules/Bindings/2DPhysics/Include
+
+    ${BULLET_INCLUDE_DIR}
+    ${Polycode_SOURCE_DIR}/Modules/Contents/3DPhysics/Include
     ${Polycode_SOURCE_DIR}/Modules/Bindings/3DPhysics/Include
     Include
     ../../Core/Contents/PolycodeView/MSVC/
@@ -60,6 +68,24 @@ SET(polycodeplayer_SRCS
         glu32
         winmm
         ws2_32
+    Physics2DLua
+    Physics3DLua
+    UILua
+    Polycode2DPhysics
+    Polycode3DPhysics
+    PolycodeUI
+    optimized ${BOX2D_RELEASE_LIBRARY}
+    debug ${BOX2D_DEBUG_LIBRARY}
+        optimized ${LIBBULLETMULTITHREADED}
+        optimized ${LIBBULLETSOFTBODY} 
+        optimized ${LIBBULLETDYNAMICS} 
+        optimized ${LIBBULLETCOLLISION}
+        optimized ${LIBBULLETMATH}            
+        debug ${LIBBULLETMULTITHREADED_DEBUG}
+        debug ${LIBBULLETSOFTBODY_DEBUG} 
+        debug ${LIBBULLETDYNAMICS_DEBUG} 
+        debug ${LIBBULLETCOLLISION_DEBUG}
+        debug ${LIBBULLETMATH_DEBUG}  
      )
 
     TARGET_LINK_LIBRARIES(StandalonePlayer 
@@ -78,7 +104,25 @@ SET(polycodeplayer_SRCS
         opengl32
         glu32
         winmm
-        ws2_32   
+        ws2_32 
+    Physics2DLua
+    Physics3DLua
+    UILua
+    Polycode2DPhysics
+    Polycode3DPhysics
+    PolycodeUI
+    optimized ${BOX2D_RELEASE_LIBRARY}
+    debug ${BOX2D_DEBUG_LIBRARY}
+        optimized ${LIBBULLETMULTITHREADED}
+        optimized ${LIBBULLETSOFTBODY} 
+        optimized ${LIBBULLETDYNAMICS} 
+        optimized ${LIBBULLETCOLLISION}
+        optimized ${LIBBULLETMATH}            
+        debug ${LIBBULLETMULTITHREADED_DEBUG}
+        debug ${LIBBULLETSOFTBODY_DEBUG} 
+        debug ${LIBBULLETDYNAMICS_DEBUG} 
+        debug ${LIBBULLETCOLLISION_DEBUG}
+        debug ${LIBBULLETMATH_DEBUG} 
      )
 
 ELSEIF(APPLE)
@@ -423,6 +467,7 @@ IF(MSVC OR MINGW)
     INSTALL(FILES "${Polycode_SOURCE_DIR}/Assets/Default\ asset\ pack/hdr.pak" DESTINATION Player)
     INSTALL(FILES "${Polycode_SOURCE_DIR}/Assets/SamplePolyapp/main.polyapp" DESTINATION Player)
     INSTALL(FILES "${Polycode_SOURCE_DIR}/Bindings/Contents/LUA/API/api.pak" DESTINATION Player)
+    INSTALL(FILES ${POLYCODE_RELEASE_DIR}/Framework/Core/Dependencies/bin/OpenAL32.dll DESTINATION Player)
 ELSEIF(APPLE)
 ELSE(MSVC OR MINGW)
     INSTALL(FILES "${Polycode_SOURCE_DIR}/Assets/Default\ asset\ pack/default.pak" DESTINATION Player)

+ 33 - 1
Player/Contents/Platform/Windows/Standalone/main.cpp

@@ -4,7 +4,8 @@
 #include "PolycodePlayerView.h"
 #include "windows.h"
 #include "resource.h"
-
+#include <io.h>
+#include <fcntl.h>
 
 using namespace Polycode;
 
@@ -16,6 +17,36 @@ for(int i = 0; i < SourceSize; ++i)
 Dest[i] = (char)Source[i];
 }
 
+static void OpenConsole()
+{
+    int outHandle, errHandle, inHandle;
+    FILE *outFile, *errFile, *inFile;
+    AllocConsole();
+    CONSOLE_SCREEN_BUFFER_INFO coninfo;
+    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
+    coninfo.dwSize.Y = 9999;
+    SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
+
+    outHandle = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
+    errHandle = _open_osfhandle((long)GetStdHandle(STD_ERROR_HANDLE),_O_TEXT);
+    inHandle = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE),_O_TEXT );
+
+    outFile = _fdopen(outHandle, "w" );
+    errFile = _fdopen(errHandle, "w");
+    inFile =  _fdopen(inHandle, "r");
+
+    *stdout = *outFile;
+    *stderr = *errFile;
+    *stdin = *inFile;
+
+    setvbuf( stdout, NULL, _IONBF, 0 );
+    setvbuf( stderr, NULL, _IONBF, 0 );
+    setvbuf( stdin, NULL, _IONBF, 0 );
+
+    std::ios::sync_with_stdio();
+
+}
+
 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
 {
 	
@@ -60,6 +91,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
 	player->addEventListener(view, PolycodeDebugEvent::EVENT_ERROR);
 	player->addEventListener(view, PolycodeDebugEvent::EVENT_PRINT);
 
+	OpenConsole();
 
 	player->runPlayer();
 

+ 3 - 4
Player/Contents/Source/PolycodePlayer.cpp

@@ -481,6 +481,7 @@ PolycodeDebugEvent::~PolycodeDebugEvent() {
 
 PolycodePlayer::PolycodePlayer(String fileName, bool knownArchive, bool useDebugger) : EventDispatcher()  {
 	L = NULL;
+	remoteDebuggerClient = NULL;
 
 	crashed = false;
 	doCodeInject = false;
@@ -669,7 +670,7 @@ void PolycodePlayer::loadFile(const char *fileName) {
 	
 	Logger::log("Core created...\n");
 
-	CoreServices::getInstance()->getResourceManager()->addArchive("UIThemes.pak");
+	CoreServices::getInstance()->getResourceManager()->addArchive("UIThemes.zip");
 	CoreServices::getInstance()->getConfig()->loadConfig("Polycode", "UIThemes/default/theme.xml");
 	
 	CoreServices::getInstance()->getResourceManager()->addArchive("api.pak");
@@ -720,9 +721,7 @@ void PolycodePlayer::loadFile(const char *fileName) {
 		fullPath += mainFile;	
 		Logger::log(fullPath.c_str());
 	}
-	
-	remoteDebuggerClient = NULL;
-	
+
 	if(useDebugger) {