GpuSpriteBatch::init() ahora acepta capacidad dinámica para soportar --custom-balls N con N > 200000. El buffer se dimensiona a (N+1) quads, reservando siempre un slot para el overlay. addFullscreenOverlay() calcula overlay_index_count_ desde el delta real de indices_ en lugar de fijarlo a 6 incondicionalmente. Engine calcula la capacidad correcta al init. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
89 lines
3.5 KiB
C++
89 lines
3.5 KiB
C++
#pragma once
|
||
|
||
#include <SDL3/SDL_gpu.h>
|
||
#include <vector>
|
||
#include <cstdint>
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// GpuVertex — 8-float vertex layout sent to the GPU.
|
||
// Position is in NDC (pre-transformed on CPU), UV in [0,1], color in [0,1].
|
||
// ---------------------------------------------------------------------------
|
||
struct GpuVertex {
|
||
float x, y; // NDC position (−1..1)
|
||
float u, v; // Texture coords (0..1)
|
||
float r, g, b, a; // RGBA color (0..1)
|
||
};
|
||
|
||
// ============================================================================
|
||
// GpuSpriteBatch — Accumulates sprite quads, uploads them in one copy pass.
|
||
//
|
||
// Usage per frame:
|
||
// batch.beginFrame();
|
||
// batch.addBackground(...); // Must be first (bg indices = [0..5])
|
||
// batch.addSprite(...) × N;
|
||
// batch.uploadBatch(device, cmd); // Copy pass
|
||
// // Then in render pass: bind buffers, draw bg with white tex, draw sprites.
|
||
// ============================================================================
|
||
class GpuSpriteBatch {
|
||
public:
|
||
// Default maximum sprites (background + UI overlay each count as one sprite)
|
||
static constexpr int DEFAULT_MAX_SPRITES = 200000;
|
||
|
||
bool init(SDL_GPUDevice* device, int max_sprites = DEFAULT_MAX_SPRITES);
|
||
void destroy(SDL_GPUDevice* device);
|
||
|
||
void beginFrame();
|
||
|
||
// Add the full-screen background gradient quad.
|
||
// top_* and bot_* are RGB in [0,1].
|
||
void addBackground(float screen_w, float screen_h,
|
||
float top_r, float top_g, float top_b,
|
||
float bot_r, float bot_g, float bot_b);
|
||
|
||
// Add a sprite quad (pixel coordinates).
|
||
// scale: uniform scale around the quad centre.
|
||
void addSprite(float x, float y, float w, float h,
|
||
float r, float g, float b, float a,
|
||
float scale,
|
||
float screen_w, float screen_h);
|
||
|
||
// Add a full-screen overlay quad (e.g. UI surface, NDC −1..1).
|
||
void addFullscreenOverlay();
|
||
|
||
// Upload CPU vectors to GPU buffers via a copy pass.
|
||
// Returns false if the batch is empty.
|
||
bool uploadBatch(SDL_GPUDevice* device, SDL_GPUCommandBuffer* cmd_buf);
|
||
|
||
SDL_GPUBuffer* vertexBuffer() const { return vertex_buf_; }
|
||
SDL_GPUBuffer* indexBuffer() const { return index_buf_; }
|
||
int bgIndexCount() const { return bg_index_count_; }
|
||
int overlayIndexOffset() const { return overlay_index_offset_; }
|
||
int overlayIndexCount() const { return overlay_index_count_; }
|
||
int spriteIndexOffset() const { return sprite_index_offset_; }
|
||
int spriteIndexCount() const { return sprite_index_count_; }
|
||
bool isEmpty() const { return vertices_.empty(); }
|
||
|
||
private:
|
||
void toNDC(float px, float py, float screen_w, float screen_h,
|
||
float& ndx, float& ndy) const;
|
||
void pushQuad(float ndx0, float ndy0, float ndx1, float ndy1,
|
||
float u0, float v0, float u1, float v1,
|
||
float r, float g, float b, float a);
|
||
|
||
std::vector<GpuVertex> vertices_;
|
||
std::vector<uint32_t> indices_;
|
||
|
||
SDL_GPUBuffer* vertex_buf_ = nullptr;
|
||
SDL_GPUBuffer* index_buf_ = nullptr;
|
||
SDL_GPUTransferBuffer* vertex_transfer_ = nullptr;
|
||
SDL_GPUTransferBuffer* index_transfer_ = nullptr;
|
||
|
||
int bg_index_count_ = 0;
|
||
int sprite_index_offset_ = 0;
|
||
int sprite_index_count_ = 0;
|
||
int overlay_index_offset_ = 0;
|
||
int overlay_index_count_ = 0;
|
||
|
||
int max_sprites_ = DEFAULT_MAX_SPRITES;
|
||
};
|