/*
* color.h
* DIN Is Noise is copyright (c) 2006-2024 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/


#ifndef __color__
#define __color__

#include "dingl.h"
#include "random.h"
#include "utils.h"
#include <fstream>

inline void hex2rgb (unsigned char hr, unsigned char hg, unsigned char hb, float& r, float& g, float& b) {
  const unsigned char ff = 0xff;
  const float ff1 = 1.0f / ff;
  r = hr * ff1;
  g = hg * ff1;
  b = hb * ff1;
}

struct color {
  float r, g, b;
  color (float rr = 0, float gg = 0, float bb = 0) {
    r = rr;
    g = gg;
    b = bb;
  }
  color (const color& t, const color& s) {
		r = t.r - s.r;
		g = t.g - s.g;
		b = t.b - s.b;
	}
	color& operator*= (float v) {
		r *= v;
		g *= v;
		b *= v;
		return *this;
	}
};

inline void set_rnd_color (float& r, float& g, float& b, float m0 = 0, float m1 = 1) {
	rnd<float> rd (m0, m1);
	r = rd(); g = rd (); b = rd ();
}

inline void set_color (unsigned char hr, unsigned char hg, unsigned char hb, float a = 1) {
  float r, g, b;
  hex2rgb (hr, hg, hb, r, g, b);
  glColor4f (r, g, b, a);
}

inline void blend_color (const color& source, const color& target, color& result, float amount) {
	color delta (target, source);
	delta *= amount; 
	result.r = source.r + delta.r; 
	result.g = source.g + delta.g;
	result.b = source.b + delta.b;
}

struct color_data_t {
	color clr[2];
	color out;
	int i;
	float p;
};

struct get_color {
	static color_data_t data;
	static void update_data ();
	virtual color& operator()() = 0;
};

struct get_fixed_color : get_color {
	int ii;
	get_fixed_color (int _i) { ii = _i;}
	color& operator() () {return data.clr [ii];}
};

struct get_random_color : get_color {
	color& operator() () {
		color& c0 = data.clr[0];
		color& c1 = data.clr[1];
		rnd<float> r(c0.r, c1.r), g(c0.g, c1.g), b(c0.b, c1.b);
		data.out.r = r(); data.out.g = g(); data.out.b = b();
		return data.out;
	}
};

struct get_blend_color : get_color {
	color& operator() () {
		color& c0 = data.clr[0];
		color& c1 = data.clr[1];
		blend_color (c0, c1, data.out, data.p);
		return data.out;
	}
};


struct colorer_t {
	enum {TOP, BOTTOM, BLEND, RANDOM};	
	static const char* s_schemes [];
	#define maxs_ 4
	#define maxs__1 (maxs_ - 1)
	int i;
	get_color* schemes[maxs_];
	color& operator() () {
		get_color& gci = *schemes[i];
		return gci ();
	}
	colorer_t& operator+= (int ds) {
		i += ds;
		wrap (0, i, maxs__1);
		return *this;
	}
	const char* get_scheme_name () {
		return s_schemes[i];
	}
};

std::ostream& operator<< (std::ostream&, colorer_t&);
std::istream& operator>> (std::istream&, colorer_t&);


#endif
