/*
---------------------------------------------------------------------------
Direct3D AssimpRenderer by ponx
---------------------------------------------------------------------------

This code is heavily based on the "AssimpView" project of the Open Asset Import Library (ASSIMP).
http://assimp.sourceforge.net

/*
---------------------------------------------------------------------------
Open Asset Import Library (ASSIMP)
---------------------------------------------------------------------------

Copyright (c) 2006-2008, 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 "StdAfx.h"

#include <assimp.hpp>
#include <assimp.h>
#include <aiScene.h>        // root structure of the imported data
#include <aiMesh.h>
#include <aiPostProcess.h>
#include <DefaultLogger.h>

#include "AssimpRenderer.h"
#include "AssetHelper.h"
#include "Shaders.h"
#include "MaterialManager.h"
#include "MeshRenderer.h"

#define PI 3.1415926
#define DEGTORAD(Deg) ((Deg * PI) / 180.0)
#define RADTODEG(Rad) ((180.0 * Rad) / PI)

namespace AssimpRendererD3d
{

	AssimpRenderer* AssimpRenderer::sInstance = NULL;

	AssimpRenderer::AssimpRenderer(void)
	{
		d3d	= NULL;
		d3ddev = NULL;		
		gDefaultVertexDecl = NULL;
		g_piDefaultEffect = NULL;
		g_piPassThroughEffect = NULL;
		g_piPatternEffect = NULL;

		// read out the current directory to set the applicationBaseDirectory
		WCHAR buffer[MAX_PATH];
		DWORD len = GetCurrentDirectory(sizeof(buffer), buffer);

		assert(len);
		assert(len < MAX_PATH - 50);

		applicationBaseDirectory = new WCHAR[len+2];
		wcscpy_s(applicationBaseDirectory, len+2, buffer);
	}

	AssimpRenderer::~AssimpRenderer(void)
	{
	}


	/**
	* Returns the AssimpRenderer Instance (Singleton)
	*/
	AssimpRenderer* AssimpRenderer::Instance()
	{
		if (AssimpRenderer::sInstance == NULL)
		{
			AssimpRenderer::sInstance = new AssimpRenderer();
		}

		return AssimpRenderer::sInstance;
	}



	/// Have the AssimpRenderer create your Direct3D Device object.
	/** The AssimpRenderer Instance will use the this D3d Device for every rendering operation. In this version it's not yet 
	* possible to create the d3ddevice object somewhere else and have it passed to the AssimpRenderer. Therefore it's 
	* mandatory to call this method before you can use the AssimpRenderer. 
	* @param d3d pointer to your IDirect3D9 Interface
	* @param d3dpp Direct3D Presentation parameters for the Direct3D Device to be created. The object will be altered within the call. 
	* Make sure to set the following values:				
	*         -# d3dpp.BackBufferWidth and d3dpp.BackBufferHeight to match the desired screen or window size
	*		  -# set d3dpp.hDeviceWindow to true to run in windowed mode
	*		  -# set d3dpp.hDeviceWindow to your gamescreen's hWnd
	* @param gameWindow the structure containing the screen dimensions and a window handle
	* @param renderOptions the global rendering settings for all Assets
	* @return pointer to the d3d device
	*/
	LPDIRECT3DDEVICE9 AssimpRenderer::CreateD3dDevice(LPDIRECT3D9 d3d, D3DPRESENT_PARAMETERS* d3dpp, const RenderOptions& renderOptions)
	{
		int rc = 0; 
		this->d3d = d3d;
		this->d3dpp = d3dpp;
		this->renderOptions = renderOptions;

		rc = CreateD3dDevice(renderOptions.bMultiSample, true);
		if (rc)
			return this->d3ddev;
		else 
		{
			MessageBox(d3dpp->hDeviceWindow, L"AssimpRenderer failed to create Direct3D Device !",L"HLSL",MB_OK);
			return NULL;
		}
	}


	int AssimpRenderer::CreateD3dDevice(bool p_bMultiSample, bool useHardware /*= true*/)
	{

		D3DDEVTYPE eType = useHardware ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF;

		//ZeroMemory(&d3dpp, sizeof(d3dpp));;

		// get the current display mode
		D3DDISPLAYMODE sMode;
		d3d->GetAdapterDisplayMode(0,&sMode);

		// check whether we can use a D32 depth buffer format
		if (SUCCEEDED ( d3d->CheckDepthStencilMatch(0,eType,
			D3DFMT_X8R8G8B8,D3DFMT_X8R8G8B8,D3DFMT_D32)))
		{
			d3dpp->AutoDepthStencilFormat = D3DFMT_D32;
		}
		else 
			d3dpp->AutoDepthStencilFormat = D3DFMT_D24X8;            // war: D3DFMT_D24X8

		// find the highest multisample type available on this device    
		D3DMULTISAMPLE_TYPE sMS = D3DMULTISAMPLE_2_SAMPLES;
		D3DMULTISAMPLE_TYPE sMSOut = D3DMULTISAMPLE_NONE;
		DWORD dwQuality = 0;
		if (p_bMultiSample)
		{
			while ((D3DMULTISAMPLE_TYPE)(D3DMULTISAMPLE_16_SAMPLES + 1)  != 
				(sMS = (D3DMULTISAMPLE_TYPE)(sMS + 1)))
			{
				if(SUCCEEDED( d3d->CheckDeviceMultiSampleType(0,eType,
					sMode.Format,TRUE,sMS,&dwQuality)))
				{
					sMSOut = sMS;
				}
			}
			if (0 != dwQuality)dwQuality -= 1;


			d3dpp->MultiSampleQuality = dwQuality;
 			d3dpp->MultiSampleType = sMSOut;
		}    

		DWORD creationFlags = 0;

		// preget the device capabilities. If the hardware vertex shader is too old,6 we prefer software vertex processing
		d3d->GetDeviceCaps( 0, D3DDEVTYPE_HAL, &g_sCaps);

		// -----
		// übernommen aus PIXGameDebugging.cpp :

		// Debugging vertex shaders requires either REF or software vertex processing 
		// and debugging pixel shaders requires REF.  
	#ifdef DEBUG_VS
		if( g_sCaps.DeviceType != D3DDEVTYPE_REF )
		{
			creationFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
			creationFlags &= ~D3DCREATE_PUREDEVICE;
			creationFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
		}
	#endif
	#ifdef DEBUG_PS
		creationFlags = D3DDEVTYPE_REF;
	#endif

		// -----

#if !defined(DEBUG_VS) && !defined(DEBUG_PS)		
		creationFlags &= D3DCREATE_MULTITHREADED;					/// wieder rein !
		if( g_sCaps.VertexShaderVersion >= D3DVS_VERSION( 2, 0))
			creationFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
		else
		
			creationFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
#endif

		// create the D3D9 device object. with software-vertexprocessing if VS2.0 isn`t supported in hardware     
		int returnCode = 0;
		returnCode = d3d->CreateDevice(0,eType, d3dpp->hDeviceWindow, creationFlags, d3dpp, &d3ddev);    
		//char* errorString = DXGetErrorString9 (returnCode);			// gibt das Makro des Fehlers zurück, also zB. D3DERROR_INVALIDDATA
		const WCHAR* errorString = DXGetErrorDescription9(returnCode);			// gibt den Fehler im Klartext zurück (so weit ich ausprobiert hab, auch nicht viel mehr info, "Invalid Data" z.B.)
		if(FAILED(returnCode))
		{
			// if hardware fails use software rendering instead
			if (useHardware)return CreateD3dDevice(p_bMultiSample, false);
			return 0;
		}


		// create a vertex declaration to match the vertex
		D3DVERTEXELEMENT9* vdecl = AssimpRendererD3d::AssetHelper::Vertex::GetDeclarationElements();
		if( FAILED( d3ddev->CreateVertexDeclaration( vdecl, &gDefaultVertexDecl)))
		{
			MessageBox( d3dpp->hDeviceWindow, L"Failed to create vertex declaration", L"Init", MB_OK);
			return 0;
		}
		d3ddev->SetVertexDeclaration( gDefaultVertexDecl);

		// get the capabilities of the device object
		d3ddev->GetDeviceCaps(&g_sCaps);
		if(g_sCaps.PixelShaderVersion < D3DPS_VERSION(3,0))
		{
			EnableWindow(GetDlgItem(d3dpp->hDeviceWindow,1020),FALSE);
		}

		// compile the default material shader (gray gouraud/phong)
		ID3DXBuffer* piBuffer = NULL;
		if(FAILED( D3DXCreateEffect(d3ddev,
			AssimpRendererD3d::AiToDxShaders::g_szDefaultShader.c_str(),
			(UINT)AssimpRendererD3d::AiToDxShaders::g_szDefaultShader.length(),
			NULL,
			NULL,
			D3DXSHADER_USE_LEGACY_D3DX9_31_DLL,
			NULL,
			&g_piDefaultEffect,&piBuffer)))
		{
			if( piBuffer) 
			{
				MessageBox(d3dpp->hDeviceWindow,CA2W((LPCSTR)piBuffer->GetBufferPointer()), L"HLSL",MB_OK);
				piBuffer->Release();
			}
			return 0;
		}
		if( piBuffer) 
		{
			piBuffer->Release();
			piBuffer = NULL;
		}

		// use Fixed Function effect when working with shaderless cards
		if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
			g_piDefaultEffect->SetTechnique( "DefaultFXSpecular_FF");


		// ---
		// PNX: Kann weg, richtig ?
		// create the shader used to draw the HUD
		if(FAILED( D3DXCreateEffect(d3ddev,
			AssimpRendererD3d::AiToDxShaders::g_szPassThroughShader.c_str(),(UINT)AssimpRendererD3d::AiToDxShaders::g_szPassThroughShader.length(),
			NULL,NULL,D3DXSHADER_USE_LEGACY_D3DX9_31_DLL,NULL,&g_piPassThroughEffect,&piBuffer)))
		{
			if( piBuffer) 
			{
				MessageBox(d3dpp->hDeviceWindow,CA2W((LPCSTR)piBuffer->GetBufferPointer()),L"HLSL",MB_OK);
				piBuffer->Release();
			}
			return 0;
		}
		if( piBuffer) 
		{
			piBuffer->Release();
			piBuffer = NULL;
		}
		// ----

		// use Fixed Function effect when working with shaderless cards
		if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
			g_piPassThroughEffect->SetTechnique( "PassThrough_FF");

		if( piBuffer) 
		{
			piBuffer->Release();
			piBuffer = NULL;
		}

		return 1;
	}


	// rendert eine aiNode.
	// 
	//  piMatrix: die 4x4 transform matrix, world transform
	//
	int AssimpRenderer::RenderNode(const AssetHelper& g_pcAsset, aiNode* piNode, const aiMatrix4x4& piMatrix, bool bAlpha)
	{
		//PNX: TODO: die Zeile hier muss ggf wieder rein.. ?
		//aiMatrix4x4 aiMe = g_pcAsset->mAnimator->GetGlobalTransform( piNode->mName.data);
		aiMatrix4x4 aiMe;

		//aiMe.Transpose();
		aiMe *= piMatrix;

		bool bChangedVM = false;

		//------------------------------------
		// TODO: kann wech ?
		/*
		if (VIEWMODE_NODE == this->m_iViewMode && this->m_pcCurrentNode)
		{
			if (piNode != this->m_pcCurrentNode->psNode)
			{
				// directly call our children
				for (unsigned int i = 0; i < piNode->mNumChildren;++i)
				{
					RenderNode(piNode->mChildren[i],piMatrix,bAlpha );
				}
				return 1;
			}
			this->m_iViewMode = VIEWMODE_FULL;
			bChangedVM = true;
		}
		*/
		//-----------------------------------------



		aiMatrix4x4 pcProj;
		GetProjectionMatrix(pcProj);

		aiMatrix4x4 pcCam;

		GetCameraMatrix(pcCam);
		aiVector3D vPos = AssimpRendererD3d::AssimpRenderer::Instance()->m_Camera.vPos;

		//pcProj = (aiMe * pcCam) * pcProj;

		//pcCam = aiMe;
		//pcCam.Inverse().Transpose();


		if (true)        // ! (!g_sOptions.bRenderMats && bAlpha))
		{

			//ostringstream out;
			//out << "piNode->mNumMeshes=" << piNode->mNumMeshes;
			//WriteLog(out.str());

			for (unsigned int i = 0; i < piNode->mNumMeshes; ++i)
			{				
				AssetHelper::MeshHelper* helper = g_pcAsset.apcMeshes[piNode->mMeshes[i]];

				// fix: Render triangle meshes only
				if (helper->primitiveTypes != aiPrimitiveType_TRIANGLE)					
				    continue;

				// don't render the mesh if the render pass is incorrect
				if (helper->piOpacityTexture || helper->fOpacity != 1.0f)
				{
					if (!bAlpha)
						continue;
				}
				else if (bAlpha)
					continue;

				// Upload bone matrices. This maybe is the wrong place to do it, but for the heck of it I don't understand this code flow
				
				/* TODO: PNX: das mit den Bones kommt später ...

				if( mesh->HasBones())
				{
				if( helper->piEffect)
				{
				static float matrices[4*4*60];
				float* tempmat = matrices;
				const std::vector<aiMatrix4x4>& boneMats = g_pcAsset->mAnimator->GetBoneMatrices( piNode, i);
				ai_assert( boneMats.size() == mesh->mNumBones);

				for( unsigned int a = 0; a < mesh->mNumBones; a++)
				{
				const aiMatrix4x4& mat = boneMats[a];
				*tempmat++ = mat.a1; *tempmat++ = mat.a2; *tempmat++ = mat.a3; *tempmat++ = mat.a4;  
				*tempmat++ = mat.b1; *tempmat++ = mat.b2; *tempmat++ = mat.b3; *tempmat++ = mat.b4;
				*tempmat++ = mat.c1; *tempmat++ = mat.c2; *tempmat++ = mat.c3; *tempmat++ = mat.c4; 
				*tempmat++ = mat.d1; *tempmat++ = mat.d2; *tempmat++ = mat.d3; *tempmat++ = mat.d4; 
				//tempmat += 4;
				}

				if( g_sOptions.bRenderMats)
				{
				helper->piEffect->SetMatrixTransposeArray( "gBoneMatrix", (D3DXMATRIX*)matrices, 60);
				} else
				{
				g_piDefaultEffect->SetMatrixTransposeArray( "gBoneMatrix", (D3DXMATRIX*)matrices, 60);
				g_piDefaultEffect->CommitChanges();
				}
				}
				}
				*/


				// now setup the material

				CMaterialManager::Instance().SetupMaterial( helper, pcProj, aiMe, pcCam, vPos, g_pcAsset);

				//DxWrapper::Instance()->d3ddev->SetVertexDeclaration( gDefaultVertexDecl);

				if (bAlpha)
				{
					//TODO: PNX: DrawSorted() is not yet tested and needs some more data from aiMesh to be serialized.
					// For now, draw it opaque.
					//CMeshRenderer::Instance().DrawSorted(&g_pcAsset, piNode->mMeshes[i],aiMe);
					CMeshRenderer::Instance().DrawUnsorted(&g_pcAsset, piNode->mMeshes[i]);

					//DxWrapper::LogWrite("DrawSorted");
				}
				else 
				{
					CMeshRenderer::Instance().DrawUnsorted(&g_pcAsset, piNode->mMeshes[i]);
					//WriteLog("DrawUnsorted");
				}

				// now end the material        
				CMaterialManager::Instance().EndMaterial( helper);
			}
		}

		// render all child nodes
		for (unsigned int i = 0; i < piNode->mNumChildren;++i)
		{
			RenderNode(g_pcAsset, piNode->mChildren[i],piMatrix,bAlpha );
		}

		return 1;
	}


	/** Sets the AssimpRenderer's position of the Camera.
	*/
	void AssimpRenderer::SetCamera(const AssimpRendererD3d::Camera& sourceCamera)
	{
		m_Camera = sourceCamera;
	}


	/// Imports the Asset file with the given filename.
	/** This method creates a new AssetHelper object and returns a pointer to it. The caller is responsible to release the object.	// @param pFile
	// @param aiProcessFlags - aiProcess flags ORed together. Please have a look at the Assimp documentation for the list of aiProcess flags.
	// @return pointer to an AssetHelper
	*/
	AssetHelper* AssimpRenderer::ImportAsset(const char* pFile, unsigned int aiProcessFlags)
	{
		return ImportAssetInternal(pFile, aiProcessFlags, NULL);
	}


	/// Imports the Asset file with the given filename.
	/** This method creates a new AssetHelper object and returns a pointer to it. The caller is responsible to release the object.
	// @param pFile
	// @param aiProcessFlags - aiProcess flags ORed together. Please have a look at the Assimp documentation for the list of aiProcess flags.
	// @param matTransform - pass a transformation matrix to have each vertex transformed upon import. Use AssimpRenderer::CreateTransformationMatrix() for this. 
	// @return pointer to an AssetHelper
	*/
	AssetHelper* AssimpRenderer::ImportAsset(const char* pFile, unsigned int aiProcessFlags, const D3DXMATRIX& matTransform)
	{
		return ImportAssetInternal(pFile, aiProcessFlags, &matTransform);
	}


	AssetHelper* AssimpRenderer::ImportAssetInternal(const char* pFile, unsigned int aiImportFlags, const D3DXMATRIX* matTransform)
	{
		Assimp::DefaultLogger::get()->info("hello AssimpRenderer");

		//create an instance of the Importer class
		Assimp::Importer importer;

		// Remove allline and point meshes from the import
		aiSetImportPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,
			aiPrimitiveType_LINE | aiPrimitiveType_POINT);

		AssetHelper* g_pcAsset = new AssimpRendererD3d::AssetHelper();

		// read out the current directory
		WCHAR bufferCurrentDirectory[MAX_PATH];
		DWORD len = GetCurrentDirectory(sizeof(bufferCurrentDirectory), bufferCurrentDirectory);

		g_pcAsset->g_szFileName.Clear();
		g_pcAsset->g_szFileName.Append(CW2A(bufferCurrentDirectory));	

		g_pcAsset->g_szFileName.Append("\\");

		CMaterialManager::Instance().currentFilePath = aiString(g_pcAsset->g_szFileName);
		g_pcAsset->g_szFileName.Append(pFile);


		//DxWrapper::Instance()->LogWrite("-- starting aiImportFile --");

		//and have it read the given file
		g_pcAsset->pcScene = (aiScene*) aiImportFile( g_pcAsset->g_szFileName.data, aiImportFlags); 


		//     const char* debugstring = aiGetErrorString();
		//     WriteLog(debugstring);


		// multiply each vertice with the given matrix
		if (matTransform)
		{
			for (unsigned int iMesh=0; iMesh < g_pcAsset->pcScene->mNumMeshes; iMesh++)
			{
				aiMesh* mesh = g_pcAsset->pcScene->mMeshes[iMesh];
				for (unsigned int iv=0; iv < mesh->mNumVertices; iv++)
				{
					aiVector3D* aiVecPos = &mesh->mVertices[iv];
					/*
					ostringstream ostr1, ostr2;
					ostr1 << "transforming vector " << iv <<" x=" << aiVecPos->x << " y=" << aiVecPos->y << " z=" << aiVecPos->z;
					DxWrapper::Instance()->LogWrite(ostr1.str());
					*/
					TransformVector(aiVecPos, *matTransform);
					/*
					ostr2 << "transformed vector " << iv << " x=" << aiVecPos->x << " y=" << aiVecPos->y << " z=" << aiVecPos->z;
					DxWrapper::Instance()->LogWrite(ostr2.str());
					*/
				}
			}
		}

		//DxWrapper::Instance()->LogWrite("-- start creating asset data --");

		// build native D3D vertex/index buffers, textures, materials    
		if( 1 != CreateAssetData(g_pcAsset, g_pcAsset->pcScene))
			return NULL;

		//AiToDx_SerializeAssetData();

		//DxWrapper::Instance()->LogWrite("-- done creating asset data --");
		SetCurrentDirectory(bufferCurrentDirectory);		// reset the current directory to the previous state

		return g_pcAsset;
	}




	/*-------------------------------------------------------------------------------
	// Create the native D3D representation of the asset: vertex buffers,
	// index buffers, materials ...
	//-------------------------------------------------------------------------------
	*/
	int AssimpRenderer::CreateAssetData(AssimpRendererD3d::AssetHelper* assetHelper, const aiScene* pScene)
	{
		if (!assetHelper || !pScene)
			return 0;

		// reset all subsystems
		CMaterialManager::Instance().Reset();
		CMeshRenderer::Instance().Reset();

		//TODO: kann weg ? 
		//CDisplay::Instance().Reset();

		//DxWrapper* dxw = DxWrapper::Instance();
		//dxw->LogWrite("applicationBaseDirectory following next line:");
		//dxw->LogWrite(std::string(CW2A(dxw->applicationBaseDirectory)));

		assetHelper->apcMeshes = new AssetHelper::MeshHelper*[pScene->mNumMeshes]();
		assetHelper->numMeshes = pScene->mNumMeshes;

		for (unsigned int meshIndex = 0; meshIndex < pScene->mNumMeshes; ++meshIndex)
		{


			assetHelper->apcMeshes[meshIndex] = new AssetHelper::MeshHelper();  

			AssetHelper::MeshHelper* meshHelper = assetHelper->apcMeshes[meshIndex];      //PNX: store current meshhelper for convenience

			const aiMesh* assimpMesh = pScene->mMeshes[meshIndex];

			//PNX: the MeshHelper needs to store the number of vertices for serialization
			meshHelper->numVertices = assimpMesh->mNumVertices;
			meshHelper->numFaces = assimpMesh->mNumFaces;
			meshHelper->primitiveTypes = assimpMesh->mPrimitiveTypes;

			// create the material for the mesh
			if (!meshHelper->piEffect)
			{
				CMaterialManager::Instance().CreateMaterial(assetHelper, meshHelper,assimpMesh);
			}

			if (assimpMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
			{
				continue;
			}

			meshHelper->indexBufferLength = assimpMesh->mNumFaces * 3;


			// create local vertex buffer
			meshHelper->vertexBuffer = new AssetHelper::Vertex[meshHelper->numVertices];

			DWORD dwUsage = 0;
			if (meshHelper->piOpacityTexture || 1.0f != meshHelper->fOpacity)
				dwUsage |= D3DUSAGE_DYNAMIC;


			// PNX: create and fill the local index buffer
			meshHelper->indexBuffer = new unsigned int[meshHelper->indexBufferLength];
			unsigned int* pIndexBufferLocal = meshHelper->indexBuffer;
			for (unsigned int x = 0; x < assimpMesh->mNumFaces;++x)
			{
				for (unsigned int a = 0; a < 3;++a)
				{
					*pIndexBufferLocal++ = assimpMesh->mFaces[x].mIndices[a];
				}
			}

			// collect weights on all vertices. Quick and careless
			std::vector<std::vector<aiVertexWeight> > weightsPerVertex( assimpMesh->mNumVertices);
			for( unsigned int a = 0; a < assimpMesh->mNumBones; a++)
			{
				const aiBone* bone = assimpMesh->mBones[a];
				for( unsigned int b = 0; b < bone->mNumWeights; b++)
					weightsPerVertex[bone->mWeights[b].mVertexId].push_back( aiVertexWeight( a, bone->mWeights[b].mWeight));
			}


			// now fill the vertex buffer
			AssetHelper::Vertex* pbData2; 


			//meshHelper->piVB->Lock(0,0,(void**)&pbData2,0);
			pbData2 = meshHelper->vertexBuffer;

			//AssetHelper::Vertex* pbDataStart = pbData2; // TEST: store pointer for test reload

			for (unsigned int x = 0; x < assimpMesh->mNumVertices;++x)
			{
				pbData2->vPosition = assimpMesh->mVertices[x];

				if (NULL == assimpMesh->mNormals)
					pbData2->vNormal = aiVector3D(0.0f,0.0f,0.0f);
				else pbData2->vNormal = assimpMesh->mNormals[x];

				if (NULL == assimpMesh->mTangents)
				{
					pbData2->vTangent = aiVector3D(0.0f,0.0f,0.0f);
					pbData2->vBitangent = aiVector3D(0.0f,0.0f,0.0f);
				}
				else 
				{
					pbData2->vTangent = assimpMesh->mTangents[x];
					pbData2->vBitangent = assimpMesh->mBitangents[x];
				}

				if (assimpMesh->HasVertexColors( 0))
				{
					pbData2->dColorDiffuse = D3DCOLOR_ARGB(                    
						((unsigned char)max( min( assimpMesh->mColors[0][x].a * 255.0f, 255.0f),0.0f)),
						((unsigned char)max( min( assimpMesh->mColors[0][x].r * 255.0f, 255.0f),0.0f)),
						((unsigned char)max( min( assimpMesh->mColors[0][x].g * 255.0f, 255.0f),0.0f)),
						((unsigned char)max( min( assimpMesh->mColors[0][x].b * 255.0f, 255.0f),0.0f)));
				}
				else pbData2->dColorDiffuse = D3DCOLOR_ARGB(0xFF,0xff,0xff,0xff);

				// ignore a third texture coordinate component
				if (assimpMesh->HasTextureCoords( 0))
				{
					pbData2->vTextureUV = aiVector2D(
						assimpMesh->mTextureCoords[0][x].x,
						assimpMesh->mTextureCoords[0][x].y);
				}
				else pbData2->vTextureUV = aiVector2D(0.5f,0.5f);

				if (assimpMesh->HasTextureCoords( 1))
				{
					pbData2->vTextureUV2 = aiVector2D(
						assimpMesh->mTextureCoords[1][x].x,
						assimpMesh->mTextureCoords[1][x].y);
				}
				else pbData2->vTextureUV2 = aiVector2D(0.5f,0.5f);

				// Bone indices and weights
				if( assimpMesh->HasBones())
				{
					unsigned char boneIndices[4] = { 0, 0, 0, 0 };
					unsigned char boneWeights[4] = { 0, 0, 0, 0 };
					ai_assert( weightsPerVertex[x].size() <= 4);
					for( unsigned int a = 0; a < weightsPerVertex[x].size(); a++)
					{
						boneIndices[a] = weightsPerVertex[x][a].mVertexId;
						boneWeights[a] = (unsigned char) (weightsPerVertex[x][a].mWeight * 255.0f);
					}

					memcpy( pbData2->mBoneIndices, boneIndices, sizeof( boneIndices));
					memcpy( pbData2->mBoneWeights, boneWeights, sizeof( boneWeights));
				} else
				{
					memset( pbData2->mBoneIndices, 0, sizeof( pbData2->mBoneIndices));
					memset( pbData2->mBoneWeights, 0, sizeof( pbData2->mBoneWeights));
				}

				++pbData2;
			}

			SendMeshDataToDx(meshHelper);

		}
		return 1;
	}



	/// Creates a transformation matrix for rotating and scaling an Asset upon import.
	/** Sometimes it may be necessary to rotate an Asset to a certain direction to match your game logic. To do Pass the returned D3DXMATRIX to ImportAsset(), if you
	// Method:    CreateTransformMatrix
	// FullName:  AssimpRendererD3d::AssimpRenderer::CreateTransformMatrix
	// Access:    public 
	// Returns:   D3DXMATRIX
	// Qualifier:
	// @param rotX rotate each vertex by this angle (degree)
	// @param rotY rotate each vertex by this angle (degree)
	// @param rotZ rotate each vertex by this angle (degree)
	// @param scaleFactor: have each vertex multiplied by this value to scale the Asset.
	// @return the transformation matrix to be passed to ImportAsset()
	*/
	D3DXMATRIX AssimpRenderer::CreateTransformMatrix(float rotX, float rotY, float rotZ, float scaleFactor)
	{
		using namespace std;

		D3DXMATRIX dxMatrix, dxMatrixRotX, dxMatrixRotY, dxMatrixRotZ;
		D3DXMatrixRotationX(&dxMatrixRotX, static_cast<float>(DEGTORAD(rotX )));
		D3DXMatrixRotationY(&dxMatrixRotY, static_cast<float>(DEGTORAD(rotY )));
		D3DXMatrixRotationZ(&dxMatrixRotZ, static_cast<float>(DEGTORAD(rotZ )));
		dxMatrix = scaleFactor * (dxMatrixRotX * dxMatrixRotY * dxMatrixRotZ);
		return dxMatrix;
	}


	/* this method sends the indexBuffer and vertexBuffer arrays stored in the
	* MeshHelper instance to the Graphics Card
	*/
	int AssimpRenderer::SendMeshDataToDx(AssetHelper::MeshHelper* meshHelper)
	{
		AssimpRenderer* assimpRenderer = AssimpRenderer::Instance();

		DWORD dwUsage = 0;
		if (meshHelper->piOpacityTexture || 1.0f != meshHelper->fOpacity)
			dwUsage |= D3DUSAGE_DYNAMIC;

		// check whether we can use 16 bit indices
		if (meshHelper->indexBufferLength >= 65536)
		{
			// create 32 bit index buffer
			if(FAILED( assimpRenderer->d3ddev->CreateIndexBuffer( 4 *
				meshHelper->indexBufferLength,
				D3DUSAGE_WRITEONLY | dwUsage,
				D3DFMT_INDEX32,
				D3DPOOL_DEFAULT, 
				&meshHelper->piIB,
				NULL)))
			{
				MessageBox(assimpRenderer->d3dpp->hDeviceWindow,L"Failed to create 32 Bit index buffer",
					L"ASSIMP Viewer Utility",MB_OK);
				return 2;
			}

			// now fill the index buffer            
			unsigned int* pIndexBufferDx;
			meshHelper->piIB->Lock(0,0,(void**)&pIndexBufferDx,0);
			for (unsigned int x = 0; x < meshHelper->indexBufferLength;++x)
			{

				*pIndexBufferDx++ = meshHelper->indexBuffer[x];
			}
		}
		else
		{
			// create 16 bit index buffer
			if(FAILED( assimpRenderer->d3ddev->CreateIndexBuffer( 2 *
				meshHelper->indexBufferLength,
				D3DUSAGE_WRITEONLY | dwUsage,
				D3DFMT_INDEX16,
				D3DPOOL_DEFAULT,
				&meshHelper->piIB,
				NULL)))
			{
				MessageBox(assimpRenderer->d3dpp->hDeviceWindow,L"Failed to create 16 Bit index buffer",
					L"ASSIMP Renderer",MB_OK);
				return 2;
			}

			// now fill the index buffer
			boost::uint16_t* pbData;
			meshHelper->piIB->Lock(0,0,(void**)&pbData,0);
			for (unsigned int x = 0; x < meshHelper->indexBufferLength;++x)
			{
				*pbData++ = (boost::uint16_t)meshHelper->indexBuffer[x];
			}
		}
		meshHelper->piIB->Unlock();


		// create the vertex buffer (directX)
		if(FAILED( assimpRenderer->d3ddev->CreateVertexBuffer(sizeof(AssimpRendererD3d::AssetHelper::Vertex) *
			meshHelper->numVertices,
			D3DUSAGE_WRITEONLY,
			0,
			D3DPOOL_DEFAULT, &meshHelper->piVB,NULL)))
		{
			MessageBox(assimpRenderer->d3dpp->hDeviceWindow, L"Failed to create vertex buffer",
				L"ASSIMP Renderer",MB_OK);
			return 2;
		}

		// fill the dx vertex buffer
		AssetHelper::Vertex* pbData2; 
		meshHelper->piVB->Lock(0,0,(void**)&pbData2,0);
		memcpy( pbData2, meshHelper->vertexBuffer, sizeof(AssetHelper::Vertex) * meshHelper->numVertices);
		meshHelper->piVB->Unlock();

		return 1;
	}



	int AssimpRenderer::GetProjectionMatrix(aiMatrix4x4& p_mOut)
	{    

		const float fFarPlane = 1000.0f;
		const float fNearPlane = 0.1f;
		const float fFOV = (float)(45.0 * 0.0174532925);

		const float s = 1.0f / tanf(fFOV * 0.5f);
		const float Q = fFarPlane / (fFarPlane - fNearPlane);

		RECT sRect;
		GetWindowRect(d3dpp->hDeviceWindow,&sRect);
		sRect.right -= sRect.left;
		sRect.bottom -= sRect.top;
		const float fAspect = (float)sRect.right / (float)sRect.bottom;

		p_mOut = aiMatrix4x4(
			s / fAspect, 0.0f, 0.0f, 0.0f,
			0.0f, s, 0.0f, 0.0f,
			0.0f, 0.0f, Q, 1.0f,
			0.0f, 0.0f, -Q * fNearPlane, 0.0f);
		return 1;
	}

	// stattdessen kann man wohl auch einfach transposen..?
	void AssimpRenderer::ConvertMatrixAiToDx(D3DXMATRIX& dxDest, const aiMatrix4x4& aiSource)
	{
		dxDest._11 = aiSource.a1;
		dxDest._12 = aiSource.a2;
		dxDest._13 = aiSource.a3;
		dxDest._14 = aiSource.a4;
		dxDest._21 = aiSource.b1;
		dxDest._22 = aiSource.b2;
		dxDest._23 = aiSource.b3;
		dxDest._24 = aiSource.b4;
		dxDest._31 = aiSource.c1;
		dxDest._32 = aiSource.c2;
		dxDest._33 = aiSource.c3;
		dxDest._34 = aiSource.c4;
		dxDest._41 = aiSource.d1;
		dxDest._42 = aiSource.d2;
		dxDest._43 = aiSource.d3;
		dxDest._44 = aiSource.d4;
	}

	// stattdessen kann man wohl auch einfach transposen..?
	void AssimpRenderer::ConvertMatrixDxToAi(aiMatrix4x4& aiDest, const D3DXMATRIX& dxSource)
	{
		aiDest.a1 = dxSource._11;
		aiDest.a2 = dxSource._12;
		aiDest.a3 = dxSource._13;
		aiDest.a4 = dxSource._14;
		aiDest.b1 = dxSource._21;
		aiDest.b2 = dxSource._22;
		aiDest.b3 = dxSource._23;
		aiDest.b4 = dxSource._24;
		aiDest.c1 = dxSource._31;
		aiDest.c2 = dxSource._32;
		aiDest.c3 = dxSource._33;
		aiDest.c4 = dxSource._34;
		aiDest.d1 = dxSource._41;
		aiDest.d2 = dxSource._42;
		aiDest.d3 = dxSource._43;
		aiDest.d4 = dxSource._44;
	}




	aiVector3D AssimpRenderer::GetCameraMatrix(aiMatrix4x4& p_mOut)
	{
		D3DXMATRIX dxMatLookAt;
		D3DXVECTOR3 vecCameraPos(m_Camera.vPos.x, m_Camera.vPos.y, m_Camera.vPos.z);
		D3DXVECTOR3 vecLookAtPos(m_Camera.vLookAt.x, m_Camera.vLookAt.y, m_Camera.vLookAt.z);

		D3DXMatrixLookAtLH(&dxMatLookAt,
			&vecCameraPos,                         // the camera position
			&vecLookAtPos,    // the look-at position
			&D3DXVECTOR3 (0.0f, 1.0f, 0.0f));    // the up direction

		ConvertMatrixDxToAi(p_mOut, dxMatLookAt);   
		return m_Camera.vPos;
	}


	/*
	aiVector3D AssimpRenderer::GetCameraMatrix(aiMatrix4x4& p_mOut)
	{
		D3DXMATRIX view;
		D3DXMatrixIdentity( &view );

		D3DXVec3Normalize( (D3DXVECTOR3*)&m_Camera.vLookAt, (D3DXVECTOR3*)&m_Camera.vLookAt );
		D3DXVec3Cross( (D3DXVECTOR3*)&m_Camera.vRight, (D3DXVECTOR3*)&m_Camera.vUp, (D3DXVECTOR3*)&m_Camera.vLookAt );
		D3DXVec3Normalize( (D3DXVECTOR3*)&m_Camera.vRight, (D3DXVECTOR3*)&m_Camera.vRight );
		D3DXVec3Cross( (D3DXVECTOR3*)&m_Camera.vUp, (D3DXVECTOR3*)&m_Camera.vLookAt, (D3DXVECTOR3*)&m_Camera.vRight );
		D3DXVec3Normalize( (D3DXVECTOR3*)&m_Camera.vUp, (D3DXVECTOR3*)&m_Camera.vUp );

		view._11 = m_Camera.vRight.x;
		view._12 = m_Camera.vUp.x;
		view._13 = m_Camera.vLookAt.x;
		view._14 = 0.0f;

		view._21 = m_Camera.vRight.y;
		view._22 = m_Camera.vUp.y;
		view._23 = m_Camera.vLookAt.y;
		view._24 = 0.0f;

		view._31 = m_Camera.vRight.z;
		view._32 = m_Camera.vUp.z;
		view._33 = m_Camera.vLookAt.z;
		view._34 = 0.0f;

		view._41 = -D3DXVec3Dot( (D3DXVECTOR3*)&m_Camera.vPos, (D3DXVECTOR3*)&m_Camera.vRight );
		view._42 = -D3DXVec3Dot( (D3DXVECTOR3*)&m_Camera.vPos, (D3DXVECTOR3*)&m_Camera.vUp );
		view._43 = -D3DXVec3Dot( (D3DXVECTOR3*)&m_Camera.vPos, (D3DXVECTOR3*)&m_Camera.vLookAt );
		view._44 =  1.0f;

		memcpy(&p_mOut,&view,sizeof(aiMatrix4x4));

		return m_Camera.vPos;
		
	}
	*/


	//---------------------------------------------------------
	// SERIALIZATION
	//---------------------------------------------------------


	/// Creates an AssetHelper object from a file that has been created using SaveAssetToFile()
	/**	
	// @param filename path of the file to load
	// @return a pointer to the newly created AssetHelper object. The caller is responsible to release the object.
	//************************************
	*/
	AssetHelper* AssimpRenderer::LoadAssetFromFile(aiString filename )
	{		
		//DxWrapper::Instance()->LogWrite("starting LoadAssetHelperFromFile");

		AssetHelper* assetHelper = new AssimpRendererD3d::AssetHelper();		

		std::string strFileName(filename.data);

		std::fstream inp;

		inp.open(filename.data, std::ifstream::in);
		inp.close();
		if(inp.fail())
		{
			std::wstringstream wstr;
			std::string currentDir = GetCurrentDir();
			wstr << "Serialized AssetHelper file " << filename.data << " not found at\n" << currentDir.c_str() << std::endl;
			MessageBox(d3dpp->hDeviceWindow, wstr.str().c_str(), L"ASSIMP Renderer",MB_OK);
		}


		WCHAR bufferCurrentDirectory[MAX_PATH];
		DWORD len = GetCurrentDirectory(sizeof(bufferCurrentDirectory), bufferCurrentDirectory);

		aiString path;
		path.Append(CW2A(bufferCurrentDirectory));

		// the MaterialManager needs the absolute path. Therefore we check if the filename contains a subdirectory.
		// If so, we add the subdir to the CurrentFilePath to construct the absolute path. (getestet und funzt)
		size_t pathIndex = strFileName.find_last_of('/');
		if (pathIndex == std::string::npos)
		{
			pathIndex = strFileName.find_last_of('\\');
		}
		if (pathIndex != std::string::npos)
		{
			std::string subPath = strFileName.substr(0, pathIndex);
			path.Append("\\");
			path.Append(subPath.c_str());
			path.Append("\\");
		}


		// generate the absolute filepath and update the filepath of the material manager
		CMaterialManager::Instance().currentFilePath = path;

		assetHelper->g_szFileName.Append(filename.data);

		// deserialize:
		{
			std::ifstream ifs(filename.data, std::ios::binary);		// Standard stream i/o on some systems will expand linefeed characters to carriage-return/linefeed on output. This creates a problem for binary archives. The easiest way to handle this is to open streams for binary archives in "binary mode" by using the flag ios::binary. If this is not done, the archive generated will be unreadable. 
			//boost::archive::text_iarchive ia(ifs);
			boost::archive::binary_iarchive ia(ifs);
			ia >> *(assetHelper);
		}

		// now that the Asset is loaded, have DxWrapper load/create the textures and materials
		CMaterialManager& materialManager = CMaterialManager::Instance();
		for (unsigned int i=0; i < assetHelper->numMeshes; ++i)
		{
			AssimpRendererD3d::AssetHelper::MeshHelper* meshHelper = assetHelper->apcMeshes[i];

			if (meshHelper->piDiffuseTexture)
				meshHelper->piDiffuseTexture->Release();
			if (meshHelper->piDiffuseTexture2)
				meshHelper->piDiffuseTexture2->Release();
			if (meshHelper->piEmissiveTexture)
				meshHelper->piEmissiveTexture->Release();
			if (meshHelper->piOpacityTexture)
				meshHelper->piOpacityTexture->Release();
			if (meshHelper->piShininessTexture)
				meshHelper->piShininessTexture->Release();
			if (meshHelper->piSpecularTexture)
				meshHelper->piSpecularTexture->Release();
			if (meshHelper->piNormalTexture)
				meshHelper->piNormalTexture->Release();
			if (meshHelper->piEffect)
				meshHelper->piEffect->Release();

			materialManager.LoadDirect3DTexturesInMeshHelper(assetHelper, meshHelper);

			SendMeshDataToDx(meshHelper);
		}

		//DxWrapper::Instance()->LogWrite("done LoadAssetHelperFromFile()");

		return assetHelper;
	}


	/// Serializes the given AssetHelper to a file with the given filename.
	/**
	// @param asset the asset to store
	// @param aiString path of the file to create / replace
	// @return 0 if successful
	//************************************
	*/
	int AssimpRenderer::SaveAssetToFile(const AssetHelper& asset, aiString filename)
	{

		//DxWrapper::Instance()->LogWrite("starting SaveAssetHelperToFile()");

		//SetCurrentDirectory(DxWrapper::Instance()->applicationBaseDirectory);

		{
			std::ofstream ofs(filename.data, std::ios::binary);		// Standard stream i/o on some systems will expand linefeed characters to carriage-return/linefeed on output. This creates a problem for binary archives. The easiest way to handle this is to open streams for binary archives in "binary mode" by using the flag ios::binary. If this is not done, the archive generated will be unreadable. 

			//boost::archive::text_oarchive oa(ofs);
			boost::archive::binary_oarchive oa(ofs);
			oa << asset;
		}
		//DxWrapper::Instance()->LogWrite("done SaveAssetHelperToFile()");
		return 0;			//TODO: PNX: Fehler abfangen, returncodes definieren
	}

		
	// TODO: das hier geht sicher auch effektiver:
	void AssimpRenderer::TransformVector(aiVector3D* aiVec, const D3DXMATRIX& matrix)
	{
		D3DXVECTOR3 vecDxIn, vecDxOut;
		vecDxIn.x = aiVec->x;
		vecDxIn.y = aiVec->y;
		vecDxIn.z = aiVec->z;

		D3DXVec3TransformCoord(&vecDxOut, &vecDxIn, &matrix);
		aiVec->x = vecDxOut.x;
		aiVec->y = vecDxOut.y;
		aiVec->z = vecDxOut.z;
	}


	/// Renders an Asset.
	/** This method signature provides aiVector parameters for rendering the Asset at the given position, with a given rotation and scaling.
	*   @param vPos the position
	*	@param vRot the rotation in degrees
	*	@param vScale the scaling factors for each axis
	*/
	void AssimpRenderer::RenderAsset(const AssetHelper& assetHelper, const aiVector3D& vPos, const aiVector3D& vRot, const aiVector3D& vScale)
	{

		d3ddev->SetVertexDeclaration( gDefaultVertexDecl);

		aiMatrix4x4 matRotX, matRotY, matRotZ, matTranslate, matScaling, matScaleRotTrans;
		
		aiMatrix4x4::RotationX(static_cast<float>(DEGTORAD(-vRot.x)), matRotX);
		aiMatrix4x4::RotationY(static_cast<float>(DEGTORAD(-vRot.y)), matRotY);
		aiMatrix4x4::RotationZ(static_cast<float>(DEGTORAD(-vRot.z)), matRotZ);
		aiMatrix4x4::Translation(vPos, matTranslate);

		// aiMatrix4x4 benutzt Spaltenvektoren, und D3DXMATRIX Zeilenvektoren. D.h. wenn ich eine aiMatrix in eine d3dxmatrix
		// umrechnen will, muss ich die matrix transponieren. Transponieren heißt, die erste Spalte wird zur ersten Zeile, usw.
		// Entspricht einem Spiegeln an der Diagonalen.
		// Es reicht allerdings nicht, die Matrizen erst wie gewohnt in der bekannten Reihenfolge (skalieren, rotieren, translate)
		// aufeinander zu multiplizieren, und dann am Ende das Ergebnis zu transposen. Das hängt mit den Rechenregeln bei Matrizen-
		// multiplikation zusammen: (AB)^T = B^T A^T   - man beachte, dass sich die Reihenfolge der Multiplikation ändert !
		// Wenn man die "alte" Multiplikations-Reihenfolge also beibehalten will, muss man die Matrizen vorher einzeln transposen.

		matRotX.Transpose();
		matRotY.Transpose();
		matRotZ.Transpose();
		matTranslate.Transpose();

		matScaling.a1 = vScale.x;
		matScaling.b2 = vScale.y;
		matScaling.c3 = vScale.z;
		matScaling.Transpose();

		matScaleRotTrans = ((((matScaling * matRotX) * matRotY) * matRotZ) * matTranslate);

		RenderAsset(assetHelper, matScaleRotTrans);
	}



	/// Renders an Asset.
	/** This method renders an Asset using the given transpose matrix.
	*   @param matTranspose a matrix containing the scale, translation and rotation values for transposing the asset to world coordinates.
	*/
	void AssimpRenderer::RenderAsset(const AssetHelper& assetHelper, aiMatrix4x4 matTranspose)
	{

		// draw all opaque objects in the scene
		if (NULL != assetHelper.pcScene->mRootNode)
		{        
			RenderNode(assetHelper, assetHelper.pcScene->mRootNode, matTranspose, false);
		}

		// TODO: PNX: WIEDER REIN !!!   durchsichtige meshes werden noch nicht gerendert
		// -------
		// draw all non-opaque objects in the scene
		//if (NULL != m_Dxw->g_pcAsset && NULL != m_Dxw->g_pcAsset->pcScene->mRootNode)
		//{
		// disable the z-buffer
		//m_Dxw->d3ddev->SetRenderState(D3DRS_ZWRITEENABLE,FALSE);
		//m_Dxw->AiToDx_RenderNode(m_Dxw->g_pcAsset->pcScene->mRootNode, matAiPlayerWorld, true);
		//m_Dxw->d3ddev->SetRenderState(D3DRS_ZWRITEENABLE,TRUE);
		//}   
		//------------

		//std::ostringstream s(std::ostringstream::out);
		//PlayerCraft* e = m_Player;
		//s << "player->rotZ=" << e->m_RotZ << "player->speedX=" << e->m_Velocity.x << "\n" << "player->speedY=" << e->m_Velocity.y << std::endl;
		//s << "enemy->pos=" << e->m_Position.x << "," << e->m_Position.y << "\n";
		//m_Dxw->RenderTextS(s.str(), 100,300);
	}


	std::string AssimpRenderer::GetCurrentDir()
	{
		// read out the current directory to set the applicationBaseDirectory
		WCHAR buffer[MAX_PATH];
		DWORD len = GetCurrentDirectory(sizeof(buffer), buffer);

		std::string returnString = std::string(CW2A(buffer));


		return returnString;
	}

	/// Attaches a LogStream for receiving logging information from the AssimpRenderer.
	/** Assimp comes with a DefaultLogger class for receiving debug information from the Assimp library.
	* Party of this mechanism is the LogStream interface, where you can attach your own functionality
	* for handling debug information. If you already implemented this interface, you can pass the same
	* instance of your implementation to AssimpRenderer::AttachLogStream(), and have the debug info
	* from AssimpRenderer handled the same way.
	* @param logstr your implementation of the LogStream interface that comes with Assimp
	* @param severity the known flags from Logger class ORed together: Logger::DEBUGGING, Logger::INFO, Logger::WARN, Logger::ERR;
	*
	*/
	int AssimpRenderer::AttachLogStream( Assimp::LogStream* logstr, unsigned int severity )
	{
		Assimp::DefaultLogger::get()->attachStream(logstr, severity);
		return 0;
	}

	///
	int AssimpRenderer::DetachLogStream( Assimp::LogStream* logstr, unsigned int severity )
	{
		Assimp::DefaultLogger::get()->detatchStream(logstr, severity);
		return 0;
	}




} // namespace AssimpRendererD3d


// ----------------------------------
// BOOST SERIALIZATION
// ----------------------------------

namespace boost {
	namespace serialization {

		template<class Archive>
		void serialize(Archive & ar, aiVector2D & aiVec, const unsigned int version)
		{
			ar & aiVec.x;
			ar & aiVec.y;
		}


		template<class Archive>
		void serialize(Archive & ar, aiVector3D & aiVec, const unsigned int version)
		{
			ar & aiVec.x;
			ar & aiVec.y;
			ar & aiVec.z;
		}



		template<class Archive>
		void serialize(Archive & ar, aiString & aistr, const unsigned int version)
		{		
			// 			DxWrapper* dxw = DxWrapper::Instance();
			// 			dxw->LogWrite("serializing aiString");

			ar & aistr.length;

			for (size_t i=0; i < aistr.length+1; ++i)		// +1 um die /0 mitzukopieren
			{
				ar & aistr.data[i];
			}

		}

		template<class Archive>
		void serialize(Archive & ar, aiNode & node, const unsigned int version)
		{	
			// 			DxWrapper* dxw = DxWrapper::Instance();
			// 			aiString logMessage("serializing aiNode");
			//if (node.mName)
			//	logMessage.Append(node.mName.data);
			//else
			//	logMessage.Append("--NULL--");
			//dxw->LogWrite(logMessage.data);

			ar & node.mName;
			ar & node.mTransformation;
			ar & node.mParent;
			ar & node.mNumChildren;
			ar & node.mNumMeshes;

			if (!node.mMeshes)
			{
				node.mMeshes = new unsigned int[node.mNumMeshes];
			}

			for (unsigned int i=0; i<node.mNumMeshes; ++i)
			{
				ar & node.mMeshes[i];
			}

			// create children pointer array and init with zeroes
			if (!node.mChildren)
			{
				node.mChildren = new aiNode*[node.mNumChildren];
				for (unsigned int i=0; i<node.mNumChildren; ++i)
				{
					node.mChildren[i]=0;
				}
			}

			for (unsigned int i=0; i<node.mNumChildren; ++i)
			{
				if (!node.mChildren[i])
					node.mChildren[i] = new aiNode;

				ar & *node.mChildren[i];
			}

		}

		template<class Archive>
		void serialize(Archive & ar, aiMatrix4x4 & matrix, const unsigned int version)
		{
			// 			DxWrapper* dxw = DxWrapper::Instance();
			// 			dxw->LogWrite("serializing aiMatrix4x4");
			ar & matrix.a1;
			ar & matrix.b1;
			ar & matrix.c1;
			ar & matrix.d1;
			ar & matrix.a2;
			ar & matrix.b2;
			ar & matrix.c2;
			ar & matrix.d2;
			ar & matrix.a3;
			ar & matrix.b3;
			ar & matrix.c3;
			ar & matrix.d3;
			ar & matrix.a4;
			ar & matrix.b4;
			ar & matrix.c4;
			ar & matrix.d4;
		}

		template<class Archive>
		void serialize(Archive & ar, aiScene & scene, const unsigned int version)
		{
			// 			DxWrapper* dxw = DxWrapper::Instance();
			// 			dxw->LogWrite("serializing aiScene");

			ar & scene.mNumMeshes;
			ar & scene.mRootNode;
		}

		template<class Archive>
		void serialize(Archive & ar, D3DXVECTOR4 & vec, const unsigned int version)
		{
			ar & vec.x;
			ar & vec.y;
			ar & vec.z;
			ar & vec.w;
		}


	} // namespace serialization
} // namespace boost

