/*
    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/>.
*/

#include "gltexture_manager.h"

using namespace QGLEngineShaders;


Map::Map() {
	bitmap_id    = 0;
	color_amount = 1.f;
	color_offset = 0.f;
	bitmap_scale = QPointF(1., 1.);
	use_bitmap   = false;
	_changed     = true;
	_layer       = 0;
	_bitmap_hash = 0;
}


void Map::setBitmapPath(const QString & p) {
	bitmap_path  = p;
	_changed     = true;
	_bitmap_hash = 0;
}


void Map::load(TextureManager * tm) {
	_bitmap_hash = 0;
	if (!bitmap_path.isEmpty()) tm->loadTextureImage(bitmap_path, _type == mtNormal, bake_options, &_bitmap_hash);
	_changed = false;
}


void Map::setMapLayer(TextureManager * tm) {
	if (loadedBitmap())
		_layer = tm->textureLayer(_bitmap_hash);
	else
		_layer = 0;
}


void Map::copyToQGLMap(QGLMap & m) const {
	m.amount = color_amount;
	m.offset = color_offset;
	m.scale  = QVector2D(bitmap_scale);
	if (loadedBitmap() && use_bitmap) {
		m.array_index = 1;
		m.map_index   = _layer;
	} else {
		m.array_index = 0;
		m.map_index   = emptyMapIndex(_type);
	}
}


GLuint Map::emptyMapIndex(int type) {
	switch (type) {
	case mtNormal: return emrBlue;
	case mtRelief: return emrBlack;
	default: return emrWhite;
	}
	return 0;
}


Material::Material(const QString _name) {
	setTypes();
	name           = _name;
	color_diffuse  = Qt::white;
	color_emission = Qt::black;
	glass          = false;
	transparency = reflectivity = 0.f;
	map_roughness.color_amount  = 0.75f;
	map_metalness.color_amount  = 0.25f;
	iof                         = 1.f;
	dispersion                  = 0.05f;
	_changed                    = true;
	_index                      = 0;
}


uint Material::hash() {
	return qHash(name);
}


bool Material::hasTransparency() const {
	return float(color_diffuse.alphaF()) * (1.f - transparency) < 1.f;
}


bool Material::isMapsChanged() const {
	return map_diffuse._changed || map_normal._changed || map_metalness._changed || map_roughness._changed || map_emission._changed ||
	       map_relief._changed;
}


bool Material::isMapChanged(int type) const {
	switch (type) {
	case mtDiffuse: return map_diffuse._changed;
	case mtNormal: return map_normal._changed;
	case mtMetalness: return map_metalness._changed;
	case mtRoughness: return map_roughness._changed;
	case mtEmission: return map_emission._changed;
	case mtRelief: return map_relief._changed;
	}
	return false;
}


void Material::load(TextureManager * tm) {
	map_diffuse.load(tm);
	map_normal.load(tm);
	map_metalness.load(tm);
	map_roughness.load(tm);
	map_emission.load(tm);
	map_relief.load(tm);
}


void Material::setMapsLayers(TextureManager * tm) {
	map_diffuse.setMapLayer(tm);
	map_normal.setMapLayer(tm);
	map_metalness.setMapLayer(tm);
	map_roughness.setMapLayer(tm);
	map_emission.setMapLayer(tm);
	map_relief.setMapLayer(tm);
}


void Material::setMapsChanged() {
	map_diffuse._changed   = true;
	map_normal._changed    = true;
	map_metalness._changed = true;
	map_roughness._changed = true;
	map_emission._changed  = true;
	map_relief._changed    = true;
}


void Material::setTypes() {
	map_diffuse._type   = mtDiffuse;
	map_normal._type    = mtNormal;
	map_metalness._type = mtMetalness;
	map_roughness._type = mtRoughness;
	map_emission._type  = mtEmission;
	map_relief._type    = mtRelief;
}


void Material::detectMaps() {
	map_diffuse.use_bitmap   = !map_diffuse.bitmap_path.isEmpty();
	map_normal.use_bitmap    = !map_normal.bitmap_path.isEmpty();
	map_metalness.use_bitmap = !map_metalness.bitmap_path.isEmpty();
	map_roughness.use_bitmap = !map_roughness.bitmap_path.isEmpty();
	map_emission.use_bitmap  = !map_emission.bitmap_path.isEmpty();
	map_relief.use_bitmap    = !map_relief.bitmap_path.isEmpty();
}


uint MapBakeOptions::hash() const {
	return qHash((uint)invert_R + ((uint)invert_G << 1) + ((uint)invert_B << 2));
}
