tileset: initial GPU texture atlas w/ procedural sprite painting
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I7b6991f7342362033ad72ab4700fdb9f6a6a6964
This commit is contained in:
parent
e00424a918
commit
ceb657add8
5 changed files with 1171 additions and 0 deletions
118
libs/tileset/tileset.c
Normal file
118
libs/tileset/tileset.c
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#include "tileset.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int tileset_init(Tileset *ts, int tile_w, int tile_h) {
|
||||
if (ts == NULL)
|
||||
return 0;
|
||||
if (tile_w <= 0 || tile_h <= 0)
|
||||
return 0;
|
||||
|
||||
memset(ts, 0, sizeof(Tileset));
|
||||
|
||||
ts->tile_w = tile_w;
|
||||
ts->tile_h = tile_h;
|
||||
|
||||
// Compute grid dimensions to fit MAX_TILE_ID tiles
|
||||
ts->atlas_cols = 4; // 4 columns
|
||||
ts->atlas_rows = (MAX_TILE_ID + ts->atlas_cols - 1) / ts->atlas_cols; // round up
|
||||
|
||||
int atlas_w = ts->atlas_cols * tile_w;
|
||||
int atlas_h = ts->atlas_rows * tile_h;
|
||||
|
||||
// Validate atlas dimensions are reasonable
|
||||
if (atlas_w <= 0 || atlas_h <= 0 || atlas_w > 4096 || atlas_h > 4096)
|
||||
return 0;
|
||||
|
||||
ts->render_target = LoadRenderTexture(atlas_w, atlas_h);
|
||||
if (!IsRenderTextureValid(ts->render_target))
|
||||
return 0;
|
||||
|
||||
// Clear to transparent so unpainted regions don't show artifacts
|
||||
BeginTextureMode(ts->render_target);
|
||||
ClearBackground(BLANK);
|
||||
EndTextureMode();
|
||||
|
||||
ts->finalized = 0;
|
||||
ts->tile_count = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tileset_register(Tileset *ts, int id) {
|
||||
if (ts == NULL)
|
||||
return 0;
|
||||
if (id < 0 || id >= MAX_TILE_ID)
|
||||
return 0;
|
||||
if (ts->render_target.id == 0)
|
||||
return 0;
|
||||
if (ts->finalized)
|
||||
return 0;
|
||||
if (ts->regions[id].width != 0)
|
||||
return 0; // already registered
|
||||
|
||||
int col = id % ts->atlas_cols;
|
||||
int row = id / ts->atlas_cols;
|
||||
|
||||
ts->regions[id] =
|
||||
(Rectangle){(float)(col * ts->tile_w), (float)(row * ts->tile_h), (float)ts->tile_w, (float)ts->tile_h};
|
||||
ts->tile_count++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tileset_finalize(Tileset *ts) {
|
||||
if (ts == NULL)
|
||||
return 0;
|
||||
if (ts->render_target.id == 0)
|
||||
return 0;
|
||||
if (ts->finalized)
|
||||
return 1; // already finalized
|
||||
|
||||
// Convert RenderTexture to regular Texture2D
|
||||
// RenderTexture textures are flipped vertically in raylib, so we need to handle that
|
||||
Texture2D old_texture = ts->render_target.texture;
|
||||
|
||||
// Create a new texture from the render texture data
|
||||
Image img = LoadImageFromTexture(old_texture);
|
||||
if (img.data == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Flip image vertically because RenderTexture is upside-down
|
||||
ImageFlipVertical(&img);
|
||||
|
||||
Texture2D new_tex = LoadTextureFromImage(img);
|
||||
UnloadImage(img);
|
||||
|
||||
if (new_tex.id == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Unload the old render texture and replace with the new regular texture
|
||||
UnloadRenderTexture(ts->render_target);
|
||||
ts->render_target.id = 0;
|
||||
ts->atlas = new_tex;
|
||||
ts->finalized = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Rectangle tileset_get_region(const Tileset *ts, int id) {
|
||||
if (ts == NULL || id < 0 || id >= MAX_TILE_ID)
|
||||
return (Rectangle){0, 0, 0, 0};
|
||||
if (!ts->finalized)
|
||||
return (Rectangle){0, 0, 0, 0};
|
||||
return ts->regions[id];
|
||||
}
|
||||
|
||||
void tileset_destroy(Tileset *ts) {
|
||||
if (ts == NULL)
|
||||
return;
|
||||
if (ts->finalized) {
|
||||
if (ts->atlas.id != 0)
|
||||
UnloadTexture(ts->atlas);
|
||||
} else {
|
||||
if (ts->render_target.id != 0)
|
||||
UnloadRenderTexture(ts->render_target);
|
||||
}
|
||||
memset(ts, 0, sizeof(Tileset));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue