/*
    QGLView
    Ivan Pelipenko peri4ko@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef GLMATERIAL_H
#define GLMATERIAL_H

#include "glshaders_types.h"
#include "chunkstream.h"

/*
class Texture {
public:
	Texture(int _width, int _height, const GLenum & _format = GL_RGBA8, const GLenum & _target = GL_TEXTURE_2D) {wid = _width; hei = _height; format_ = _format; target_ = _target; id_ = 0;}
	bool create() {destroy(); createGLTexture(id_, wid, hei, format_, target_); return id_ > 0;}
	void destroy() {if (id_ > 0) glDeleteTextures(1, &id_); id_ = 0;}
	void bind() {if (id_ > 0) glBindTexture(target_, id_);}
	void release() {glBindTexture(target_, 0);}
	int width() const {return wid;}
	int height() const {return hei;}
	GLenum format() const {return format_;}
	GLenum target() const {return target_;}
	GLuint id() const {return id_;}
private:
	int wid, hei;
	GLenum format_, target_;
	GLuint id_;
};


class CubeTexture {
public:
	CubeTexture(int _size, const GLenum & _format = GL_RGBA8) {size = _size; format_ = _format; id_ = 0; changed_ = false; pathes.resize(6);}
	bool create();
	void destroy() {if (id_ > 0) glDeleteTextures(1, &id_); id_ = 0;}
	void bind() {if (changed_) {changed_ = false; create();} if (id_ > 0) glBindTexture(GL_TEXTURE_CUBE_MAP, id_);}
	void release() {glBindTexture(GL_TEXTURE_CUBE_MAP, 0);}
	void resize(int _size) {size = _size; changed_ = true;}
	void loadFromDirectory(const QString & dir);
	void loadFront(const QString & path) {bind(); pathes[0] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_X);}
	void loadBack(const QString & path) {bind(); pathes[1] = path; createGLTexture(id_, rotateQImageRight(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_X);}
	void loadLeft(const QString & path) {bind(); pathes[2] = path; createGLTexture(id_, QImage(path).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);}
	void loadRight(const QString & path) {bind(); pathes[3] = path; createGLTexture(id_, rotateQImage180(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_Y);}
	void loadTop(const QString & path) {bind(); pathes[4] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);}
	void loadBottom(const QString & path) {bind(); pathes[5] = path; createGLTexture(id_, rotateQImageLeft(QImage(path)).scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), format_, GL_TEXTURE_CUBE_MAP_POSITIVE_Z);}
	void load();
	bool isEmpty() const {foreach (const QString & i, pathes) if (!i.isEmpty()) return false; return true;}
	GLenum format() const {return format_;}
	void setFormat(GLenum f) {format_ = f; changed_ = true;}
	GLuint id() const {return id_;}
	const QString & path(int side) const {return pathes[side];}
	void setPath(int side, const QString & p) {pathes[side] = p;}
	void loadPathesFromDirectory(const QString & dir);
private:
	bool changed_;
	int size;
	GLenum format_;
	GLuint id_;
	QVector<QString> pathes;
};
*/

class Map {
public:
	Map();
	void setBitmapPath(const QString & p);
	void clearBitmap() {setBitmapPath(QString());}
	bool hasBitmap() const {return !bitmap_path.isEmpty();}
	void load(TextureManager * tm);
	void copyToQGLMap(QGLEngineShaders::QGLMap & m) const;
	QString bitmap_path;
	GLuint  bitmap_id;
	QPointF bitmap_offset;
	QPointF bitmap_scale;
	float color_amount;
	float color_offset;
	bool use_bitmap;

	bool _changed;
	int _type, _layer;
};

class Material {
public:
	Material(const QString _name = QString());
	uint hash();
	bool hasTransparency() const;
	bool isMapsChanged() const;
	bool isMapChanged(int type) const;
	void load(TextureManager * tm);
	void setMapsChanged();
	void setTypes();
	void detectMaps();
	QString name;
	QColor color_diffuse;
	QColor color_emission;
	bool glass;
	float transparency;
	float reflectivity;
	float iof;
	float dispersion;
	Map map_diffuse  ;
	Map map_normal   ;
	Map map_metalness;
	Map map_roughness;
	Map map_emission ;
	Map map_relief   ;
	bool _changed;
	int _index;
	//GLCubeTexture map_reflection;
};


inline QDataStream & operator <<(QDataStream & s, const Map & m) {
	ChunkStream cs;
	cs.add(1, m.bitmap_path).add(2, m.color_amount).add(3, m.color_offset).add(6, m.bitmap_scale)
	  .add(7, m.use_bitmap);
	s << cs.data(); return s;
}
inline QDataStream & operator >>(QDataStream & s, Map & m) {
	ChunkStream cs(s);
	cs.readAll();
	cs.get(1, m.bitmap_path).get(2, m.color_amount).get(3, m.color_offset).get(6, m.bitmap_scale)
	  .get(7, m.use_bitmap);
	return s;
}

inline QDataStream & operator <<(QDataStream & s, const Material * m) {
	ChunkStream cs;
	cs.add(1, m->name).add(2, m->color_diffuse).add(4, m->color_emission)
	  .add(5, m->transparency).add(6, m->reflectivity).add(7, m->glass).add(8, m->map_diffuse).add(9, m->map_normal)
	  .add(10, m->map_relief).add(11, m->map_metalness).add(12, m->map_roughness).add(13, m->map_emission);
	s << /*qCompress*/(cs.data()); return s;
}
inline QDataStream & operator >>(QDataStream & s, Material *& m) {
	m = new Material();
	//QByteArray ba;
	//s >> ba;
	//ba = qUncompres(ba);
	ChunkStream cs(s);
	while (!cs.atEnd()) {
		switch (cs.read()) {
		case 1:  cs.get(m->name); break;
		case 2:  cs.get(m->color_diffuse); break;
		case 4:  cs.get(m->color_emission); break;
		case 5:  cs.get(m->transparency); break;
		case 6:  cs.get(m->reflectivity); break;
		case 7:  cs.get(m->glass); break;
		case 8:  cs.get(m->map_diffuse); break;
		case 9:  cs.get(m->map_normal); break;
		case 10: cs.get(m->map_relief); break;
		case 11: cs.get(m->map_metalness); break;
		case 12: cs.get(m->map_roughness); break;
		case 13: cs.get(m->map_emission); break;
		}
	}
	m->setTypes();
	return s;
}

#endif // GLMATERIAL_H
