Add in-game level editor with auto-discovered tile/entity palettes

Implements a full level editor that runs inside the game engine as an
alternative mode, accessible via --edit flag or E key during gameplay.
The editor auto-discovers available tiles from the tileset texture and
entities from a new central registry, so adding new game content
automatically appears in the editor without any editor-specific changes.

Editor features: tile painting (pencil/eraser/flood fill) across 3
layers, entity placement with drag-to-move, player spawn point tool,
camera pan/zoom, grid overlay, .lvl save/load, map resize, and test
play (P to play, ESC to return to editor).

Supporting changes:
- Entity registry centralizes spawn functions (replaces strcmp chain)
- Mouse input + raw keyboard access added to input system
- Camera zoom support for editor overview
- Zoom-aware rendering in tilemap, renderer, and sprite systems
- Powerup and drone sprites/animations wired up (were defined but unused)
- Bitmap font renderer for editor UI (4x6 pixel glyphs, no dependencies)
This commit is contained in:
Thomas
2026-02-28 20:24:43 +00:00
parent c66c12ae68
commit ea6e16358f
30 changed files with 4959 additions and 51 deletions

98
src/game/editor.h Normal file
View File

@@ -0,0 +1,98 @@
#ifndef JNR_EDITOR_H
#define JNR_EDITOR_H
#include "engine/tilemap.h"
#include "engine/camera.h"
#include <SDL2/SDL.h>
#include <stdbool.h>
/* ═══════════════════════════════════════════════════
* Level Editor
*
* An in-engine level editor that runs as an
* alternative game mode. Uses the same renderer,
* camera, and tilemap systems as gameplay.
*
* Tile palette is auto-discovered from the tileset
* texture. Entity palette is auto-discovered from
* the entity registry. Adding new tiles or entities
* to the game makes them appear in the editor
* automatically.
* ═══════════════════════════════════════════════════ */
typedef enum EditorTool {
TOOL_PENCIL, /* paint tiles */
TOOL_ERASER, /* clear tiles (paint tile 0) */
TOOL_FILL, /* flood fill area */
TOOL_ENTITY, /* place/select entities */
TOOL_SPAWN, /* set player spawn point */
TOOL_COUNT
} EditorTool;
typedef enum EditorLayer {
EDITOR_LAYER_COLLISION,
EDITOR_LAYER_BG,
EDITOR_LAYER_FG,
EDITOR_LAYER_COUNT
} EditorLayer;
/* UI panel regions */
#define EDITOR_TOOLBAR_H 14 /* top bar height */
#define EDITOR_PALETTE_W 80 /* right panel width */
#define EDITOR_STATUS_H 10 /* bottom status bar height */
typedef struct Editor {
/* ── Map data ──────────────────────────── */
Tilemap map;
char file_path[256];
bool has_file; /* true if loaded from / saved to file */
bool dirty; /* unsaved changes */
/* ── Camera ────────────────────────────── */
Camera camera;
/* ── Tool state ────────────────────────── */
EditorTool tool;
EditorLayer active_layer;
uint16_t selected_tile; /* currently selected tile ID */
int selected_entity; /* index into entity registry */
bool show_grid;
bool show_all_layers; /* dim inactive layers */
/* ── Entity editing ────────────────────── */
int dragging_entity; /* index in entity_spawns, or -1 */
float drag_offset_x; /* offset from entity origin to mouse */
float drag_offset_y;
/* ── Palette scroll ────────────────────── */
int tile_palette_scroll;
int entity_palette_scroll;
/* ── Tileset info (auto-discovered) ────── */
int tileset_cols;
int tileset_rows;
int tileset_total; /* total tiles in tileset */
/* ── UI state ──────────────────────────── */
bool active; /* editor is running */
} Editor;
/* Lifecycle */
void editor_init(Editor *ed);
void editor_new_level(Editor *ed, int width, int height);
bool editor_load(Editor *ed, const char *path);
bool editor_save(Editor *ed);
bool editor_save_as(Editor *ed, const char *path);
void editor_free(Editor *ed);
/* Frame callbacks (plug into engine) */
void editor_update(Editor *ed, float dt);
void editor_render(Editor *ed, float interpolation);
/* Returns true if the user pressed the test-play key */
bool editor_wants_test_play(Editor *ed);
/* Returns true if the editor wants to quit */
bool editor_wants_quit(Editor *ed);
#endif /* JNR_EDITOR_H */