/*
/ MESH.H
/ ******
/ Handles the storage and rendering of a mesh
/ and its textures. This implementation is in the works
/ and changes frequently due to additions elsewhere
/ in the engine.
/
/ Will Beddow 2010 - http://343gs.com/brainstem
/
/ This software is currently under development
/ and is subject to change and improvement. Some
/ aspects of the system are incomplete and/or 
/ unstable due to ongoing implementation.
/
*/

#ifndef __MESH_H__
#define __MESH_H__

#include "Compile.h"
#include "Types.h"
#include "Texture.h"

#include "BstmDevice.h"

namespace Brainstem
{
	class IMesh : public IObject
	{
	public:
		IMesh() { Mesh = NULL; }
		IMesh(LPD3DXMESH mesh) { Mesh = mesh; }
		~IMesh() { }

		void Release()
		{
			if (Mesh != NULL)
			{
				WRITE_RELEASE(this);
				SAFE_RELEASE(Mesh);
			}

			for (DWORD i = 0; i < Textures.size(); i++) 
				SAFE_RELEASE(Textures[i])

			for (DWORD i = 0; i < NormalMaps.size(); i++) 
				SAFE_RELEASE(NormalMaps[i])

			Materials.clear();
			Textures.clear();
			NormalMaps.clear();
		}

		void Render() { Render((DWORD)0); }
		void Render(DWORD i) { Mesh->DrawSubset(i); }

		void Render(ID3DXEffect* effect)
		{
			if (effect == NULL)
			{
				Render();
				return;
			}

			if (Materials.size() <= 0)
			{
				for (DWORD i = 0; i < Textures.size(); i++) 
					SetTexture(i, effect);

				for (DWORD i = 0; i < NormalMaps.size(); i++) 
					SetNormalMap(i, effect);

				effect->CommitChanges();

				Render();
				return;
			}

			for (DWORD i = 0; i < Materials.size(); i++) 
			{
				Texture* textureData = (Texture*)((ITexture*)Textures[i]);
				Texture* normalData = (Texture*)((ITexture*)NormalMaps[i]);

				if (effect != NULL)
				{
					Material mtrl;
					mtrl.Ambient = /*Materials[i].Ambient;*/D3DXCOLOR(0.29225f, 0.29225f, 0.29225f, 1.0f);
					mtrl.Diffuse = Materials[i].Diffuse;
					mtrl.Emissive = Materials[i].Emissive;
					mtrl.Specular = Materials[i].Specular;
					mtrl.Shininess = Materials[i].Power;
				
					effect->SetValue("material", &mtrl, sizeof(Material));
				
					SetTexture(i, effect);
					SetNormalMap(i, effect);

					effect->CommitChanges();
				}

				Render(i);
			}
		}

		std::string ID;
		LPD3DXMESH Mesh;

		std::vector<D3DMATERIAL9> Materials;
		std::vector<IPtr<ITexture>> Textures;
		std::vector<IPtr<ITexture>> NormalMaps;

		BoundingVolume Bounds;

		AUTO_OBJECT_SIZE;
		const char* GetName() { return "Mesh"; }
	private:

		void SetTexture(int id, ID3DXEffect* effect)
		{
			Texture* textureData = (Texture*)((ITexture*)Textures[id]);

			if (Textures.at(id) != NULL)
				if (textureData->Data != NULL)
					effect->SetTexture("colorMapTexture", textureData->Data);
		}

		void SetNormalMap(int id, ID3DXEffect* effect)
		{
			Texture* normalData = (Texture*)((ITexture*)NormalMaps[id]);

			if (NormalMaps.at(id) != NULL)
				if (normalData->Data != NULL)
					effect->SetTexture("normalMapTexture", normalData->Data);
		}
	};
}

#endif