diff --git a/source/demo1_sdl_main_callbacks.cpp b/source/demo1_1_callbacks.cpp similarity index 100% rename from source/demo1_sdl_main_callbacks.cpp rename to source/demo1_1_callbacks.cpp diff --git a/source/demo1_raii.cpp b/source/demo1_2_callbacks_raii.cpp similarity index 100% rename from source/demo1_raii.cpp rename to source/demo1_2_callbacks_raii.cpp diff --git a/source/demo1_3_callbacks_raii_sdlgpu.cpp b/source/demo1_3_callbacks_raii_sdlgpu.cpp new file mode 100644 index 0000000..ffb175e --- /dev/null +++ b/source/demo1_3_callbacks_raii_sdlgpu.cpp @@ -0,0 +1,164 @@ +#define SDL_MAIN_USE_CALLBACKS +#include +#include +#include +#include +#include +#include + +class PixelApp { +public: + static constexpr int WIDTH = 160; + static constexpr int HEIGHT = 160; + static constexpr int SIZE = WIDTH * HEIGHT; + static constexpr int ZOOM = 4; + + PixelApp() = default; + ~PixelApp() { cleanup(); } + + bool init() { + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GPU)) + return false; + + window.reset(SDL_CreateWindow("pixels (GPU)", WIDTH * ZOOM, HEIGHT * ZOOM, SDL_WINDOW_RESIZABLE)); + if (!window) return false; + + device.reset(SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV)); + if (!device) return false; + + if (!SDL_ClaimWindowForGPUDevice(device.get(), window.get())) + return false; + + // Crear textura GPU donde escribiremos los píxeles + SDL_GPUTextureCreateInfo info{}; + info.type = SDL_GPU_TEXTURETYPE_2D; + info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; + info.width = WIDTH; + info.height = HEIGHT; + info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLED | SDL_GPU_TEXTUREUSAGE_COPY_SRC | SDL_GPU_TEXTUREUSAGE_COPY_DST; + + texture.reset(SDL_CreateGPUTexture(device.get(), &info)); + if (!texture) return false; + + palette = { 0xFF000000, 0xFFFFFFFF }; + surface.fill(0); + + return true; + } + + void handleEvent(const SDL_Event& e, SDL_AppResult& result) { + if (e.type == SDL_EVENT_QUIT || + (e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_ESCAPE)) + { + result = SDL_APP_SUCCESS; + } + } + + void update() { + // --- 1. Generar efecto en CPU --- + surface.fill(0); + + float time = SDL_GetTicks() / 1000.0f; + int rad = 96; + int dx = (WIDTH - rad * 2) / 2; + int dy = (HEIGHT - rad * 2) / 2; + + for (int j = -rad; j <= rad; j += 3) { + for (int i = -rad; i <= rad; i += 2) { + float dist = std::sqrt(float(i * i + j * j)); + float z = std::cos((dist / 40 - time) * M_PI * 2) * 6; + + int X = rad + i + dx; + int Y = rad + j - z + dy; + + if (X >= 0 && X < WIDTH && Y >= 0 && Y < HEIGHT) + surface[X + Y * WIDTH] = 1; + } + } + + // --- 2. Mapear textura GPU --- + SDL_GPUTextureRegion region{}; + region.texture = texture.get(); + region.w = WIDTH; + region.h = HEIGHT; + + void* mapped = nullptr; + uint32_t pitch = 0; + + if (!SDL_MapGPUTexture(device.get(), ®ion, &mapped, &pitch)) + return; + + // --- 3. Copiar píxeles CPU → GPU --- + Uint32* dst = reinterpret_cast(mapped); + uint32_t rowPixels = pitch / sizeof(Uint32); + + for (int y = 0; y < HEIGHT; ++y) { + for (int x = 0; x < WIDTH; ++x) { + dst[x + y * rowPixels] = palette[surface[x + y * WIDTH]]; + } + } + + SDL_UnmapGPUTexture(device.get(), ®ion); + + // --- 4. Renderizar textura en pantalla --- + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device.get()); + if (!cmd) return; + + SDL_GPUCopyPass* pass = SDL_BeginGPUCopyPass(cmd); + SDL_GPUBlitInfo blit{}; + blit.source.texture = texture.get(); + blit.source.w = WIDTH; + blit.source.h = HEIGHT; + blit.destination.x = 0; + blit.destination.y = 0; + blit.destination.w = WIDTH * ZOOM; + blit.destination.h = HEIGHT * ZOOM; + + SDL_BlitGPUTexture(pass, &blit); + SDL_EndGPUCopyPass(pass); + + SDL_SubmitGPUCommandBuffer(cmd); + } + +private: + struct SDL_Deleter { + void operator()(SDL_Window* p) const { SDL_DestroyWindow(p); } + void operator()(SDL_GPUDevice* p) const { SDL_DestroyGPUDevice(p); } + void operator()(SDL_GPUTexture* p) const { SDL_DestroyGPUTexture(p); } + }; + + std::unique_ptr window; + std::unique_ptr device; + std::unique_ptr texture; + + std::array surface; + std::array palette; + + void cleanup() { + texture.reset(); + device.reset(); + window.reset(); + SDL_Quit(); + } +}; + +static PixelApp app; + +SDL_AppResult SDL_AppInit(void**, int, char**) { + return app.init() ? SDL_APP_CONTINUE : SDL_APP_FAILURE; +} + +SDL_AppResult SDL_AppEvent(void*, SDL_Event* e) { + SDL_AppResult result = SDL_APP_CONTINUE; + app.handleEvent(*e, result); + return result; +} + +SDL_AppResult SDL_AppIterate(void*) { + app.update(); + return SDL_APP_CONTINUE; +} + +void SDL_AppQuit(void*, SDL_AppResult) { + // RAII limpia todo +}