/*
 *  psychlops_g_shader_fig.h
 *  Psychlops Standard Library (Universal)
 *
 *  Last Modified 2009/12/14 by Kenchi HOSOKAWA
 *  (C) 2009 Kenchi HOSOKAWA, Kazushi MARUYA and Takao SATO
 */

#ifndef HEADER_PSYCHLOPS_GRAPHIC_SHADER_FIGURES
#define HEADER_PSYCHLOPS_GRAPHIC_SHADER_FIGURES

#include "psychlops_g_shader.h"


namespace Psychlops {

	class ShaderInterface {
		public:
		enum Version { AUTO_DETECT, GLSL1_1 };
		static void reparseGLSL1_1(const std::string &source, std::string &result, std::vector<std::string> &args);
	};

namespace Figures {

	class ShaderImage {
	protected:
		Shader api;
		bool initialized;
	public:
		std::string orig_source;
		std::vector<std::string> orig_args;
		double arg_tmp[16];
	public:
		virtual ~ShaderImage();
		ShaderImage();
		void setBase();
		void setFunction(const char* source, ShaderInterface::Version reparse = ShaderInterface::AUTO_DETECT);
		void setFunction(const std::string &source, ShaderInterface::Version reparse = ShaderInterface::AUTO_DETECT);
		void argf(
			double  a0=0.0, double  a1=0.0, double  a2=0.0, double  a3=0.0,
			double  a4=0.0, double  a5=0.0, double  a6=0.0, double  a7=0.0,
			double  a8=0.0, double  a9=0.0, double a10=0.0, double a11=0.0,
			double a12=0.0, double a13=0.0, double a14=0.0, double a15=0.0
		);
		void cache(DrawableWithCache &target = *DrawableWithCache::prime);
		void cache(const char *source, DrawableWithCache &target = *DrawableWithCache::prime);
		void cacheFromFile(const std::string path, DrawableWithCache &target = *DrawableWithCache::prime);
		ShaderImage& draw(Image &img, const double *argv, const int argn, Canvas &target = *Display::the_canvas);
		void to(Image &dest, Image &img, const double *argv, const int argn, Canvas &media = *Display::the_canvas);
		ShaderImage& draw(Image &img, Canvas &target = *Display::the_canvas);
		void to(Image &dest, Image &img, Canvas &media = *Display::the_canvas);
	};

	class ShaderField {
	protected:
		static Group internal_group;
		static Image internal_image;

		Shader api;
		bool initialized;
	public:
		std::string orig_source;
		std::vector<std::string> orig_args;
		double arg_tmp[16];
	public:
		virtual ~ShaderField();
		ShaderField();
		void setBase();
		void setFunction(const char* source, ShaderInterface::Version reparse = ShaderInterface::AUTO_DETECT);
		void setFunction(const std::string &source, ShaderInterface::Version reparse = ShaderInterface::AUTO_DETECT);
		void argf(
			double  a0=0.0, double  a1=0.0, double  a2=0.0, double  a3=0.0,
			double  a4=0.0, double  a5=0.0, double  a6=0.0, double  a7=0.0,
			double  a8=0.0, double  a9=0.0, double a10=0.0, double a11=0.0,
			double a12=0.0, double a13=0.0, double a14=0.0, double a15=0.0
		);
		void cache(DrawableWithCache &target = *DrawableWithCache::prime);
		void cache(const char *source, DrawableWithCache &target = *DrawableWithCache::prime);
		void cacheFromFile(const std::string path, DrawableWithCache &target = *DrawableWithCache::prime);
		void draw(const Rectangle &rect, const double* argv, const int argn, Drawable &target = *Display::the_canvas);
		void to(Image &dest, const Rectangle &rect, const double* argv, const int argn, Canvas &media = *Display::the_canvas);
		void draw(const Rectangle &rect, Drawable &target = *Display::the_canvas);
		void to(Image &dest, const Rectangle &rect, Canvas &media = *Display::the_canvas);
	};



	class ShaderCoordinateTuner : public Rectangle {
	protected:
		static const char *glsl_source;
		static ShaderField field;
	public:
		ShaderCoordinateTuner();
		virtual ShaderCoordinateTuner& cache(DrawableWithCache &target = *DrawableWithCache::prime);
		virtual ShaderCoordinateTuner& draw(Canvas &target = *Display::the_canvas);
		virtual void to(Image &dest, Canvas &media = *Display::the_canvas);
	};


	class ShaderGrating : public Rectangle {
	protected:
		static const char *glsl_source;
		static ShaderField field;
	public:
		Length wavelength;
		Angle orientation, phase;
		double contrast;
	public:
		ShaderGrating();
		virtual ShaderGrating& setWave(double wavelen, double cont = 0.5, double orient = 0.0, double phs=0.0);
		virtual ShaderGrating& setWave(Length wavelen, double cont = 0.5, Angle orient = 0.0*degree, Angle phs=0.0*degree);
		virtual ShaderGrating& cache(DrawableWithCache &target = *DrawableWithCache::prime);
		virtual ShaderGrating& draw(Drawable &target = *DrawableWithCache::prime);
		virtual void to(Image &dest, Canvas &media = *Display::the_canvas);
	};

	class ShaderGaussianDot : public Rectangle {
	protected:
		static const char *glsl_source;
		static ShaderField field;
	public:
		Color bgcolor;
		ShaderGaussianDot();
		virtual ShaderGaussianDot& setSigma(double sigma);
		virtual ShaderGaussianDot& cache(DrawableWithCache &target = *DrawableWithCache::prime);
		virtual ShaderGaussianDot& draw(Drawable &target = *DrawableWithCache::prime);
		virtual void to(Image &dest, Canvas &media = *Display::the_canvas);
	};

	class ShaderGabor : public Rectangle {
	protected:
		static const char *glsl_source;
		static ShaderField field;
	public:
		Length wavelength;
//		Angle orientation, phase;
		double orientation, phase;
		double contrast;
	public:
		ShaderGabor();
		virtual ShaderGabor& setSigma(double sigma);
		virtual ShaderGabor& setSigma(Length sigma);
		virtual ShaderGabor& setWave(double wavelen, double cont = 0.5, double orient = 0.0, double phs=0.0);
		virtual ShaderGabor& setWave(Length wavelen, double cont = 0.5, Angle orient = 0.0*degree, Angle phs=0.0*degree);
		virtual ShaderGabor& cache(DrawableWithCache &target = *DrawableWithCache::prime);
		virtual ShaderGabor& draw(Drawable &target = *DrawableWithCache::prime);
		virtual void to(Image &dest, Canvas &media = *Display::the_canvas);
	};

	class ShaderGaborAlpha : public Rectangle {
	protected:
		static const char *glsl_source;
		static ShaderField field;
	public:
		Length wavelength;
//		Angle orientation, phase;
		double orientation, phase;
		double contrast, alpha;
	public:
		ShaderGaborAlpha();
		virtual ShaderGaborAlpha& setSigma(double sigma);
		virtual ShaderGaborAlpha& setSigma(Length sigma);
		virtual ShaderGaborAlpha& setWave(double wavelen, double cont = 0.5, double orient = 0.0, double phs=0.0);
		virtual ShaderGaborAlpha& setWave(Length wavelen, double cont = 0.5, Angle orient = 0.0*degree, Angle phs=0.0*degree);
		virtual ShaderGaborAlpha& cache(DrawableWithCache &target = *DrawableWithCache::prime);
		virtual ShaderGaborAlpha& draw(Drawable &target = *DrawableWithCache::prime);
		virtual void to(Image &dest, Canvas &media = *Display::the_canvas);
	};

	class ShaderPlaid : public Rectangle {
	protected:
		static const char *glsl_source;
		static ShaderField field;
	public:
		Length wavelength, wavelength2;
		Angle orientation, orientation2, phase, phase2;
		double contrast, contrast2;
	public:
		ShaderPlaid();
		virtual ShaderPlaid& setSigma(double sigma);
		virtual ShaderPlaid& setSigma(Length sigma);
		virtual ShaderPlaid& setWave(double wavelen, double cont = 0.5, double orient = 0.0, double phs=0.0);
		virtual ShaderPlaid& setWave(Length wavelen, double cont = 0.5, Angle orient = 0.0*degree, Angle phs=0.0*degree);
		virtual ShaderPlaid& setWave2(double wavelen, double cont = 0.5, double orient = 0.0, double phs=0.0);
		virtual ShaderPlaid& setWave2(Length wavelen, double cont = 0.5, Angle orient = 0.0*degree, Angle phs=0.0*degree);
		virtual ShaderPlaid& cache(DrawableWithCache &target = *DrawableWithCache::prime);
		virtual ShaderPlaid& draw(Drawable &target = *DrawableWithCache::prime);
		virtual void to(Image &dest, Canvas &media = *Display::the_canvas);
	};

	class ShaderPlaidAlpha : public Rectangle {
	protected:
		static const char *glsl_source;
		static ShaderField field;
	public:
		Length wavelength, wavelength2;
		Angle orientation, orientation2, phase, phase2;
		double contrast, contrast2, alpha;
	public:
		ShaderPlaidAlpha();
		virtual ShaderPlaidAlpha& setSigma(double sigma);
		virtual ShaderPlaidAlpha& setSigma(Length sigma);
		virtual ShaderPlaidAlpha& setWave(double wavelen, double cont = 0.5, double orient = 0.0, double phs=0.0);
		virtual ShaderPlaidAlpha& setWave(Length wavelen, double cont = 0.5, Angle orient = 0.0*degree, Angle phs=0.0*degree);
		virtual ShaderPlaidAlpha& setWave2(double wavelen, double cont = 0.5, double orient = 0.0, double phs=0.0);
		virtual ShaderPlaidAlpha& setWave2(Length wavelen, double cont = 0.5, Angle orient = 0.0*degree, Angle phs=0.0*degree);
		virtual ShaderPlaidAlpha& cache(DrawableWithCache &target = *DrawableWithCache::prime);
		virtual ShaderPlaidAlpha& draw(Drawable &target = *DrawableWithCache::prime);
		virtual void to(Image &dest, Canvas &media = *Display::the_canvas);
	};


}	/*	<- namespace Figures 	*/
}	/*	<- namespace Psycholops 	*/

#endif
