From 86f85229b508f36349e833b2c15fae6b7d839bcc Mon Sep 17 00:00:00 2001 From: "re.kovalev" Date: Mon, 14 Nov 2022 19:45:14 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9A=D0=BB=D0=B0=D1=81=D1=81=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D1=82=D1=83=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/Texture.h | 34 ++++++++++++ src/Texture.cpp | 129 ++++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 29 +++-------- 3 files changed, 169 insertions(+), 23 deletions(-) create mode 100644 include/Texture.h create mode 100644 src/Texture.cpp diff --git a/include/Texture.h b/include/Texture.h new file mode 100644 index 0000000..650ee11 --- /dev/null +++ b/include/Texture.h @@ -0,0 +1,34 @@ +#ifndef TEXTURE_H +#define TEXTURE_H + +#include + +#include +#include + +enum TexType { + TEX_DIFFUSE, + TEX_AVAILABLE_COUNT +}; + +class Texture +{ + public: + Texture(GLuint type = TEX_AVAILABLE_COUNT, const std::string& filename = ""); // Загрузка текстуры с диска или использование "пустой" + Texture(const Texture& other); // Конструктор копирования + ~Texture(); + + Texture& operator=(const Texture& other); // Оператор присваивания + + static void init_textures(GLuint programID); // Инициализация текстур на шейдере + void use(); // Привязка текстуры + static void disable(GLuint type); // Отвязка текстуры по типу + GLuint getType(); // Возвращает тип текстуры + private: + GLuint handler; // Дескриптор текстуры + GLuint type; // Тип текстуры, соответствует её слоту + static std::map filename_handler; // Получение дескриптора текстуры по её имени + static std::map handler_count; // Получение количества использований по дескриптору текстуры (Shared pointer) +}; + +#endif // TEXTURE_H diff --git a/src/Texture.cpp b/src/Texture.cpp new file mode 100644 index 0000000..181db4b --- /dev/null +++ b/src/Texture.cpp @@ -0,0 +1,129 @@ +#include "Texture.h" + +#define STB_IMAGE_IMPLEMENTATION +#include + +std::map Texture::filename_handler; // Получение дескриптора текстуры по её имени +std::map 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(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++; + } + } +} + +const char* textures_base_shader_names[] = {"tex_diffuse"}; + +// Инициализация текстур на шейдере +void Texture::init_textures(GLuint programID) +{ + // Цикл по всем доступным текстурам + for (int i = 0; i < TEX_AVAILABLE_COUNT; i++) + glUniform1i(glGetUniformLocation(programID, textures_base_shader_names[i]), i); +} + +// Привязка текстуры +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; +} diff --git a/src/main.cpp b/src/main.cpp index 0ced0fb..f054b2b 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,13 +2,12 @@ #include #include #include -#define STB_IMAGE_IMPLEMENTATION -#include #include #include "Camera.h" #include "Model.h" +#include "Texture.h" #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 @@ -182,6 +181,8 @@ int main(void) GLuint shaderProgram = LoadShaders("shaders/shader.vert", "shaders/shader.frag"); // Активация шейдера glUseProgram(shaderProgram); + // Установим значения текстур + Texture::init_textures(shaderProgram); // Вершины прямоугольника glm::vec3 verticies[] = { {-0.5f, -0.5f, 0.0f} @@ -217,23 +218,8 @@ int main(void) rectangle.e_rotation() = {0.707f, 0.707f, 0.0f, 0.0f}; rectangle.e_scale() = glm::vec3(3); - // Работа с текстурой - GLuint texture; // Дескриптор текстуры - glGenTextures(1, &texture); // Генерация одной текстуры - glBindTexture(GL_TEXTURE_2D, texture); // Привязка текстуры как активной - - int width, height, channels; // Ширина, высота и цветовые каналы текстуры - unsigned char* image = stbi_load("../resources/textures/grass.png", &width, &height, &channels, STBI_default); // Загрузка в оперативную память изображения - // Загрузка данных с учетом прозрачности - 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); // Освобождение оперативной памяти + // Текстура травы + Texture grass(TEX_DIFFUSE, "../resources/textures/grass.png"); // Установка цвета очистки буфера цвета glClearColor(0.0f, 0.0f, 0.0f, 1.0f); @@ -254,7 +240,7 @@ int main(void) glClear(GL_COLOR_BUFFER_BIT); // Тут производится рендер - glBindTexture(GL_TEXTURE_2D, texture); // Привязка текстуры как активной + grass.use(); // Привязка текстуры как активной rectangle.render(model_uniform); // Представление содержимого буфера цепочки показа на окно @@ -263,9 +249,6 @@ int main(void) glfwPollEvents(); } - // Удаление текстуры - glDeleteTextures(1, &texture); - // Удаление шейдерной программы glDeleteProgram(shaderProgram);