tiling progress

This commit is contained in:
jacob 2025-12-17 15:37:56 -06:00
parent 1b9208dd3b
commit cd48dd53ff
11 changed files with 529 additions and 219 deletions

View File

@ -45,6 +45,37 @@ u32 countof(T arr[N])
return N;
}
////////////////////////////////////////////////////////////
//~ Min / max
//- Min
#define MinU8(...) min(__VA_ARGS__)
#define MinI8(...) min(__VA_ARGS__)
#define MinU32(...) min(__VA_ARGS__)
#define MinI32(...) min(__VA_ARGS__)
#define MinF32(...) min(__VA_ARGS__)
#define MinU64(...) min(__VA_ARGS__)
#define MinI64(...) min(__VA_ARGS__)
#define MinF64(...) min(__VA_ARGS__)
//- Max
#define MaxU8(...) max(__VA_ARGS__)
#define MaxI8(...) max(__VA_ARGS__)
#define MaxU32(...) max(__VA_ARGS__)
#define MaxI32(...) max(__VA_ARGS__)
#define MaxF32(...) max(__VA_ARGS__)
#define MaxU64(...) max(__VA_ARGS__)
#define MaxI64(...) max(__VA_ARGS__)
#define MaxF64(...) max(__VA_ARGS__)
//- Clamp
#define ClampU32(...) clamp(__VA_ARGS__)
#define ClampI32(...) clamp(__VA_ARGS__)
#define ClampF32(...) clamp(__VA_ARGS__)
#define ClampU64(...) clamp(__VA_ARGS__)
#define ClampI64(...) clamp(__VA_ARGS__)
#define ClampF64(...) clamp(__VA_ARGS__)
////////////////////////////////////////////////////////////
//~ Color helpers

View File

@ -69,7 +69,7 @@
#define FLOOD_DEBUG 0
#define GPU_DEBUG 0
#define GPU_DEBUG 1
#define GPU_DEBUG_VALIDATION 0
#define GPU_SHADER_PRINT 1

View File

@ -8,6 +8,8 @@
//////////////////////////////
//- Api
@IncludeC pp_sim_tiles.cgh
@IncludeG pp_sim_tiles.cgh
@IncludeC pp_sim_core.h
@Bootstrap S_Bootstrap
@ -16,3 +18,5 @@
//- Impl
@IncludeC pp_sim_core.c
@IncludeC pp_sim_tiles.cg
@IncludeG pp_sim_tiles.cg

View File

@ -62,6 +62,30 @@ S_Key S_RandKey(void)
return result;
}
////////////////////////////////////////////////////////////
//~ Tile helpers
void S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement)
{
switch (placement.placement_kind)
{
case S_TilePlacementKind_Range:
{
S_TileKind tile = placement.tile_kind;
Rng2I32 range = placement.range;
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
{
for (i32 tile_x = range.p0.y; tile_x < range.p1.y; ++tile_x)
{
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
tiles[tile_idx] = (u8)tile;
}
}
} break;
}
}
////////////////////////////////////////////////////////////
//~ Shape helpers
@ -237,6 +261,8 @@ void S_TickForever(WaveLaneCtx *lane)
Arena *frame_arena = AcquireArena(Gibi(64));
Arena *perm = PermArena();
const i32 world_size = S_WorldSize;
//- World data
Arena *ents_arena = AcquireArena(Gibi(64));
S_World *world = PushStruct(perm, S_World);
@ -244,6 +270,8 @@ void S_TickForever(WaveLaneCtx *lane)
i64 first_free_ent_num = 0;
i64 sim_time_ns = 0;
u8 *tiles = PushBytes(perm, world_size * world_size * 4, alignof(S_TileKind));
//////////////////////////////
//- Sim loop
@ -280,42 +308,49 @@ void S_TickForever(WaveLaneCtx *lane)
UnlockTicketMutex(&S.input_back_tm);
//////////////////////////////
//- Spawn entities
//- Process world edit commands
u64 tile_placements_count = 0;
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{
S_Cmd cmd = cmd_node->cmd;
if (cmd.kind == S_CmdKind_Spawn)
{
for (S_EntListNode *src_n = cmd.ents.first; src_n; src_n = src_n->next)
{
S_Ent *src = &src_n->ent;
S_Key key = src->key;
if (!S_IsKeyNil(key))
{
S_Ent *dst = S_EntFromKey(&lookup, key);
if (S_IsEntNil(dst))
{
if (first_free_ent_num > 0)
{
dst = &world->ents[first_free_ent_num - 1];
first_free_ent_num = dst->next_free_ent_num;
}
else
{
dst = PushStructNoZero(ents_arena, S_Ent);
}
*dst = S_ro.nil_ent;
dst->key = key;
++world->ents_count;
}
*dst = *src;
dst->local_shape.points_count = MaxI32(dst->local_shape.points_count, 1);
S_Cmd *cmd = &cmd_node->cmd;
dst->active = 1;
/* Spawn entity */
if (cmd->kind == S_CmdKind_Spawn)
{
S_Ent *src = &cmd->ent;
S_Key key = src->key;
if (!S_IsKeyNil(key))
{
S_Ent *dst = S_EntFromKey(&lookup, key);
if (S_IsEntNil(dst))
{
if (first_free_ent_num > 0)
{
dst = &world->ents[first_free_ent_num - 1];
first_free_ent_num = dst->next_free_ent_num;
}
else
{
dst = PushStructNoZero(ents_arena, S_Ent);
}
*dst = S_ro.nil_ent;
dst->key = key;
++world->ents_count;
}
*dst = *src;
dst->local_shape.points_count = MaxI32(dst->local_shape.points_count, 1);
dst->active = 1;
}
LogInfoF("Received spawn cmd containing %F ents. New count: %F", FmtSint(cmd.ents.count), FmtSint(world->ents_count));
}
/* Place tiles */
if (cmd->kind == S_CmdKind_Tile)
{
tile_placements_count += 1;
S_TilePlacement placement = cmd->tile_placement;
S_UpdateTilesInPlaceFromPlacement(tiles, placement);
}
}
lookup = S_LookupFromWorld(frame_arena, world);
@ -377,6 +412,24 @@ void S_TickForever(WaveLaneCtx *lane)
S_Ent *dst = &snapshot->ents[ent_idx];
*dst = *src;
}
/* Forward tile placements */
snapshot->tile_placements_count = tile_placements_count;
snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count);
{
u64 tile_placement_idx = 0;
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node && tile_placement_idx < tile_placements_count; cmd_node = cmd_node->next)
{
S_Cmd *cmd = &cmd_node->cmd;
if (cmd->kind == S_CmdKind_Tile)
{
S_TilePlacement *dst_placement = &snapshot->tile_placements[tile_placement_idx];
*dst_placement = cmd->tile_placement;
tile_placement_idx += 1;
}
}
}
}
UnlockTicketMutex(&S.output_back_tm);

View File

@ -105,6 +105,7 @@ Struct(S_Lookup)
Struct(S_World)
{
i64 tick;
S_Ent *ents;
i64 ents_count;
};
@ -112,8 +113,12 @@ Struct(S_World)
Struct(S_Snapshot)
{
i64 tick;
S_Ent *ents;
i64 ents_count;
S_TilePlacement *tile_placements;
u64 tile_placements_count;
};
Struct(S_SnapshotNode)
@ -137,6 +142,7 @@ Struct(S_Iter)
Enum(S_CmdKind)
{
S_CmdKind_Nop,
S_CmdKind_Tile,
S_CmdKind_Spawn,
S_CmdKind_Control,
};
@ -145,8 +151,11 @@ Struct(S_Cmd)
{
S_CmdKind kind;
/* Tiles */
S_TilePlacement tile_placement;
/* Spawn */
S_EntList ents;
S_Ent ent;
/* Control */
S_Key target;
@ -226,6 +235,11 @@ b32 S_MatchKey(S_Key a, S_Key b);
S_Key S_RandKey(void);
////////////////////////////////////////////////////////////
//~ Tile helpers
void S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement);
////////////////////////////////////////////////////////////
//~ Shape helpers

View File

@ -0,0 +1,16 @@
////////////////////////////////////////////////////////////
//~ Tile helpers
Vec2I32 S_TilePosFromWorldPos(Vec2 p)
{
Vec2I32 result;
result.x = ClampI32((p.x + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
result.y = ClampI32((p.y + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
return result;
}
i32 S_TileIdxFromTilePos(Vec2I32 p)
{
i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4);
return result;
}

View File

@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////
//~ Tile types
#define S_WorldSize 128
Enum(S_TileKind)
{
S_TileKind_None,
S_TileKind_Floor,
S_TileKind_Wall,
};
Enum(S_TilePlacementKind)
{
S_TilePlacementKind_Range
};
Struct(S_TilePlacement)
{
S_TilePlacementKind placement_kind;
S_TileKind tile_kind;
Rng2I32 range;
};
////////////////////////////////////////////////////////////
//~ Tile helpers
Vec2I32 S_TilePosFromWorldPos(Vec2 p);
i32 S_TileIdxFromTilePos(Vec2I32 p);

View File

@ -14,12 +14,37 @@ void V_Shutdown(void)
YieldOnFence(&V.shutdown_complete, 1);
}
////////////////////////////////////////////////////////////
//~ Helpers
V_Frame *V_CurrentFrame(void)
{
return &V.frames[V.current_frame_idx];
}
S_Cmd *V_PushSimCmd(S_CmdKind kind)
{
V_Frame *frame = V_CurrentFrame();
S_CmdNode *n = PushStruct(frame->arena, S_CmdNode);
n->cmd.kind = kind;
SllQueuePush(frame->first_sim_cmd_node, frame->last_sim_cmd_node, n);
++frame->sim_cmds_count;
return &n->cmd;
}
////////////////////////////////////////////////////////////
//~ Vis tick
void V_TickForever(WaveLaneCtx *lane)
{
Arena *perm = PermArena();
G_ArenaHandle gpu_perm = G_PermArena();
const i32 world_size = S_WorldSize;
const f32 zoom_rate = 1.50;
const f32 min_zoom = 0.03;
const f32 max_zoom = 10.0;
const f32 meters_per_draw_width = 20;
//////////////////////////////
//- Init vis state
@ -28,6 +53,16 @@ void V_TickForever(WaveLaneCtx *lane)
V.world = PushStruct(V.world_arena, S_World);
V.player_key = S_RandKey();
u8 *tiles = PushBytes(perm, world_size * world_size * 4, alignof(S_TileKind));
G_ResourceHandle gpu_tiles = G_PushTexture2D(
gpu_perm,
G_Format_R8_Uint,
VEC2I32(world_size, world_size),
G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite
);
G_Texture2DRef gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles);
for (u32 i = 0; i < countof(V.frames); ++i)
{
V_Frame *frame = &V.frames[i];
@ -111,7 +146,7 @@ void V_TickForever(WaveLaneCtx *lane)
Arena *old_arena = frame->arena;
Arena *old_dverts_arena = frame->dverts_arena;
Arena *old_dvert_idxs_arena = frame->dvert_idxs_arena;
G_ArenaHandle old_gpu_arena = frame->gpu_arena;
G_ArenaHandle old_gpu_arena = frame->gpu_arena;
ZeroStruct(frame);
frame->arena = old_arena;
frame->dverts_arena = old_dverts_arena;
@ -127,7 +162,7 @@ void V_TickForever(WaveLaneCtx *lane)
/* Persist state */
CopyBytes(frame->held_buttons, last_frame->held_buttons, sizeof(frame->held_buttons));
frame->commands_widget = last_frame->commands_widget;
frame->edit_mode = last_frame->edit_mode;
frame->is_editing = last_frame->is_editing;
frame->ui_debug = last_frame->ui_debug;
frame->show_command_palette = last_frame->show_command_palette;
frame->show_console = last_frame->show_console;
@ -141,48 +176,26 @@ void V_TickForever(WaveLaneCtx *lane)
frame->dt = SecondsFromNs(frame->dt_ns);
S_Iter iter = Zi;
S_EntList spawn_ents = Zi;
//////////////////////////////
//- Spawn test ents
if (frame->tick == 1)
{
S_Key child_key = S_RandKey();
i32 count = 1;
for (u64 i = 0; i < count; ++i)
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Spawn);
S_Ent *ent = &cmd->ent;
ent->key = V.player_key;
ent->move_speed = 0.1;
{
S_EntListNode *n = PushStruct(frame->arena, S_EntListNode);
SllQueuePush(spawn_ents.first, spawn_ents.last, n);
++spawn_ents.count;
S_Ent *ent = &n->ent;
*ent = S_ro.nil_ent;
switch (i)
{
/* Test player */
case 0:
{
ent->key = V.player_key;
ent->move_speed = 0.1;
{
ent->local_shape = S_ShapeFromDesc(
.mass = 10,
.count = 1,
.radius = 0.4,
);
}
// ent->local_xf = XformFromPos(VEC2(200, 200));
ent->xf = XformFromPos(VEC2(0, 0));
ent->has_weapon = 1;
} break;
default:
{
Assert(0);
} break;
}
ent->local_shape = S_ShapeFromDesc(
.mass = 10,
.count = 1,
.radius = 0.4,
);
}
// ent->local_xf = XformFromPos(VEC2(200, 200));
ent->xf = XformFromPos(VEC2(0, 0));
ent->has_weapon = 1;
}
//////////////////////////////
@ -238,6 +251,34 @@ void V_TickForever(WaveLaneCtx *lane)
}
UnlockTicketMutex(&S.output_back_tm);
//////////////////////////////
//- Update tiles from sim
{
/* TODO: Only upload dirty rects to gpu tile map */
b32 is_dirty = 0;
for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
{
S_Snapshot *snapshot = &n->snapshot;
if (snapshot->tick > V.world->tick)
{
for (u64 placement_idx = 0; placement_idx < snapshot->tile_placements_count; ++placement_idx)
{
is_dirty = 1;
S_TilePlacement placement = snapshot->tile_placements[placement_idx];
S_UpdateTilesInPlaceFromPlacement(tiles, placement);
}
}
}
if (is_dirty)
{
G_CopyCpuToBuffer(frame->cl, gpu_tiles, 0, tiles, RNGU64(0, sizeof(tiles)));
}
}
//////////////////////////////
//- Update world from sim
if (sim_output->last_snapshot_node && sim_output->last_snapshot_node->snapshot.tick > V.world->tick)
{
ResetArena(V.world_arena);
@ -291,18 +332,9 @@ void V_TickForever(WaveLaneCtx *lane)
}
}
//////////////////////////////
//- Update edit mode camera position
//////////////////////////////
//- Initialize world <-> draw <-> ui transforms
f32 zoom_rate = 1.50;
f32 min_zoom = 0.03;
f32 max_zoom = 50.0;
f32 world_size = 256;
f32 meters_per_draw_width = 20;
/* World <-> ui */
frame->world_to_ui_xf = XformIdentity;
frame->ui_to_world_xf = XformIdentity;
@ -310,18 +342,20 @@ void V_TickForever(WaveLaneCtx *lane)
/* Determine target camera pos */
Vec2 target_camera_pos = Zi;
f32 target_camera_zoom = 0;
if (frame->edit_mode)
if (frame->is_editing)
{
b32 pan_button = Button_M3;
frame->is_panning = frame->held_buttons[pan_button] != 0;
frame->edit_camera_zoom *= PowF32(zoom_rate, -last_frame->zooms);
if (frame->edit_camera_zoom <= 0)
{
frame->edit_camera_zoom = 1;
frame->edit_camera_pos = S_EntFromKey(&V.lookup, V.player_key)->xf.og;
frame->edit_camera_zoom = 3;
}
frame->edit_camera_zoom = ClampF32(frame->edit_camera_zoom, min_zoom, max_zoom);
/* Offset edit camera based on cursor if panning / zooming */
if (last_frame->edit_mode && ((last_frame->zooms != 0 && (frame->edit_camera_zoom != last_frame->edit_camera_zoom)) || (frame->is_panning && last_frame->is_panning)))
b32 is_zooming = last_frame->zooms != 0 && (frame->edit_camera_zoom != last_frame->edit_camera_zoom);
if (last_frame->is_editing && (is_zooming || (frame->is_panning && last_frame->is_panning)))
{
Xform last_frame_edit_to_ui_xf = Zi;
Xform edit_to_ui_xf = Zi;
@ -366,7 +400,7 @@ void V_TickForever(WaveLaneCtx *lane)
{
lerp_ratio = 1;
}
else if (frame->edit_mode)
else if (frame->is_editing)
{
lerp_ratio = 30.0 * frame->dt;
}
@ -445,28 +479,67 @@ void V_TickForever(WaveLaneCtx *lane)
if (frame->show_console)
{
f32 padding = 20;
f32 rounding = 0;
Vec4 color = VEC4(0, 0, 0, 0.75);
UI_BuildSpacer(UI_GROW(1, 0), Axis_Y);
// UI_SetNext(Width, UI_SHRINK(0, 1));
// UI_SetNext(Height, UI_SHRINK(0, 1));
UI_SetNext(Width, UI_SHRINK(0, 1));
UI_SetNext(Height, UI_SHRINK(0, 1));
UI_SetNext(BackgroundColor, color);
UI_SetNext(Rounding, UI_RPIX(rounding));
UI_PushCP(UI_BuildColumn());
{
// UI_BuildSpacer(UI_PIX(10, 1), Axis_X);
// UI_Push(ChildAlignment, UI_Alignment_Center);
// UI_SetNext(Width, UI_SHRINK(0, 1));
// UI_SetNext(Height, UI_SHRINK(0, 1));
UI_SetNext(Width, UI_SHRINK(0, 1));
UI_SetNext(Height, UI_SHRINK(0, 1));
UI_PushCP(UI_BuildRow());
{
UI_BuildSpacer(UI_PIX(padding, 1), Axis_X);
UI_SetNext(Width, UI_SHRINK(0, 1));
UI_SetNext(Height, UI_SHRINK(0, 1));
UI_PushCP(UI_BuildColumn());
{
UI_Push(FontSize, 32);
UI_BuildLabelF("CPU:");
UI_Pop(FontSize);
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
Vec2I32 tile_pos = S_TilePosFromWorldPos(frame->world_cursor);
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
{
UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor));
UI_BuildLabelF("Cursor tile pos: %F", FmtSint2(tile_pos));
UI_BuildLabelF("Cursor tile idx: %F", FmtSint(tile_idx));
}
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
{
{
UI_Push(FontSize, 32);
UI_BuildLabelF("CPU:");
UI_Pop(FontSize);
}
UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumArenas)));
UI_BuildLabelF(" Arena memory committed: %F MiB", FmtFloat((f64)GetGstat(ArenaMemoryCommitted) / 1024 / 1024));
UI_BuildLabelF(" Arena memory reserved: %F TiB", FmtFloat((f64)GetGstat(ArenaMemoryReserved) / 1024 / 1024 / 1024 / 1024));
}
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
{
{
UI_Push(FontSize, 32);
UI_BuildLabelF("GPU:");
UI_Pop(FontSize);
}
UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumGpuArenas)));
UI_BuildLabelF(" Dedicated arena memory committed: %F MiB", FmtFloat((f64)GetGstat(DedicatedGpuArenaMemoryCommitted) / 1024 / 1024));
UI_BuildLabelF(" Shared arena memory committed: %F MiB", FmtFloat((f64)GetGstat(SharedGpuArenaMemoryCommitted) / 1024 / 1024));
}
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
}
UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumArenas)));
UI_BuildLabelF(" Arena memory committed: %F MiB", FmtFloat((f64)GetGstat(ArenaMemoryCommitted) / 1024 / 1024));
UI_BuildLabelF(" Arena memory reserved: %F TiB", FmtFloat((f64)GetGstat(ArenaMemoryReserved) / 1024 / 1024 / 1024 / 1024));
}
{
{
UI_Push(FontSize, 32);
UI_BuildLabelF("GPU:");
UI_Pop(FontSize);
}
UI_BuildLabelF(" Arenas: %F", FmtSint(GetGstat(NumGpuArenas)));
UI_BuildLabelF(" Dedicated arena memory committed: %F MiB", FmtFloat((f64)GetGstat(DedicatedGpuArenaMemoryCommitted) / 1024 / 1024));
UI_BuildLabelF(" Shared arena memory committed: %F MiB", FmtFloat((f64)GetGstat(SharedGpuArenaMemoryCommitted) / 1024 / 1024));
UI_PopCP(UI_TopCP());
UI_BuildSpacer(UI_PIX(padding, 1), Axis_X);
}
UI_PopCP(UI_TopCP());
}
UI_PopCP(UI_TopCP());
}
@ -474,7 +547,7 @@ void V_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Build edit mode UI
if (frame->edit_mode)
if (frame->is_editing)
{
}
@ -509,7 +582,7 @@ void V_TickForever(WaveLaneCtx *lane)
case V_CmdKind_zoom_in:
{
if (frame->edit_mode)
if (frame->is_editing)
{
frame->zooms += 1;
}
@ -517,24 +590,24 @@ void V_TickForever(WaveLaneCtx *lane)
case V_CmdKind_zoom_out:
{
if (frame->edit_mode)
if (frame->is_editing)
{
frame->zooms -= 1;
}
} break;
case V_CmdKind_toggle_edit_mode:
case V_CmdKind_toggle_editor:
{
b32 new = !frame->edit_mode;
b32 new = !frame->is_editing;
if (new)
{
LogInfoF("Enabled edit mode");
LogInfoF("Enabled editor");
}
else
{
LogInfoF("Disabled edit mode");
LogInfoF("Disabled editor");
}
frame->edit_mode = new;
frame->is_editing = new;
} break;
case V_CmdKind_toggle_ui_debug:
@ -564,6 +637,11 @@ void V_TickForever(WaveLaneCtx *lane)
case V_CmdKind_spawn:
{
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Tile);
cmd->tile_placement.placement_kind = S_TilePlacementKind_Range;
cmd->tile_placement.tile_kind = S_TileKind_Floor;
cmd->tile_placement.range.p0 = VEC2I32(100, 100);
cmd->tile_placement.range.p1 = VEC2I32(200, 200);
} break;
}
}
@ -571,7 +649,7 @@ void V_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Compute movement & look
if (!frame->edit_mode)
if (!frame->is_editing)
{
Vec2 move = Zi;
{
@ -590,53 +668,77 @@ void V_TickForever(WaveLaneCtx *lane)
frame->look = look;
}
/* Push control cmd */
{
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Control);
cmd->target = V.player_key;
cmd->move = frame->move;
cmd->look = frame->look;
}
//////////////////////////////
//- Submit sim commands
LockTicketMutex(&S.input_back_tm);
{
S_InputState *v2s = &S.input_states[S.input_back_idx];
/* Submit control cmd */
for (S_CmdNode *src = frame->first_sim_cmd_node; src; src = src->next)
{
S_Cmd *cmd = 0;
{
S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode);
SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node);
++v2s->cmds_count;
cmd = &cmd_node->cmd;
}
cmd->kind = S_CmdKind_Control;
cmd->target = V.player_key;
cmd->move = frame->move;
cmd->look = frame->look;
}
/* Submit spawn cmds */
if (spawn_ents.count > 0)
{
S_Cmd *cmd = 0;
{
S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode);
SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node);
++v2s->cmds_count;
cmd = &cmd_node->cmd;
}
cmd->kind = S_CmdKind_Spawn;
S_EntList *dst = &cmd->ents;
for (S_EntListNode *src_n = spawn_ents.first; src_n; src_n = src_n->next)
{
S_EntListNode *dst_n = PushStruct(v2s->arena, S_EntListNode);
{
SllQueuePush(dst->first, dst->last, dst_n);
++dst->count;
}
dst_n->ent = src_n->ent;
}
S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode);
cmd_node->cmd = src->cmd;
SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node);
++v2s->cmds_count;
}
}
UnlockTicketMutex(&S.input_back_tm);
// LockTicketMutex(&S.input_back_tm);
// {
// S_InputState *v2s = &S.input_states[S.input_back_idx];
// /* Submit control cmd */
// {
// S_Cmd *cmd = 0;
// {
// S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode);
// SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node);
// ++v2s->cmds_count;
// cmd = &cmd_node->cmd;
// }
// cmd->kind = S_CmdKind_Control;
// cmd->target = V.player_key;
// cmd->move = frame->move;
// cmd->look = frame->look;
// }
// /* Submit tile cmds */
// /* Submit spawn cmds */
// if (spawn_ents.count > 0)
// {
// S_Cmd *cmd = 0;
// {
// S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode);
// SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node);
// ++v2s->cmds_count;
// cmd = &cmd_node->cmd;
// }
// cmd->kind = S_CmdKind_Spawn;
// S_EntList *dst = &cmd->ents;
// for (S_EntListNode *src_n = spawn_ents.first; src_n; src_n = src_n->next)
// {
// S_EntListNode *dst_n = PushStruct(v2s->arena, S_EntListNode);
// {
// SllQueuePush(dst->first, dst->last, dst_n);
// ++dst->count;
// }
// dst_n->ent = src_n->ent;
// }
// }
// }
// UnlockTicketMutex(&S.input_back_tm);
//////////////////////////////
//- Render
@ -709,19 +811,24 @@ void V_TickForever(WaveLaneCtx *lane)
params.target_size = frame->draw_dims;
params.target_ro = draw_target_ro;
params.target_rw = draw_target_rw;
params.shape_verts = dverts_ro;
params.target_cursor_pos = frame->draw_cursor;
params.background_color_a = LinearFromSrgb(VEC4(0.30, 0.30, 0.30, 1));
params.background_color_b = LinearFromSrgb(VEC4(0.15, 0.15, 0.15, 1));
params.x_axis_color = LinearFromSrgb(VEC4(0.75, 0, 0, 1));
params.y_axis_color = LinearFromSrgb(VEC4(0, 0.75, 0, 1));
params.bounds_color = LinearFromSrgb(VEC4(0.75, 0.75, 0, 1));
params.world_size = world_size;
params.world_to_draw_xf = frame->world_to_draw_xf;
params.draw_to_world_xf = frame->draw_to_world_xf;
params.target_cursor_pos = frame->draw_cursor;
params.camera_pos = frame->camera_pos;
params.camera_zoom = frame->camera_zoom;
params.world_size = world_size;
params.tiles = gpu_tiles_ref;
params.shape_verts = dverts_ro;
params.background_color_a = LinearFromSrgb(VEC4(0.30, 0.30, 0.30, 1));
params.background_color_b = LinearFromSrgb(VEC4(0.15, 0.15, 0.15, 1));
params.grid_color = LinearFromSrgb(VEC4(0, 0, 0, 1));
params.x_axis_color = LinearFromSrgb(VEC4(0.75, 0, 0, 1));
params.y_axis_color = LinearFromSrgb(VEC4(0, 0.75, 0, 1));
params.bounds_color = LinearFromSrgb(VEC4(0.75, 0.75, 0, 1));
}
G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(&params));
G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, V_DParams);

View File

@ -7,7 +7,7 @@
X(toggle_command_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \
X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \
X(toggle_edit_mode, Toggle Edit Mode, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \
X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \
X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \
X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \
X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \
@ -76,6 +76,11 @@ Global Readonly V_CmdDesc V_cmd_descs[V_CmdKind_Count] = {
////////////////////////////////////////////////////////////
//~ Context types
Enum(V_EditMode)
{
V_EditMode_Tile,
};
Struct(V_Frame)
{
Arena *arena;
@ -99,12 +104,15 @@ Struct(V_Frame)
Vec2I32 draw_dims;
/* Modes */
b32 edit_mode;
b32 is_editing;
b32 ui_debug;
b32 show_command_palette;
b32 show_console;
/* Edit camera */
/* Editor state */
V_EditMode edit_mode;
/* Editor */
b32 is_panning;
Vec2 edit_camera_pos;
f32 edit_camera_zoom;
@ -133,6 +141,11 @@ Struct(V_Frame)
/* Control */
Vec2 move;
Vec2 look;
/* Sim cmds */
u64 sim_cmds_count;
S_CmdNode *first_sim_cmd_node;
S_CmdNode *last_sim_cmd_node;
};
Struct(V_Ctx)
@ -157,6 +170,12 @@ extern V_Ctx V;
void V_Bootstrap(void);
void V_Shutdown(void);
////////////////////////////////////////////////////////////
//~ Helpers
V_Frame *V_CurrentFrame(void);
S_Cmd *V_PushSimCmd(S_CmdKind kind);
////////////////////////////////////////////////////////////
//~ Vis tick

View File

@ -9,21 +9,24 @@ Struct(V_DParams)
G_Texture2DRef target_ro;
G_RWTexture2DRef target_rw;
Xform world_to_draw_xf;
Xform draw_to_world_xf;
Vec2 target_cursor_pos;
Vec2 camera_pos;
f32 camera_zoom;
f32 world_size;
G_Texture2DRef tiles;
G_StructuredBufferRef quads;
G_StructuredBufferRef shape_verts;
Vec2 target_cursor_pos;
Vec4 background_color_a;
Vec4 background_color_b;
Vec4 grid_color;
Vec4 x_axis_color;
Vec4 y_axis_color;
Vec4 bounds_color;
f32 world_size;
Xform world_to_draw_xf;
Xform draw_to_world_xf;
};
////////////////////////////////////////////////////////////

View File

@ -5,75 +5,109 @@ ComputeShader2D(V_BackdropCS, 8, 8)
{
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
Vec2U32 target_pos = SV_DispatchThreadID;
Vec2I32 target_size = params.target_size;
if (target_pos.x < target_size.x && target_pos.y < target_size.y)
{
Vec4 result = 0;
Vec4 result = Vec4(0.025, 0.025, 0.025, 1);
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(target_pos, 1));
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
/* Checkered square color */
f32 half_thickness = 1;
f32 half_bounds_size = params.world_size * 0.5;
Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1));
Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1));
b32 is_in_bounds = target_pos.x > (bounds_screen_p0.x - half_thickness) &&
target_pos.y > (bounds_screen_p0.y - half_thickness) &&
target_pos.x < (bounds_screen_p1.x + half_thickness) &&
target_pos.y < (bounds_screen_p1.y + half_thickness);
if (is_in_bounds)
{
i32 color_idx = 0;
Vec4 colors[2] = {
params.background_color_a,
params.background_color_b
};
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(target_pos, 1));
Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(2, 2));
if (world_pos_modded.x < 1)
/* Grid checker */
{
color_idx = !color_idx;
}
if (world_pos_modded.y < 1)
{
color_idx = !color_idx;
}
if (world_pos.x < 0)
{
color_idx = !color_idx;
}
if (world_pos.y < 0)
{
color_idx = !color_idx;
}
result = colors[color_idx];
}
{
f32 half_thickness = 1;
f32 half_bounds_size = params.world_size * 0.5;
Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1));
Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1));
if (target_pos.x > (bounds_screen_p0.x - half_thickness) && target_pos.y > (bounds_screen_p0.y - half_thickness) &&
target_pos.x < (bounds_screen_p1.x + half_thickness) && target_pos.y < (bounds_screen_p1.y + half_thickness))
{
/* Axis color */
i32 color_idx = 0;
Vec4 colors[2] = {
params.background_color_a,
params.background_color_b
};
Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(1.0, 1.0));
if (world_pos_modded.x < 0.5)
{
f32 half_thickness = 1;
Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1));
f32 x_dist = abs(target_pos.x - zero_screen.x);
f32 y_dist = abs(target_pos.y - zero_screen.y);
if (y_dist <= half_thickness)
{
result = params.x_axis_color;
}
else if (x_dist <= half_thickness)
{
result = params.y_axis_color;
}
color_idx = !color_idx;
}
/* World bounds color */
if (world_pos_modded.y < 0.5)
{
f32 bounds_dist = 100000;
bounds_dist = min(bounds_dist, abs(target_pos.x - bounds_screen_p0.x));
bounds_dist = min(bounds_dist, abs(target_pos.x - bounds_screen_p1.x));
bounds_dist = min(bounds_dist, abs(target_pos.y - bounds_screen_p0.y));
bounds_dist = min(bounds_dist, abs(target_pos.y - bounds_screen_p1.y));
if (bounds_dist <= half_thickness)
color_idx = !color_idx;
}
if (world_pos.x < 0)
{
color_idx = !color_idx;
}
if (world_pos.y < 0)
{
color_idx = !color_idx;
}
result = colors[color_idx];
}
/* Grid outline */
{
Vec2 grid_screen_p0 = mul(params.world_to_draw_xf, Vec3(floor(world_pos), 1));
Vec2 grid_screen_p1 = mul(params.world_to_draw_xf, Vec3(ceil(world_pos), 1));
f32 grid_dist = 100000;
grid_dist = min(grid_dist, abs(target_pos.x - grid_screen_p0.x));
grid_dist = min(grid_dist, abs(target_pos.x - grid_screen_p1.x));
grid_dist = min(grid_dist, abs(target_pos.y - grid_screen_p0.y));
grid_dist = min(grid_dist, abs(target_pos.y - grid_screen_p1.y));
if (grid_dist <= half_thickness)
{
result = params.grid_color;
}
}
/* Tile */
{
S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0));
switch (tile)
{
default: break;
case S_TileKind_Floor:
{
result = params.bounds_color;
}
result = Color_Blue;
} break;
case S_TileKind_Wall:
{
result = Color_Red;
} break;
}
}
/* Axis */
{
f32 half_thickness = 1;
Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1));
f32 x_dist = abs(target_pos.x - zero_screen.x);
f32 y_dist = abs(target_pos.y - zero_screen.y);
if (y_dist <= half_thickness)
{
result = params.x_axis_color;
}
else if (x_dist <= half_thickness)
{
result = params.y_axis_color;
}
}
/* World bounds */
{
f32 bounds_dist = 100000;
bounds_dist = min(bounds_dist, abs(target_pos.x - bounds_screen_p0.x));
bounds_dist = min(bounds_dist, abs(target_pos.x - bounds_screen_p1.x));
bounds_dist = min(bounds_dist, abs(target_pos.y - bounds_screen_p0.y));
bounds_dist = min(bounds_dist, abs(target_pos.y - bounds_screen_p1.y));
if (bounds_dist <= half_thickness)
{
result = params.bounds_color;
}
}
}