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

#define GL_GLEXT_PROTOTYPES
#include "gltexturearray.h"

#include <QOpenGLExtraFunctions>


Texture2DArray::Texture2DArray(GLenum format, bool filter) {
	target_    = GL_TEXTURE_2D_ARRAY;
	format_    = format;
	texture_   = 0;
	layers_    = 0;
	filtering_ = filter;
}


Texture2DArray::~Texture2DArray() {}


void Texture2DArray::init(QOpenGLExtraFunctions * f) {
	if (!isInit()) {
		f->glGenTextures(1, &texture_);
	}
}


void Texture2DArray::destroy(QOpenGLExtraFunctions * f) {
	if (texture_ != 0) {
		f->glDeleteTextures(1, &texture_);
	}
	texture_ = 0;
}


void Texture2DArray::reinit() {
	texture_ = 0;
	layers_  = 0;
}


void Texture2DArray::bind(QOpenGLExtraFunctions * f, int channel) {
	f->glActiveTexture(GL_TEXTURE0 + channel);
	f->glBindTexture(target_, texture_);
}


void Texture2DArray::release(QOpenGLExtraFunctions * f) {
	f->glBindTexture(target_, 0);
}


bool Texture2DArray::resize(QOpenGLExtraFunctions * f, QSize new_size, int layers_count) {
	if (new_size.isNull() || layers_count <= 0) return false;
	if ((size_ == new_size) && (layers_ >= layers_count)) return false;
	size_   = new_size;
	layers_ = layers_count;
	f->glBindTexture(target_, texture_);
	f->glTexParameteri(target_, GL_TEXTURE_WRAP_S, GL_REPEAT);
	f->glTexParameteri(target_, GL_TEXTURE_WRAP_T, GL_REPEAT);
	if (filtering_) {
		f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		f->glTexParameteri(target_, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
	} else {
		f->glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		f->glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	}
	GLenum bformat = format_;
	GLenum btype   = GL_UNSIGNED_BYTE;
	if (format_ == GL_R16F || format_ == GL_R32F) {
		bformat = GL_RED;
		btype   = GL_FLOAT;
	}
	if (format_ == GL_DEPTH_COMPONENT || format_ == GL_DEPTH_COMPONENT16 || format_ == GL_DEPTH_COMPONENT24 ||
		format_ == GL_DEPTH_COMPONENT32) {
		bformat = GL_DEPTH_COMPONENT;
	}
	f->glTexImage3D(target_, 0, format_, size_.width(), size_.height(), layers_, 0, bformat, btype, nullptr);
	return true;
}


void Texture2DArray::load(QOpenGLExtraFunctions * f, const QImage & image, int layer) {
	if (image.isNull() || size_.isNull() || layer < 0 || layer >= layers_) return;
	QImage im =
		image.mirrored(false, true).scaled(size_, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).convertToFormat(QImage::Format_RGBA8888);
	// qDebug() << "Texture2DArray::load image" << image.size() << "to layer" << layer;
	f->glTexSubImage3D(target_, 0, 0, 0, layer, size_.width(), size_.height(), 1, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
}


void Texture2DArray::mipmaps(QOpenGLExtraFunctions * f) {
	f->glBindTexture(target_, texture_);
	f->glGenerateMipmap(target_);
}
