#pragma once

#ifndef __gx_effect_h__
	#define __gx_effect_h__

#include "foundation.h"
#include "graphicsresource.h"
#include "gxopengl.h"

#include "foundation/PxVec2.h"
#include "foundation/PxVec3.h"
#include "foundation/PxVec4.h"
#include "foundation/PxMat44.h"

#include <map>

namespace Gx
{
	class GX_API Effect : public GraphicsResource
	{
	public:
		Effect();
		virtual ~Effect();

		void createFromSourceCode(const char* vertexCode, const char* fragmentCode);

		void setUniformParam(const std::string& name, bool param) {
			glUniform1i(this->getUniformLocation(name), (GLint)param);
		}

		void setUniformParam(const std::string& name, GLint param) {
			glUniform1i(this->getUniformLocation(name), param);
		}

		void setUniformParam(const std::string& name, GLuint param) {
			glUniform1ui(this->getUniformLocation(name), param);
		}

		void setUniformParam(const std::string& name, GLfloat param) {
			glUniform1f(this->getUniformLocation(name), param);
		}

		void setUniformParam(const std::string& name, const physx::PxVec2 param) {
			glUniform2fv(this->getUniformLocation(name), 1, &param.x);
		}

		void setUniformParam(const std::string& name, const physx::PxVec3& param) {
			glUniform3fv(this->getUniformLocation(name), 1, &param.x);
		}

		void setUniformParam(const std::string& name, const physx::PxVec4& param) {
			glUniform4fv(this->getUniformLocation(name), 1, &param.x);
		}

		void setUniformParam(const std::string& name, const physx::PxMat33& param) {
			glUniformMatrix3fv(this->getUniformLocation(name), 1, GL_FALSE, param.front());
		}

		void setUniformParam(const std::string& name, const physx::PxMat44& param) {
			glUniformMatrix4fv(this->getUniformLocation(name), 1, GL_FALSE, param.front());
		}

		void bind() {
			glUseProgram(m_program);
		}

		void unbind() {
			glUseProgram(0);
		}

	private:
		GLint getUniformLocation(const std::string& name);

	private:
		GLuint m_program;
		std::map<std::string, GLint> m_uniforms;
	};
}

#endif /* __gx_effect_h__ */