The Mega Snivy Update
Some checks failed
Build / Build Game (push) Has been cancelled

This commit is contained in:
2026-02-28 21:48:00 -05:00
parent 8b2edd1359
commit 17f3348e94
163 changed files with 8725 additions and 13281 deletions

View File

@@ -1,60 +1,75 @@
#include "texture.h"
#include "texture.hpp"
#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#include <SDL3/SDL_surface.h>
#include <string>
#include <unordered_map>
#define STBI_ONLY_PNG
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#include <iostream>
#include "../log.hpp"
using namespace glm;
using namespace game::util;
namespace game::resource
{
struct CachedTexture
{
std::weak_ptr<GLuint> idShared{};
glm::ivec2 size{};
int channels{};
};
static std::unordered_map<std::string, CachedTexture> textureCache{};
static bool cache_get(const std::string& key, std::shared_ptr<GLuint>& idShared, GLuint& id, ivec2& size, int& channels)
{
auto it = textureCache.find(key);
if (it == textureCache.end()) return false;
auto shared = it->second.idShared.lock();
if (!shared)
{
textureCache.erase(it);
return false;
}
idShared = shared;
id = *shared;
size = it->second.size;
channels = it->second.channels;
return true;
}
static void cache_set(const std::string& key, const std::shared_ptr<GLuint>& idShared, ivec2 size, int channels)
{
if (!idShared) return;
textureCache[key] = CachedTexture{.idShared = idShared, .size = size, .channels = channels};
}
static std::shared_ptr<GLuint> texture_id_make(GLuint id)
{
return std::shared_ptr<GLuint>(new GLuint(id),
[](GLuint* p)
{
if (!p) return;
if (*p != 0) glDeleteTextures(1, p);
delete p;
});
}
bool Texture::is_valid() const { return id != 0; }
void Texture::retain()
Texture::~Texture()
{
if (refCount) ++(*refCount);
}
void Texture::release()
{
if (refCount)
{
if (--(*refCount) == 0)
{
if (is_valid()) glDeleteTextures(1, &id);
delete refCount;
}
refCount = nullptr;
}
else if (is_valid())
{
glDeleteTextures(1, &id);
}
idShared.reset();
id = 0;
}
Texture::~Texture() { release(); }
Texture::Texture(const Texture& other)
{
id = other.id;
size = other.size;
channels = other.channels;
refCount = other.refCount;
retain();
idShared = other.idShared;
}
Texture::Texture(Texture&& other) noexcept
@@ -62,24 +77,21 @@ namespace game::resource
id = other.id;
size = other.size;
channels = other.channels;
refCount = other.refCount;
idShared = std::move(other.idShared);
other.id = 0;
other.size = {};
other.channels = 0;
other.refCount = nullptr;
}
Texture& Texture::operator=(const Texture& other)
{
if (this != &other)
{
release();
idShared = other.idShared;
id = other.id;
size = other.size;
channels = other.channels;
refCount = other.refCount;
retain();
}
return *this;
}
@@ -88,45 +100,103 @@ namespace game::resource
{
if (this != &other)
{
release();
idShared.reset();
id = other.id;
size = other.size;
channels = other.channels;
refCount = other.refCount;
idShared = std::move(other.idShared);
other.id = 0;
other.size = {};
other.channels = 0;
other.refCount = nullptr;
}
return *this;
}
void Texture::init(const uint8_t* data)
{
idShared.reset();
id = 0;
GLuint newId{};
glGenTextures(1, &newId);
glBindTexture(GL_TEXTURE_2D, newId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, 0);
channels = CHANNELS;
idShared = texture_id_make(newId);
id = newId;
}
Texture::Texture(const std::filesystem::path& path)
{
if (auto data = stbi_load(path.c_str(), &size.x, &size.y, nullptr, CHANNELS); data)
auto key = std::string("fs:") + path.string();
if (cache_get(key, idShared, id, size, channels))
{
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
channels = CHANNELS;
refCount = new int(1);
std::cout << "Initialized texture: '" << path.string() << "\n";
logger.info(std::format("Using cached texture: {}", path.string()));
return;
}
if (auto surface = SDL_LoadPNG(path.c_str()))
{
auto rgbaSurface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
SDL_DestroySurface(surface);
surface = rgbaSurface;
this->size = ivec2(surface->w, surface->h);
init((const uint8_t*)surface->pixels);
SDL_DestroySurface(surface);
cache_set(key, idShared, this->size, channels);
logger.info(std::format("Initialized texture: {}", path.string()));
}
else
logger.error(std::format("Failed to initialize texture: {} ({})", path.string(), SDL_GetError()));
}
Texture::Texture(const physfs::Path& path)
{
if (!path.is_valid())
{
id = 0;
size = {};
channels = 0;
refCount = nullptr;
std::cout << "Failed to initialize texture: '" << path.string() << "'\n";
logger.error(
std::format("Failed to initialize texture from PhysicsFS path: {}", path.c_str(), physfs::error_get()));
return;
}
auto key = std::string("physfs:") + path.c_str();
if (cache_get(key, idShared, id, size, channels))
{
logger.info(std::format("Using cached texture: {}", path.c_str()));
return;
}
auto buffer = path.read();
if (buffer.empty())
{
logger.error(
std::format("Failed to initialize texture from PhysicsFS path: {} ({})", path.c_str(), physfs::error_get()));
return;
}
auto ioStream = SDL_IOFromConstMem(buffer.data(), buffer.size());
if (auto surface = SDL_LoadPNG_IO(ioStream, true))
{
auto rgbaSurface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
SDL_DestroySurface(surface);
surface = rgbaSurface;
this->size = ivec2(surface->w, surface->h);
init((const uint8_t*)surface->pixels);
SDL_DestroySurface(surface);
cache_set(key, idShared, this->size, channels);
logger.info(std::format("Initialized texture: {}", path.c_str()));
}
else
logger.error(std::format("Failed to initialize texture: {} ({})", path.c_str(), SDL_GetError()));
}
}