|
/*
|
|
* Copyright (C) 2020 Christopher J. Howard
|
|
*
|
|
* This file is part of Antkeeper source code.
|
|
*
|
|
* Antkeeper source code 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.
|
|
*
|
|
* Antkeeper source code 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 Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "rasterizer/texture-2d.hpp"
|
|
#include "rasterizer/texture-wrapping.hpp"
|
|
#include "rasterizer/texture-filter.hpp"
|
|
#include <glad/glad.h>
|
|
#include <algorithm>
|
|
|
|
static constexpr GLenum pixel_format_lut[] =
|
|
{
|
|
GL_DEPTH_COMPONENT,
|
|
GL_DEPTH_STENCIL,
|
|
GL_RED,
|
|
GL_RG,
|
|
GL_RGB,
|
|
GL_BGR,
|
|
GL_RGBA,
|
|
GL_BGRA
|
|
};
|
|
|
|
static constexpr GLenum pixel_type_lut[] =
|
|
{
|
|
GL_BYTE,
|
|
GL_UNSIGNED_BYTE,
|
|
GL_SHORT,
|
|
GL_UNSIGNED_SHORT,
|
|
GL_INT,
|
|
GL_UNSIGNED_INT,
|
|
GL_HALF_FLOAT,
|
|
GL_FLOAT
|
|
};
|
|
|
|
static constexpr GLenum internal_format_lut[][8] =
|
|
{
|
|
{GL_NONE, GL_NONE, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32, GL_NONE, GL_DEPTH_COMPONENT32F},
|
|
|
|
// Note: GL_DEPTH32F_STENCIL8 is actually a 64-bit format, 32 depth bits, 8 stencil bits, and 24 alignment bits.
|
|
{GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH32F_STENCIL8},
|
|
|
|
{GL_R8, GL_R8, GL_R16, GL_R16, GL_R32F, GL_R32F, GL_R16F, GL_R32F},
|
|
{GL_RG8, GL_RG8, GL_RG16, GL_RG16, GL_RG32F, GL_RG32F, GL_RG16F, GL_RG32F},
|
|
{GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
|
|
{GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
|
|
{GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F},
|
|
{GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F}
|
|
|
|
};
|
|
|
|
static constexpr GLint swizzle_mask_lut[][4] =
|
|
{
|
|
{GL_RED, GL_RED, GL_RED, GL_ONE},
|
|
{GL_RED, GL_GREEN, GL_ZERO, GL_ONE},
|
|
{GL_RED, GL_RED, GL_RED, GL_ONE},
|
|
{GL_RED, GL_RED, GL_RED, GL_GREEN},
|
|
{GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
|
|
{GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
|
|
{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA},
|
|
{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}
|
|
};
|
|
|
|
static constexpr GLenum wrapping_lut[] =
|
|
{
|
|
GL_CLAMP_TO_EDGE,
|
|
GL_REPEAT,
|
|
GL_MIRRORED_REPEAT
|
|
};
|
|
|
|
static constexpr GLenum min_filter_lut[] =
|
|
{
|
|
GL_NEAREST,
|
|
GL_LINEAR,
|
|
GL_NEAREST_MIPMAP_NEAREST,
|
|
GL_LINEAR_MIPMAP_NEAREST,
|
|
GL_NEAREST_MIPMAP_LINEAR,
|
|
GL_LINEAR_MIPMAP_LINEAR
|
|
};
|
|
|
|
static constexpr GLenum mag_filter_lut[] =
|
|
{
|
|
GL_NEAREST,
|
|
GL_LINEAR
|
|
};
|
|
|
|
texture_2d::texture_2d(int width, int height, ::pixel_type type, ::pixel_format format, const void* data):
|
|
gl_texture_id(0),
|
|
dimensions({0, 0}),
|
|
wrapping({texture_wrapping::repeat, texture_wrapping::repeat}),
|
|
filters({texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear}),
|
|
max_anisotropy(0.0f)
|
|
{
|
|
glGenTextures(1, &gl_texture_id);
|
|
resize(width, height, type, format, data);
|
|
set_wrapping(std::get<0>(wrapping), std::get<1>(wrapping));
|
|
set_filters(std::get<0>(filters), std::get<1>(filters));
|
|
set_max_anisotropy(max_anisotropy);
|
|
}
|
|
|
|
texture_2d::~texture_2d()
|
|
{
|
|
glDeleteTextures(1, &gl_texture_id);
|
|
}
|
|
|
|
void texture_2d::resize(int width, int height, ::pixel_type type, ::pixel_format format, const void* data)
|
|
{
|
|
dimensions = {width, height};
|
|
pixel_type = type;
|
|
pixel_format = format;
|
|
|
|
GLenum gl_internal_format = internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)];
|
|
GLenum gl_format = pixel_format_lut[static_cast<std::size_t>(format)];
|
|
const GLint* gl_swizzle_mask = swizzle_mask_lut[static_cast<std::size_t>(format)];
|
|
|
|
GLenum gl_type = pixel_type_lut[static_cast<std::size_t>(type)];
|
|
|
|
// Special cases for depth + stencil pixel formats
|
|
if (gl_internal_format == GL_DEPTH24_STENCIL8)
|
|
gl_type = GL_UNSIGNED_INT_24_8;
|
|
else if (gl_internal_format == GL_DEPTH32F_STENCIL8)
|
|
gl_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
|
|
|
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, gl_texture_id);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data);
|
|
glGenerateMipmap(GL_TEXTURE_2D);
|
|
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle_mask);
|
|
|
|
/// TODO: remove this
|
|
if (format == pixel_format::d)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
|
}
|
|
}
|
|
|
|
void texture_2d::set_wrapping(texture_wrapping wrap_s, texture_wrapping wrap_t)
|
|
{
|
|
wrapping = {wrap_s, wrap_t};
|
|
|
|
GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)];
|
|
GLenum gl_wrap_t = wrapping_lut[static_cast<std::size_t>(wrap_t)];
|
|
|
|
glBindTexture(GL_TEXTURE_2D, gl_texture_id);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl_wrap_s);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_wrap_t);
|
|
}
|
|
|
|
void texture_2d::set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter)
|
|
{
|
|
filters = {min_filter, mag_filter};
|
|
|
|
GLenum gl_min_filter = min_filter_lut[static_cast<std::size_t>(min_filter)];
|
|
GLenum gl_mag_filter = mag_filter_lut[static_cast<std::size_t>(mag_filter)];
|
|
|
|
glBindTexture(GL_TEXTURE_2D, gl_texture_id);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_min_filter);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_mag_filter);
|
|
}
|
|
|
|
void texture_2d::set_max_anisotropy(float anisotropy)
|
|
{
|
|
this->max_anisotropy = std::max<float>(0.0f, std::min<float>(1.0f, anisotropy));
|
|
|
|
// Lerp between 1.0f and GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
|
|
float gl_max_texture_max_anisotropy;
|
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_texture_max_anisotropy);
|
|
float gl_max_anisotropy = 1.0f + this->max_anisotropy * (gl_max_texture_max_anisotropy - 1.0f);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, gl_texture_id);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy);
|
|
}
|
|
|