/*
    QGLView
    Copyright (C) 2020  Ivan Pelipenko peri4ko@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU 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 General Public License for more details.

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

#include "gltypes.h"
#include "gltexture_manager.h"
#include "qglview.h"

using namespace QGLEngineShaders;

/*
bool CubeTexture::create() {
	//qDebug("create");
	destroy();
	glGenTextures(1, &id_);
	glBindTexture(GL_TEXTURE_CUBE_MAP, id_);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
	//glClearError();
	glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
	glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
	glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
	glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
	glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
	glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, format_, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
	//qDebug() << glGetError();
	changed_ = false;
	return id_ > 0;
}


void CubeTexture::load() {
	if (isEmpty()) return;
	create();
	if (!path(0).isEmpty()) loadFront(path(0));
	if (!path(1).isEmpty()) loadBack(path(1));
	if (!path(2).isEmpty()) loadLeft(path(2));
	if (!path(3).isEmpty()) loadRight(path(3));
	if (!path(4).isEmpty()) loadTop(path(4));
	if (!path(5).isEmpty()) loadBottom(path(5));
}


void CubeTexture::loadFromDirectory(const QString & dir) {
	QDir d(dir); QFileInfoList sl;
	sl = d.entryInfoList(QStringList("front.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadFront(sl[0].absoluteFilePath());
	sl = d.entryInfoList(QStringList("back.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadBack(sl[0].absoluteFilePath());
	sl = d.entryInfoList(QStringList("left.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadLeft(sl[0].absoluteFilePath());
	sl = d.entryInfoList(QStringList("right.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadRight(sl[0].absoluteFilePath());
	sl = d.entryInfoList(QStringList("top.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadTop(sl[0].absoluteFilePath());
	sl = d.entryInfoList(QStringList("bottom.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) loadBottom(sl[0].absoluteFilePath());
}


void CubeTexture::loadPathesFromDirectory(const QString & dir) {
	QDir d(dir); QFileInfoList sl;
	sl = d.entryInfoList(QStringList("front.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[0] = sl[0].absoluteFilePath();
	sl = d.entryInfoList(QStringList("back.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[1] = sl[0].absoluteFilePath();
	sl = d.entryInfoList(QStringList("left.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[2] = sl[0].absoluteFilePath();
	sl = d.entryInfoList(QStringList("right.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[3] = sl[0].absoluteFilePath();
	sl = d.entryInfoList(QStringList("top.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[4] = sl[0].absoluteFilePath();
	sl = d.entryInfoList(QStringList("bottom.*"), QDir::Files | QDir::NoDotAndDotDot); if (!sl.isEmpty()) pathes[5] = sl[0].absoluteFilePath();
}
*/



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;
}


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


void Map::load(TextureManager * tm) {
	if (bitmap_id == 0)
		bitmap_id = tm->loadTexture(bitmap_path, true, _type == mtNormal);
}


void Map::copyToQGLMap(QGLMap & m) const {
	m.amount = color_amount;
	m.offset = color_offset;
	m.scale  = QVector2D(bitmap_scale);
	if (hasBitmap() && use_bitmap) {
		m.array_index = tarMaps;
		m.map_index   = _layer;
	} else {
		m.array_index = tarEmpty;
		m.map_index   = (_type == mtNormal ? emrBlue : emrWhite);
	}
}




Material::Material(const QString _name)/*: map_reflection(512)*/ {
	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::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();
}
