Corregidos ~2570 issues automáticamente con clang-tidy --fix-errors más ajustes manuales posteriores: - modernize: designated-initializers, trailing-return-type, use-auto, avoid-c-arrays (→ std::array<>), use-ranges, use-emplace, deprecated-headers, use-equals-default, pass-by-value, return-braced-init-list, use-default-member-init - readability: math-missing-parentheses, implicit-bool-conversion, braces-around-statements, isolate-declaration, use-std-min-max, identifier-naming, else-after-return, redundant-casting, convert-member-functions-to-static, make-member-function-const, static-accessed-through-instance - performance: avoid-endl, unnecessary-value-param, type-promotion, inefficient-vector-operation - dead code: XOR_KEY (orphan tras eliminar encryptData/decryptData), dead stores en engine.cpp y png_shape.cpp - NOLINT justificado en 10 funciones con alta complejidad cognitiva (initialize, render, main, processEvents, update×3, performDemoAction, randomizeOnDemoStart, renderDebugHUD, AppLogo::update) Compilación: gcc -Wall sin warnings. clang-tidy: 0 issues. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
229 lines
7.2 KiB
C++
229 lines
7.2 KiB
C++
#include "gpu_texture.hpp"
|
||
|
||
#include <SDL3/SDL_log.h>
|
||
#include <SDL3/SDL_pixels.h>
|
||
|
||
#include <array> // for std::array
|
||
#include <cstring> // memcpy
|
||
#include <string>
|
||
|
||
// stb_image is compiled in texture.cpp (STB_IMAGE_IMPLEMENTATION defined there)
|
||
#include "external/stb_image.h"
|
||
#include "resource_manager.hpp"
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Public interface
|
||
// ---------------------------------------------------------------------------
|
||
|
||
auto GpuTexture::fromFile(SDL_GPUDevice* device, const std::string& file_path) -> bool {
|
||
unsigned char* resource_data = nullptr;
|
||
size_t resource_size = 0;
|
||
|
||
if (!ResourceManager::loadResource(file_path, resource_data, resource_size)) {
|
||
SDL_Log("GpuTexture: can't load resource '%s'", file_path.c_str());
|
||
return false;
|
||
}
|
||
|
||
int w = 0;
|
||
int h = 0;
|
||
int orig = 0;
|
||
unsigned char* pixels = stbi_load_from_memory(
|
||
resource_data,
|
||
static_cast<int>(resource_size),
|
||
&w,
|
||
&h,
|
||
&orig,
|
||
STBI_rgb_alpha);
|
||
delete[] resource_data;
|
||
|
||
if (pixels == nullptr) {
|
||
SDL_Log("GpuTexture: stbi decode failed for '%s': %s",
|
||
file_path.c_str(),
|
||
stbi_failure_reason());
|
||
return false;
|
||
}
|
||
|
||
destroy(device);
|
||
bool ok = uploadPixels(device, pixels, w, h, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM);
|
||
stbi_image_free(pixels);
|
||
|
||
if (ok) {
|
||
ok = createSampler(device, true /*nearest = pixel-perfect sprites*/);
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
auto GpuTexture::fromSurface(SDL_GPUDevice* device, SDL_Surface* surface, bool nearest) -> bool {
|
||
if (surface == nullptr) {
|
||
return false;
|
||
}
|
||
|
||
// Ensure RGBA32 format
|
||
SDL_Surface* rgba = surface;
|
||
bool need_free = false;
|
||
if (surface->format != SDL_PIXELFORMAT_RGBA32) {
|
||
rgba = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
|
||
if (rgba == nullptr) {
|
||
SDL_Log("GpuTexture: SDL_ConvertSurface failed: %s", SDL_GetError());
|
||
return false;
|
||
}
|
||
need_free = true;
|
||
}
|
||
|
||
destroy(device);
|
||
bool ok = uploadPixels(device, rgba->pixels, rgba->w, rgba->h, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM);
|
||
if (ok) {
|
||
ok = createSampler(device, nearest);
|
||
}
|
||
|
||
if (need_free) {
|
||
SDL_DestroySurface(rgba);
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
auto GpuTexture::createRenderTarget(SDL_GPUDevice* device, int w, int h, SDL_GPUTextureFormat format) -> bool {
|
||
destroy(device);
|
||
|
||
SDL_GPUTextureCreateInfo info = {};
|
||
info.type = SDL_GPU_TEXTURETYPE_2D;
|
||
info.format = format;
|
||
info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER;
|
||
info.width = static_cast<Uint32>(w);
|
||
info.height = static_cast<Uint32>(h);
|
||
info.layer_count_or_depth = 1;
|
||
info.num_levels = 1;
|
||
info.sample_count = SDL_GPU_SAMPLECOUNT_1;
|
||
|
||
texture_ = SDL_CreateGPUTexture(device, &info);
|
||
if (texture_ == nullptr) {
|
||
SDL_Log("GpuTexture: createRenderTarget failed: %s", SDL_GetError());
|
||
return false;
|
||
}
|
||
width_ = w;
|
||
height_ = h;
|
||
|
||
// Render targets are sampled with linear filter (postfx reads them)
|
||
return createSampler(device, false);
|
||
}
|
||
|
||
auto GpuTexture::createWhite(SDL_GPUDevice* device) -> bool {
|
||
destroy(device);
|
||
// 1×1 white RGBA pixel
|
||
constexpr std::array<Uint8, 4> WHITE = {255, 255, 255, 255};
|
||
bool ok = uploadPixels(device, WHITE.data(), 1, 1, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM);
|
||
if (ok) {
|
||
ok = createSampler(device, true);
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
void GpuTexture::destroy(SDL_GPUDevice* device) {
|
||
if (device == nullptr) {
|
||
return;
|
||
}
|
||
if (sampler_ != nullptr) {
|
||
SDL_ReleaseGPUSampler(device, sampler_);
|
||
sampler_ = nullptr;
|
||
}
|
||
if (texture_ != nullptr) {
|
||
SDL_ReleaseGPUTexture(device, texture_);
|
||
texture_ = nullptr;
|
||
}
|
||
width_ = height_ = 0;
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Private helpers
|
||
// ---------------------------------------------------------------------------
|
||
|
||
auto GpuTexture::uploadPixels(SDL_GPUDevice* device, const void* pixels, int w, int h, SDL_GPUTextureFormat format) -> bool {
|
||
// Create GPU texture
|
||
SDL_GPUTextureCreateInfo tex_info = {};
|
||
tex_info.type = SDL_GPU_TEXTURETYPE_2D;
|
||
tex_info.format = format;
|
||
tex_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
|
||
tex_info.width = static_cast<Uint32>(w);
|
||
tex_info.height = static_cast<Uint32>(h);
|
||
tex_info.layer_count_or_depth = 1;
|
||
tex_info.num_levels = 1;
|
||
tex_info.sample_count = SDL_GPU_SAMPLECOUNT_1;
|
||
|
||
texture_ = SDL_CreateGPUTexture(device, &tex_info);
|
||
if (texture_ == nullptr) {
|
||
SDL_Log("GpuTexture: SDL_CreateGPUTexture failed: %s", SDL_GetError());
|
||
return false;
|
||
}
|
||
|
||
// Create transfer buffer and upload pixels
|
||
auto data_size = static_cast<Uint32>(w * h * 4); // RGBA = 4 bytes/pixel
|
||
|
||
SDL_GPUTransferBufferCreateInfo tb_info = {};
|
||
tb_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
|
||
tb_info.size = data_size;
|
||
|
||
SDL_GPUTransferBuffer* transfer = SDL_CreateGPUTransferBuffer(device, &tb_info);
|
||
if (transfer == nullptr) {
|
||
SDL_Log("GpuTexture: transfer buffer creation failed: %s", SDL_GetError());
|
||
SDL_ReleaseGPUTexture(device, texture_);
|
||
texture_ = nullptr;
|
||
return false;
|
||
}
|
||
|
||
void* mapped = SDL_MapGPUTransferBuffer(device, transfer, false);
|
||
if (mapped == nullptr) {
|
||
SDL_Log("GpuTexture: map failed: %s", SDL_GetError());
|
||
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
||
SDL_ReleaseGPUTexture(device, texture_);
|
||
texture_ = nullptr;
|
||
return false;
|
||
}
|
||
memcpy(mapped, pixels, data_size);
|
||
SDL_UnmapGPUTransferBuffer(device, transfer);
|
||
|
||
// Upload via command buffer
|
||
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device);
|
||
SDL_GPUCopyPass* copy = SDL_BeginGPUCopyPass(cmd);
|
||
|
||
SDL_GPUTextureTransferInfo src = {};
|
||
src.transfer_buffer = transfer;
|
||
src.offset = 0;
|
||
src.pixels_per_row = static_cast<Uint32>(w);
|
||
src.rows_per_layer = static_cast<Uint32>(h);
|
||
|
||
SDL_GPUTextureRegion dst = {};
|
||
dst.texture = texture_;
|
||
dst.mip_level = 0;
|
||
dst.layer = 0;
|
||
dst.x = dst.y = dst.z = 0;
|
||
dst.w = static_cast<Uint32>(w);
|
||
dst.h = static_cast<Uint32>(h);
|
||
dst.d = 1;
|
||
|
||
SDL_UploadToGPUTexture(copy, &src, &dst, false);
|
||
SDL_EndGPUCopyPass(copy);
|
||
SDL_SubmitGPUCommandBuffer(cmd);
|
||
|
||
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
||
width_ = w;
|
||
height_ = h;
|
||
return true;
|
||
}
|
||
|
||
auto GpuTexture::createSampler(SDL_GPUDevice* device, bool nearest) -> bool {
|
||
SDL_GPUSamplerCreateInfo info = {};
|
||
info.min_filter = nearest ? SDL_GPU_FILTER_NEAREST : SDL_GPU_FILTER_LINEAR;
|
||
info.mag_filter = nearest ? SDL_GPU_FILTER_NEAREST : SDL_GPU_FILTER_LINEAR;
|
||
info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
|
||
info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
||
info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
||
info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
||
|
||
sampler_ = SDL_CreateGPUSampler(device, &info);
|
||
if (sampler_ == nullptr) {
|
||
SDL_Log("GpuTexture: SDL_CreateGPUSampler failed: %s", SDL_GetError());
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|