feat(service-menu): esquelet amb F12, brackets sci-fi i highlight animat

This commit is contained in:
JailDesigner committed 2026-05-24 11:25:09 +02:00
1 parent cc16908b86
commit 443b461974
12 files changed
+722 -1

No files matched your search

@@ -5,6 +5,7 @@
#include <SDL3/SDL.h>
#include <SDL3/SDL_gpu.h>
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cstring>
@@ -390,6 +391,10 @@ namespace Rendering::GPU {
color_target.store_op = SDL_GPU_STOREOP_STORE;
render_pass_ = SDL_BeginGPURenderPass(cmd_buffer_, &color_target, 1, nullptr);
// L'scissor és per render pass: en reobrir cal restaurar-lo des del top
// de la pila si pushClip/popClip s'han usat mid-frame.
applyCurrentScissor();
SDL_BindGPUGraphicsPipeline(render_pass_, line_pipeline_.get());
// UBO de líneas usa el tamaño lógico (también del offscreen).
@@ -415,6 +420,11 @@ namespace Rendering::GPU {
SDL_ReleaseGPUBuffer(dev, vbo);
SDL_ReleaseGPUBuffer(dev, ibo);
SDL_ReleaseGPUTransferBuffer(dev, tbo);
// Buidem el batch perquè pushClip/popClip puguin emetre seccions
// separades dins el mateix frame sense re-enviar geometria.
vertices_.clear();
indices_.clear();
}
void GpuFrameRenderer::bloomPass() {
@@ -603,6 +613,51 @@ namespace Rendering::GPU {
SDL_DrawGPUPrimitives(render_pass_, 3, 1, 0, 0);
}
void GpuFrameRenderer::pushClip(int logical_x, int logical_y, int logical_w, int logical_h) {
// Convertim coordenades lògiques (espai del joc, 1280×720) a píxels
// físics del offscreen (render_w_ × render_h_). Si l'usuari hi treballa
// amb upscale (p.ex. 1920×1080), l'scissor escala proporcionalment.
const float SX = render_w_ / logical_w_;
const float SY = render_h_ / logical_h_;
SDL_Rect rect{
.x = static_cast<int>(static_cast<float>(logical_x) * SX),
.y = static_cast<int>(static_cast<float>(logical_y) * SY),
.w = std::max(0, static_cast<int>(static_cast<float>(logical_w) * SX)),
.h = std::max(0, static_cast<int>(static_cast<float>(logical_h) * SY)),
};
// Emetem tot el batch acumulat *abans* d'activar l'scissor perquè quedi
// dibuixat sense retallar.
flushBatch();
clip_stack_.push_back(rect);
applyCurrentScissor();
}
void GpuFrameRenderer::popClip() {
// Emetem el batch que s'ha acumulat *dins* del clip actiu.
flushBatch();
if (!clip_stack_.empty()) {
clip_stack_.pop_back();
}
applyCurrentScissor();
}
void GpuFrameRenderer::applyCurrentScissor() {
if (render_pass_ == nullptr) {
return;
}
SDL_Rect rect{};
if (clip_stack_.empty()) {
// Sense clips: scissor cobreix tot el offscreen.
rect.x = 0;
rect.y = 0;
rect.w = static_cast<int>(render_w_);
rect.h = static_cast<int>(render_h_);
} else {
rect = clip_stack_.back();
}
SDL_SetGPUScissor(render_pass_, &rect);
}
void GpuFrameRenderer::endFrame() {
if (cmd_buffer_ == nullptr) {
return;
@@ -94,6 +94,15 @@ namespace Rendering::GPU {
// d'UI (notificacions, panels).
void pushRect(float x, float y, float w, float h, float r, float g, float b, float a);
// Clipping rectangular per a UI (scissor a SDL_GPU). pushClip/popClip
// forcen un flush intermedi del batch i activen/restauren l'scissor del
// pase actiu. Coordenades en píxels lògics del joc (1280×720); es
// converteixen a píxels físics del offscreen automàticament. Stack
// d'scissors per a clips niats. Quan la pila queda buida, l'scissor
// torna a cobrir el target sencer.
void pushClip(int logical_x, int logical_y, int logical_w, int logical_h);
void popClip();
// endFrame: flush del batch de líneas → composite postpro → submit + presenta.
void endFrame();
@@ -168,6 +177,10 @@ namespace Rendering::GPU {
std::vector<LineVertex> vertices_;
std::vector<uint16_t> indices_;
// Pila d'scissors actius en píxels físics del offscreen. Buida = sense
// clip (full target). Cada push/pop fa un flushBatch i reaplica scissor.
std::vector<SDL_Rect> clip_stack_;
// Estado del frame en curso.
SDL_GPUCommandBuffer* cmd_buffer_{nullptr};
SDL_GPUTexture* swapchain_texture_{nullptr};
@@ -190,6 +203,7 @@ namespace Rendering::GPU {
void bloomPass(); // pre-composite: H + V passes sobre les bloom textures
void compositePass();
void applyFinalViewport();
void applyCurrentScissor(); // re-aplica el top de clip_stack_ al render_pass_
};
} // namespace Rendering::GPU