/*
 * RTMaterial.h
 *
 *  Created on: 22. 9. 2017
 *      Author: tonda
 */

#pragma once

#include "scenemanager.h"
#include "material.h"
#include "kernel.h"

namespace VRUT
{
	struct RTMaterial
	{
		enum RTMaterialProperties
		{
			VALID = 1,
			HAS_IOR = 2,
			HAS_TEXTURE = 4,
			HAS_BUMPMAPPING = 8,
			ALPHA_TEST = 16,
			TEX_GEN_FUNC_V_SPHERE = 32,
			TEX_UWRAP_CLAMP = 64,
			TEX_VWRAP_CLAMP = 128,
			TEX_MAG_FILTER_LINEAR = 256,
			TEX_ENV_INTERPOLATE = 512,
			TEX_ENV_MODULATE = 1024,
			TEX_ENV_REPLACE = 2048,
			TEX_ENV_DECAL = 4096,
			TEX_ENV_BLEND = 8192,
			TEX_ENV_ADD = 16384
		};
		Vector4 diffuse;
		Vector4 specular;
		Vector4 emission;
		float shininess;
		float reflectivityOrIOR;
		float bumpScale;
		float textureMix;
		unsigned int flags;
		const_smart_pointer<Image> texture;
		const_smart_pointer<Image> bumpTexture;
		RTMaterial() : shininess(0.0f), reflectivityOrIOR(0.0f), bumpScale(0.0f), textureMix(0.0f), flags(0) {}
		RTMaterial(Material *mat)
		{
			SetMaterial(mat);
		}
		void Invalidate()
		{
			flags &= (unsigned)~(unsigned(0)) ^ VALID;
		}
		bool IsValid()
		{
			return flags&VALID;
		}
		void SetMaterial(const Material *mat)
		{
			flags = VALID;
			if (!mat)
			{
				diffuse = Vector4(0.3f, 0.3f, 0.3f, 1.0f);
				specular = emission = Vector4();
				shininess = reflectivityOrIOR = bumpScale = 0.0f;
				texture.assign(nullptr);
				bumpTexture.assign(nullptr);
				return;
			}
			diffuse = mat->diffuse;
			specular = mat->specular;
			emission = mat->emission;
			shininess = mat->shininess;
			reflectivityOrIOR = mat->reflectivity;
			textureMix = mat->textureMix;
			if (mat->texFlags & Material::ALPHA_TEST)
				flags |= ALPHA_TEST;
			if (mat->texFlags & Material::TEX_GEN_FUNC_V_SPHERE)
				flags |= TEX_GEN_FUNC_V_SPHERE;
			if (FLAG2B(mat->texFlags, Material::TEX_UWRAP_CLAMP, Material::TEX_UWRAP_MASK))
				flags |= TEX_UWRAP_CLAMP;
			if (FLAG2B(mat->texFlags, Material::TEX_VWRAP_CLAMP, Material::TEX_UWRAP_MASK))
				flags |= TEX_VWRAP_CLAMP;
			if (FLAG2B(mat->texFlags, Material::TEX_MAG_FILTER_LINEAR, Material::TEX_MAG_MASK))
				flags |= TEX_MAG_FILTER_LINEAR;
			if (FLAG2B(mat->texFlags, Material::TEX_ENV_INTERPOLATE, Material::TEX_ENV_MASK))
				flags |= TEX_ENV_INTERPOLATE;
			if (FLAG2B(mat->texFlags, Material::TEX_ENV_MODULATE, Material::TEX_ENV_MASK))
				flags |= TEX_ENV_MODULATE;
			if (FLAG2B(mat->texFlags, Material::TEX_ENV_REPLACE, Material::TEX_ENV_MASK))
				flags |= TEX_ENV_REPLACE;
			if (FLAG2B(mat->texFlags, Material::TEX_ENV_DECAL, Material::TEX_ENV_MASK))
				flags |= TEX_ENV_DECAL;
			if (FLAG2B(mat->texFlags, Material::TEX_ENV_BLEND, Material::TEX_ENV_MASK))
				flags |= TEX_ENV_BLEND;
			if (FLAG2B(mat->texFlags, Material::TEX_ENV_ADD, Material::TEX_ENV_MASK))
				flags |= TEX_ENV_ADD;
			if (!mat->imageName.empty())
			{
				texture = KERNEL->sceneManager->GetImage(mat->imageName, false);
				if (texture)
					flags |= HAS_TEXTURE;
			}
			else
				texture.assign(nullptr);
			bumpTexture.assign(nullptr);
			if (mat->shader)
			{
				for (auto &param : mat->shader->paramList)
				{
					if (param.name == wxT("IOR"))
					{
						reflectivityOrIOR = param.fVals[0];
						flags |= HAS_IOR;
					}
					if (param.name.Lower() == wxT("bumpscale"))
						bumpScale = param.fVals[0];
					if (param.name.Lower() == wxT("bumptexture"))
					{
						bumpTexture = KERNEL->sceneManager->GetImage(param.imageName, false);
						if (bumpTexture)
							flags |= HAS_BUMPMAPPING;
					}
				}
			}
		}
	};
}
