/*
    QGL Material
    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>


struct QGLENGINE_CORE_EXPORT MapBakeOptions {
	uint hash() const;
	bool invert_R = false;
	bool invert_G = false;
	bool invert_B = false;
};


class QGLENGINE_CORE_EXPORT Map {
public:
	Map();
	void setBitmapPath(const QString & p);
	void clearBitmap() { setBitmapPath(QString()); }
	bool hasBitmap() const { return !bitmap_path.isEmpty(); }
	bool loadedBitmap() const { return _bitmap_hash != 0; }
	void load(TextureManager * tm);
	void setMapLayer(TextureManager * tm);
	void copyToQGLMap(QGLEngineShaders::QGLMap & m) const;
	static GLuint emptyMapIndex(int type);
	QString bitmap_path;
	GLuint bitmap_id;
	QPointF bitmap_offset;
	QPointF bitmap_scale;
	float color_amount;
	float color_offset;
	bool use_bitmap;
	MapBakeOptions bake_options;

	bool _changed;
	int _type, _layer;
	uint _bitmap_hash;
};

class QGLENGINE_CORE_EXPORT 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 setMapsLayers(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;
};


inline QDataStream & operator<<(QDataStream & s, const MapBakeOptions & m) {
	ChunkStream cs;
	cs.add(1, m.invert_R).add(2, m.invert_G).add(3, m.invert_B);
	s << cs.data();
	return s;
}
inline QDataStream & operator>>(QDataStream & s, MapBakeOptions & m) {
	ChunkStream cs(s);
	cs.readAll();
	cs.get(1, m.invert_R).get(2, m.invert_G).get(3, m.invert_B);
	return s;
}


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)
		.add(11, m.bake_options);
	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)
		.get(11, m.bake_options);
	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 << (cs.data());
	return s;
}
inline QDataStream & operator>>(QDataStream & s, Material *& m) {
	m = new Material();
	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
