11/src/Texture.cpp

150 lines
6.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Texture.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
std::map<std::string, int> Texture::filename_handler; // Получение дескриптора текстуры по её имени
std::map<int, int> Texture::handler_count; // Получение количества использований по дескриптору текстуры (Shared pointer)
// Загрузка текстуры с диска или использование "пустой"
Texture::Texture(GLuint t, const std::string& filename) : type(t)
{
if (!filename_handler.count(filename))
{
std::string empty = "";
int width, height, channels; // Ширина, высота и цветовые каналы текстуры
unsigned char* image = stbi_load(filename.c_str(), &width, &height, &channels, STBI_default); // Загрузка в оперативную память изображения
// Если изображение успешно счиитано с диска или отсутствует пустая текстура
if (image || !filename_handler.count(empty))
{
glActiveTexture(type + GL_TEXTURE0);
glGenTextures(1, &handler); // Генерация одной текстуры
glBindTexture(GL_TEXTURE_2D, handler); // Привязка текстуры как активной
filename_handler[filename] = handler; // Запоминим её дескриптор для этого имени файла
handler_count[handler] = 0; // Создадим счетчик использований дескриптора, который будет изменен в конце
// Если изображение успешно считано
if (image)
{
// Загрузка данных с учетом прозрачности
if (channels == 3) // RGB
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
else if (channels == 4) // RGBA
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D); // Генерация мипмапа для активной текстуры
glBindTexture(GL_TEXTURE_2D, 0); // Отвязка активной текстуры
stbi_image_free(image); // Освобождение оперативной памяти
}
// Иначе изображение не считано и надо создать пустую текстуру
else
{
image = new unsigned char[3] {255,255,255}; // RGB по 1 байту на
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, image); // Загрузка данных на видеокарту
delete[] image; // Освобождение оперативной памяти
filename_handler[empty] = handler; // Запоминим дополнительно её дескриптор для NULL-строки
}
}
// Иначе используем существующую пустую текстуру (текстура не загружена, пустую создавать не нужно)
else
handler = filename_handler[empty];
}
// Иначе используем уже существующую по имени файла
else
handler = filename_handler[filename];
handler_count[handler]++;
}
// Конструктор текстуры заданного размера для использования в буфере
Texture::Texture(GLuint width, GLuint height, GLuint attachment, GLuint texType, GLint internalformat, GLint format, GLenum dataType) : type(texType)
{
// Генерация текстуры заданного размера
glGenTextures(1, &handler);
glBindTexture(GL_TEXTURE_2D, handler);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, dataType, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Привязка к буферу кадра
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, handler, 0);
// Создаем счетчик использований дескриптора
handler_count[handler] = 1;
}
// Конструктор копирования
Texture::Texture(const Texture& other) : handler(other.handler), type(other.type)
{
// Делаем копию и увеличиваем счетчик
handler_count[handler]++;
}
// Оператор присваивания
Texture& Texture::operator=(const Texture& other)
{
// Если это разные текстуры
if (handler != other.handler)
{
this->~Texture(); // Уничтожаем имеющуюся
// Заменяем новой
handler = other.handler;
handler_count[handler]++;
}
type = other.type;
return *this;
}
Texture::~Texture()
{
if (!--handler_count[handler]) // Если количество ссылок = 0
{
glDeleteTextures(1, &handler); // Удаление текстуры
// Удаление из словаря имен файлов и дескрипторов
for (auto it = filename_handler.begin(); it != filename_handler.end();)
{
if (it->second == handler)
it = filename_handler.erase(it);
else
it++;
}
}
}
// Пересоздает текстуру для имеющегося дескриптора
void Texture::reallocate(GLuint width, GLuint height, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
{
use();
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, dataType, NULL);
}
// Привязка текстуры
void Texture::use()
{
glActiveTexture(type + GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, handler); // Привязка текстуры как активной
}
// Отвязка текстуры по типу
void Texture::disable(GLuint type)
{
glActiveTexture(type + GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0); // Отвязка текстуры
}
// Возвращает тип текстуры
GLuint Texture::getType()
{
return type;
}
// Задает тип текстуры
void Texture::setType(GLuint type)
{
this->type = type;
}