particle falloff testing
This commit is contained in:
parent
87a624eaeb
commit
869b415ebb
@ -58,7 +58,7 @@ void G_BootstrapCommon(void)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Helpers
|
||||
//~ Utils
|
||||
|
||||
//- Arena
|
||||
|
||||
@ -71,17 +71,12 @@ G_ArenaHandle G_PermArena(void)
|
||||
return G_tl.gpu_perm;
|
||||
}
|
||||
|
||||
//- Cpu -> Gpu upload
|
||||
//- Push resource from cpu
|
||||
|
||||
G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc)
|
||||
G_ResourceHandle G_PushBufferFromCpuCopy_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc)
|
||||
{
|
||||
G_ResourceHandle buffer = G_PushResource(gpu_arena, cl, (G_ResourceDesc) { .kind = G_ResourceKind_Buffer, .buffer = desc });
|
||||
G_CopyCpuToBuffer(cl, buffer, 0, src.text, RNGU64(0, src.len));
|
||||
G_MemorySync(
|
||||
cl, buffer,
|
||||
G_Stage_Copy, G_Access_CopyWrite,
|
||||
G_Stage_All, G_Access_All
|
||||
);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
@ -23,17 +23,17 @@ extern ThreadLocal G_ThreadLocalCtx G_tl;
|
||||
void G_BootstrapCommon(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Helpers
|
||||
//~ Utils
|
||||
|
||||
//- Arena
|
||||
|
||||
G_ArenaHandle G_PermArena(void);
|
||||
|
||||
//- Cpu -> Gpu upload
|
||||
//- Push resource from cpu
|
||||
|
||||
G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc);
|
||||
#define G_PushBufferFromString(_arena, _cl, _src, ...) \
|
||||
G_PushBufferFromString_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ })
|
||||
G_ResourceHandle G_PushBufferFromCpuCopy_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc);
|
||||
#define G_PushBufferFromCpuCopy(_arena, _cl, _src, ...) \
|
||||
G_PushBufferFromCpuCopy_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ })
|
||||
|
||||
//- Viewport / scissor
|
||||
|
||||
|
||||
@ -212,15 +212,15 @@ Enum(G_Stage)
|
||||
G_Stage_Indirect = (1 << 8),
|
||||
|
||||
// Aggregate stages
|
||||
G_Stage_AllDraw = G_Stage_IndexAssembly |
|
||||
G_Stage_VertexShading |
|
||||
G_Stage_PixelShading |
|
||||
G_Stage_DepthStencil |
|
||||
G_Stage_RenderTarget,
|
||||
G_Stage_Drawing = G_Stage_IndexAssembly |
|
||||
G_Stage_VertexShading |
|
||||
G_Stage_PixelShading |
|
||||
G_Stage_DepthStencil |
|
||||
G_Stage_RenderTarget,
|
||||
|
||||
G_Stage_AllShading = G_Stage_ComputeShading |
|
||||
G_Stage_VertexShading |
|
||||
G_Stage_PixelShading,
|
||||
G_Stage_Shading = G_Stage_ComputeShading |
|
||||
G_Stage_VertexShading |
|
||||
G_Stage_PixelShading,
|
||||
|
||||
G_Stage_All = 0xFFFFFFFF
|
||||
};
|
||||
@ -409,8 +409,9 @@ Enum(G_ResourceFlag)
|
||||
G_ResourceFlag_AllowShaderReadWrite = (1 << 0),
|
||||
G_ResourceFlag_AllowRenderTarget = (1 << 1),
|
||||
G_ResourceFlag_AllowDepthStencil = (1 << 2),
|
||||
G_ResourceFlag_HostMemory = (1 << 3), // Resource will be mapped into the cpu's address space
|
||||
G_ResourceFlag_Uncached = (1 << 4), // Cpu writes will be combined & reads will be uncached
|
||||
G_ResourceFlag_ZeroMemory = (1 << 3),
|
||||
G_ResourceFlag_HostMemory = (1 << 4), // Resource will be mapped into the cpu's address space
|
||||
G_ResourceFlag_Uncached = (1 << 5), // Cpu writes will be combined & reads will be uncached
|
||||
};
|
||||
|
||||
Struct(G_BufferDesc)
|
||||
|
||||
@ -898,6 +898,8 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
|
||||
//////////////////////////////
|
||||
//- Initialize heap info
|
||||
|
||||
b32 can_reuse = 0;
|
||||
|
||||
D3D12_HEAP_FLAGS heap_flags = 0;
|
||||
D3D12_HEAP_PROPERTIES heap_props = Zi;
|
||||
b32 should_map = 0;
|
||||
@ -913,7 +915,15 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
|
||||
heap_kind = G_D12_ResourceHeapKind_CpuWriteCombined;
|
||||
}
|
||||
}
|
||||
heap_flags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
|
||||
if (flags & G_ResourceFlag_ZeroMemory)
|
||||
{
|
||||
can_reuse = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
can_reuse = 1;
|
||||
heap_flags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
|
||||
}
|
||||
// Heap props
|
||||
if (heap_kind == G_D12_ResourceHeapKind_Cpu)
|
||||
{
|
||||
@ -986,7 +996,6 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
|
||||
|
||||
// Pop reset resource
|
||||
resource = gpu_arena->reset_resources.first;
|
||||
b32 is_reusing = 0;
|
||||
if (resource)
|
||||
{
|
||||
DllQueueRemove(gpu_arena->reset_resources.first, gpu_arena->reset_resources.last, resource);
|
||||
@ -1004,9 +1013,9 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Less stringent reset constraints. We could even create textures as placed resources and reset their underlying heaps.
|
||||
is_reusing = MatchStruct(&compare_d3d_desc, &d3d_desc);
|
||||
if (!is_reusing)
|
||||
// TODO: Less stringent reuse constraints. We could even create textures as placed resources and reset their underlying heaps.
|
||||
can_reuse = can_reuse && MatchStruct(&compare_d3d_desc, &d3d_desc);
|
||||
if (!can_reuse)
|
||||
{
|
||||
// Push releasable to command list
|
||||
{
|
||||
@ -1035,10 +1044,11 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
|
||||
}
|
||||
else
|
||||
{
|
||||
can_reuse = 0;
|
||||
resource = PushStruct(gpu_arena->arena, G_D12_Resource);
|
||||
}
|
||||
|
||||
if (!is_reusing)
|
||||
if (!can_reuse)
|
||||
{
|
||||
resource->d3d_desc = d3d_desc;
|
||||
}
|
||||
@ -1126,11 +1136,19 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Transition layout if reusing
|
||||
//- Barrier if reusing
|
||||
|
||||
if (is_reusing)
|
||||
// TODO: These barriers are too cautious; it's rare that an arena would ever be reset mid-command list.
|
||||
if (can_reuse)
|
||||
{
|
||||
G_DumbMemoryLayoutSync(cl_handle, G_D12_MakeHandle(G_ResourceHandle, resource), desc.texture.initial_layout);
|
||||
if (is_buffer)
|
||||
{
|
||||
G_DumbMemorySync(cl_handle, G_D12_MakeHandle(G_ResourceHandle, resource));
|
||||
}
|
||||
else if (is_texture)
|
||||
{
|
||||
G_DumbMemoryLayoutSync(cl_handle, G_D12_MakeHandle(G_ResourceHandle, resource), desc.texture.initial_layout);
|
||||
}
|
||||
}
|
||||
|
||||
return G_D12_MakeHandle(G_ResourceHandle, resource);
|
||||
@ -2717,7 +2735,7 @@ G_QueueCompletions G_CompletionValuesFromQueues(G_QueueMask queue_mask)
|
||||
{
|
||||
if (queue_mask & (1 << queue_kind))
|
||||
{
|
||||
completions.v[queue_kind] = G_CompletionTargetFromQueue(queue_kind);
|
||||
completions.v[queue_kind] = G_CompletionValueFromQueue(queue_kind);
|
||||
}
|
||||
}
|
||||
return completions;
|
||||
@ -3279,7 +3297,7 @@ void G_D12_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame
|
||||
G_D12_Releasable *release = async->pending_releases.first;
|
||||
if (release)
|
||||
{
|
||||
G_QueueCompletions completions = G_CompletionTargetsFromQueues(G_QueueMask_All);
|
||||
G_QueueCompletions completions = G_CompletionValuesFromQueues(G_QueueMask_All);
|
||||
while (release)
|
||||
{
|
||||
G_D12_Releasable *next = release->next;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
S_Ctx S = Zi;
|
||||
ThreadLocal S_ThreadLocalCtx S_tl = Zi;
|
||||
|
||||
Readonly S_Ent S_NilEnt = {
|
||||
.last_xf = CompXformIdentity,
|
||||
@ -86,10 +87,9 @@ String S_NameFromTileKind(S_TileKind kind)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Delta helpers
|
||||
|
||||
Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta)
|
||||
void S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta)
|
||||
{
|
||||
// FIXME: Bounds check tile deltas
|
||||
Rng2I32 dirty_tile_rect = Zi;
|
||||
if (0)
|
||||
{
|
||||
}
|
||||
@ -142,7 +142,6 @@ Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta)
|
||||
world->tiles[tile_idx] = src_tile;
|
||||
}
|
||||
}
|
||||
dirty_tile_rect = range;
|
||||
}
|
||||
//- Tile range
|
||||
else if (delta->kind == S_DeltaKind_Tile)
|
||||
@ -158,10 +157,7 @@ Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta)
|
||||
world->tiles[tile_idx] = (u8)tile;
|
||||
}
|
||||
}
|
||||
dirty_tile_rect = range;
|
||||
}
|
||||
|
||||
return dirty_tile_rect;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -314,9 +310,9 @@ Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal)
|
||||
return result;
|
||||
}
|
||||
|
||||
S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep)
|
||||
S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep)
|
||||
{
|
||||
S_CollisionData result = Zi;
|
||||
S_CollisionResult result = Zi;
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
f32 tolerance = 0.00005f; // How close can non-overlapping shapes be before collision is considered
|
||||
@ -926,16 +922,16 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1, Vec2 s
|
||||
return result;
|
||||
}
|
||||
|
||||
S_RaycastData S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir)
|
||||
S_RaycastResult S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir)
|
||||
{
|
||||
S_RaycastData result = Zi;
|
||||
S_RaycastResult result = Zi;
|
||||
|
||||
// HACK: Create line shape as large as the world and perform a collision test
|
||||
Vec2 ray_shape_p0 = ray_start;
|
||||
Vec2 ray_shape_p1 = AddVec2(ray_start, MulVec2(NormVec2(ray_dir), S_WorldPitch * 1.414213562));
|
||||
S_Shape ray_shape = S_ShapeFromDesc(.count = 2, .points = { ray_shape_p0, ray_shape_p1 });
|
||||
|
||||
S_CollisionData cls = S_CollisionDataFromShapes(ray_shape, shape, ray_dir);
|
||||
S_CollisionResult cls = S_CollisionResultFromShapes(ray_shape, shape, ray_dir);
|
||||
result.is_intersecting = cls.collision_points_count > 0;
|
||||
result.normal = NegVec2(cls.collision_normal);
|
||||
result.p = cls.closest_p1;
|
||||
@ -992,7 +988,7 @@ S_Ent *S_NextEnt(S_Ent *e)
|
||||
|
||||
void S_DebugDrawPoint(Vec2 p, Vec4 srgb)
|
||||
{
|
||||
if (S.debug_draw_enabled)
|
||||
if (S_tl.is_sim_tick_thread && S.debug_draw_enabled)
|
||||
{
|
||||
S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc);
|
||||
desc->kind = S_DebugDrawKind_Point;
|
||||
@ -1003,7 +999,7 @@ void S_DebugDrawPoint(Vec2 p, Vec4 srgb)
|
||||
|
||||
void S_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb)
|
||||
{
|
||||
if (S.debug_draw_enabled)
|
||||
if (S_tl.is_sim_tick_thread && S.debug_draw_enabled)
|
||||
{
|
||||
S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc);
|
||||
desc->kind = S_DebugDrawKind_Line;
|
||||
@ -1015,7 +1011,7 @@ void S_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb)
|
||||
|
||||
void S_DebugDrawRect(Rng2 rect, Vec4 srgb)
|
||||
{
|
||||
if (S.debug_draw_enabled)
|
||||
if (S_tl.is_sim_tick_thread && S.debug_draw_enabled)
|
||||
{
|
||||
S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc);
|
||||
desc->kind = S_DebugDrawKind_Rect;
|
||||
@ -1026,7 +1022,7 @@ void S_DebugDrawRect(Rng2 rect, Vec4 srgb)
|
||||
|
||||
void S_DebugDrawShape(S_Shape shape, Vec4 srgb)
|
||||
{
|
||||
if (S.debug_draw_enabled)
|
||||
if (S_tl.is_sim_tick_thread && S.debug_draw_enabled)
|
||||
{
|
||||
S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc);
|
||||
desc->kind = S_DebugDrawKind_Shape;
|
||||
@ -1040,6 +1036,7 @@ void S_DebugDrawShape(S_Shape shape, Vec4 srgb)
|
||||
|
||||
void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
S_tl.is_sim_tick_thread = 1;
|
||||
Arena *perm = PermArena();
|
||||
Arena *frame_arena = AcquireArena(Gibi(64));
|
||||
|
||||
@ -1348,7 +1345,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
// Vec2 shape0_pt = S_SupportPointFromShape(shape0, shape_dir);
|
||||
// Vec2 shape1_pt = S_SupportPointFromShape(shape1, neg_shape_dir);
|
||||
|
||||
S_CollisionData collision_data = S_CollisionDataFromShapes(shape0, shape1, VEC2(0, 0));
|
||||
S_CollisionResult collision_data = S_CollisionResultFromShapes(shape0, shape1, VEC2(0, 0));
|
||||
Vec2 shape0_pt = collision_data.closest_p0;
|
||||
Vec2 shape1_pt = collision_data.closest_p1;
|
||||
|
||||
@ -1410,61 +1407,120 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
// TODO: Not like this
|
||||
|
||||
|
||||
{
|
||||
Struct(S_Bullet)
|
||||
{
|
||||
Vec2 start;
|
||||
Vec2 dir;
|
||||
// {
|
||||
// Struct(S_Bullet)
|
||||
// {
|
||||
// Vec2 start;
|
||||
// Vec2 dir;
|
||||
|
||||
f32 speed;
|
||||
};
|
||||
// f32 speed;
|
||||
// };
|
||||
|
||||
PERSIST i64 bullets_count = 1;
|
||||
PERSIST S_Bullet *bullets = 0;
|
||||
if (!bullets)
|
||||
{
|
||||
bullets = PushStruct(PermArena(), S_Bullet);
|
||||
S_Bullet *bullet = &bullets[0];
|
||||
bullet->start = VEC2(1, 0);
|
||||
bullet->dir = NormVec2(VEC2(1, -1));
|
||||
bullet->speed = 1;
|
||||
}
|
||||
// PERSIST i64 bullets_count = 1;
|
||||
// PERSIST S_Bullet *bullets = 0;
|
||||
// if (!bullets)
|
||||
// {
|
||||
// bullets = PushStruct(PermArena(), S_Bullet);
|
||||
// S_Bullet *bullet = &bullets[0];
|
||||
// bullet->start = VEC2(1, 0);
|
||||
// bullet->dir = NormVec2(VEC2(1, -1));
|
||||
// bullet->speed = 1;
|
||||
// }
|
||||
|
||||
for (i64 bullet_idx = 0; bullet_idx < bullets_count; ++bullet_idx)
|
||||
{
|
||||
S_Bullet *bullet = &bullets[bullet_idx];
|
||||
// for (i64 bullet_idx = 0; bullet_idx < bullets_count; ++bullet_idx)
|
||||
// {
|
||||
// S_Bullet *bullet = &bullets[bullet_idx];
|
||||
|
||||
// Raycast
|
||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
{
|
||||
Xform xf = ent->xf;
|
||||
S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
||||
// // Raycast
|
||||
// for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
// {
|
||||
// Xform xf = ent->xf;
|
||||
// S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
||||
|
||||
if (ent == S_FirstEnt(world))
|
||||
{
|
||||
bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius));
|
||||
bullet->dir = NormVec2(ent->look);
|
||||
}
|
||||
else
|
||||
{
|
||||
S_RaycastData raycast = S_RaycastShape(world_shape, bullet->start, bullet->dir);
|
||||
Vec2 isect = raycast.p;
|
||||
// if (ent == S_FirstEnt(world))
|
||||
// {
|
||||
// bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius));
|
||||
// bullet->dir = NormVec2(ent->look);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// S_RaycastResult raycast = S_RaycastShape(world_shape, bullet->start, bullet->dir);
|
||||
// Vec2 isect = raycast.p;
|
||||
|
||||
if (raycast.is_intersecting)
|
||||
{
|
||||
S_DebugDrawPoint(isect, Color_Green);
|
||||
S_DebugDrawLine(isect, AddVec2(isect, MulVec2(raycast.normal, 0.5)), Color_White);
|
||||
}
|
||||
else
|
||||
{
|
||||
S_DebugDrawPoint(isect, Color_Purple);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (raycast.is_intersecting)
|
||||
// {
|
||||
// S_DebugDrawPoint(isect, Color_Green);
|
||||
// S_DebugDrawLine(isect, AddVec2(isect, MulVec2(raycast.normal, 0.5)), Color_White);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// S_DebugDrawPoint(isect, Color_Purple);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
S_DebugDrawLine(bullet->start, AddVec2(bullet->start, Vec2WithLen(bullet->dir, 0.5)), Color_Red);
|
||||
}
|
||||
}
|
||||
// S_DebugDrawLine(bullet->start, AddVec2(bullet->start, Vec2WithLen(bullet->dir, 0.5)), Color_Red);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// // Struct(S_Bullet)
|
||||
// // {
|
||||
// // Vec2 start;
|
||||
// // Vec2 dir;
|
||||
|
||||
// // f32 speed;
|
||||
// // };
|
||||
|
||||
// // PERSIST i64 bullets_count = 1;
|
||||
// // PERSIST S_Bullet *bullets = 0;
|
||||
// // if (!bullets)
|
||||
// // {
|
||||
// // bullets = PushStruct(PermArena(), S_Bullet);
|
||||
// // S_Bullet *bullet = &bullets[0];
|
||||
// // bullet->start = VEC2(1, 0);
|
||||
// // bullet->dir = NormVec2(VEC2(1, -1));
|
||||
// // bullet->speed = 1;
|
||||
// // }
|
||||
|
||||
// // for (i64 bullet_idx = 0; bullet_idx < bullets_count; ++bullet_idx)
|
||||
// // {
|
||||
// // S_Bullet *bullet = &bullets[bullet_idx];
|
||||
|
||||
// // // Raycast
|
||||
// // for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
// // {
|
||||
// // Xform xf = ent->xf;
|
||||
// // S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
||||
|
||||
// // if (ent == S_FirstEnt(world))
|
||||
// // {
|
||||
// // bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius));
|
||||
// // bullet->dir = NormVec2(ent->look);
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // S_RaycastResult raycast = S_RaycastShape(world_shape, bullet->start, bullet->dir);
|
||||
// // Vec2 isect = raycast.p;
|
||||
|
||||
// // if (raycast.is_intersecting)
|
||||
// // {
|
||||
// // S_DebugDrawPoint(isect, Color_Green);
|
||||
// // S_DebugDrawLine(isect, AddVec2(isect, MulVec2(raycast.normal, 0.5)), Color_White);
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // S_DebugDrawPoint(isect, Color_Purple);
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// // S_DebugDrawLine(bullet->start, AddVec2(bullet->start, Vec2WithLen(bullet->dir, 0.5)), Color_Red);
|
||||
// // }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ Struct(S_ClippedLine)
|
||||
Vec2 a1_clipped, b1_clipped;
|
||||
};
|
||||
|
||||
Struct(S_CollisionData)
|
||||
Struct(S_CollisionResult)
|
||||
{
|
||||
// Contact manifold
|
||||
i32 collision_points_count;
|
||||
@ -132,7 +132,7 @@ Struct(S_CollisionData)
|
||||
Vec2 closest_p1;
|
||||
};
|
||||
|
||||
Struct(S_RaycastData)
|
||||
Struct(S_RaycastResult)
|
||||
{
|
||||
Vec2 p;
|
||||
Vec2 normal;
|
||||
@ -315,7 +315,13 @@ Struct(S_Ctx)
|
||||
S_OutputState output_states[2];
|
||||
};
|
||||
|
||||
Struct(S_ThreadLocalCtx)
|
||||
{
|
||||
b32 is_sim_tick_thread;
|
||||
};
|
||||
|
||||
extern S_Ctx S;
|
||||
extern ThreadLocal S_ThreadLocalCtx S_tl;
|
||||
extern Readonly S_Ent S_NilEnt;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -346,7 +352,7 @@ String S_NameFromTileKind(S_TileKind kind);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Delta helpers
|
||||
|
||||
Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta);
|
||||
void S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shape helpers
|
||||
@ -366,8 +372,8 @@ S_MenkowskiPoint S_MenkowskiPointFromShapes(S_Shape shape0, S_Shape shape1, Vec2
|
||||
S_ClippedLine S_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 normal);
|
||||
Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal);
|
||||
|
||||
S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep);
|
||||
S_RaycastData S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir);
|
||||
S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep);
|
||||
S_RaycastResult S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Lookup helpers
|
||||
|
||||
@ -313,6 +313,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
// u32 max_particles = Kibi(128);
|
||||
u32 max_particles = Mebi(1);
|
||||
// u32 max_particles = Mebi(2);
|
||||
// u32 max_particles = Mebi(16);
|
||||
|
||||
// Init gpu state
|
||||
G_ResourceHandle gpu_state = Zi;
|
||||
@ -324,7 +326,6 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
G_RWStructuredBufferRef gpu_particles_ref = Zi;
|
||||
G_RWTexture2DRef gpu_decals_ref = Zi;
|
||||
{
|
||||
// FIXME: Clear initial resource memory
|
||||
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
|
||||
{
|
||||
// Init state buffer
|
||||
@ -333,7 +334,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
gpu_perm, cl,
|
||||
V_GpuState,
|
||||
1,
|
||||
.flags = G_ResourceFlag_AllowShaderReadWrite
|
||||
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite
|
||||
);
|
||||
gpu_state_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_state, V_GpuState);
|
||||
}
|
||||
@ -344,7 +345,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
gpu_perm, cl,
|
||||
G_Format_R8_Uint,
|
||||
tiles_dims,
|
||||
G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite
|
||||
G_Layout_DirectQueue_ShaderRead,
|
||||
.flags = G_ResourceFlag_ZeroMemory
|
||||
);
|
||||
gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles);
|
||||
}
|
||||
@ -354,7 +356,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
gpu_perm, cl,
|
||||
V_Particle,
|
||||
max_particles,
|
||||
.flags = G_ResourceFlag_AllowShaderReadWrite
|
||||
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite
|
||||
);
|
||||
gpu_particles_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles, V_Particle);
|
||||
}
|
||||
@ -362,10 +364,12 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
gpu_decals = G_PushTexture2D(
|
||||
gpu_perm, cl,
|
||||
G_Format_R8_Uint,
|
||||
// G_Format_R8_Uint,
|
||||
// G_Format_R11G11B10_Float,
|
||||
G_Format_R10G10B10A2_Unorm,
|
||||
decals_dims,
|
||||
G_Layout_DirectQueue_ShaderReadWrite,
|
||||
.flags = G_ResourceFlag_AllowShaderReadWrite
|
||||
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite
|
||||
);
|
||||
gpu_decals_ref = G_PushRWTexture2DRef(gpu_perm, gpu_decals);
|
||||
}
|
||||
@ -582,6 +586,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
// FIXME: Only apply latest snapshot
|
||||
|
||||
b32 received_unseen_tick = 0;
|
||||
b32 tiles_dirty = 0;
|
||||
for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||
{
|
||||
S_Snapshot *snapshot = &n->snapshot;
|
||||
@ -592,17 +597,11 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
for (S_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||
{
|
||||
S_Delta *delta = &dn->delta;
|
||||
Rng2I32 dirty_tile_rect = S_UpdateWorldFromDelta(world_arena, world, delta);
|
||||
Vec2I32 dirty_tile_dims = DimsFromRng2I32(dirty_tile_rect);
|
||||
if (dirty_tile_dims.x != 0 || dirty_tile_dims.y != 0)
|
||||
if (delta->kind == S_DeltaKind_RawTiles || delta->kind == S_DeltaKind_Tile)
|
||||
{
|
||||
G_CopyCpuToTexture(
|
||||
frame->cl,
|
||||
gpu_tiles, VEC3I32(dirty_tile_rect.p0.x, dirty_tile_rect.p0.y, 0),
|
||||
world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1),
|
||||
RNG3I32(VEC3I32(dirty_tile_rect.p0.x, dirty_tile_rect.p0.y, 0), VEC3I32(dirty_tile_rect.p1.x, dirty_tile_rect.p1.y, 1))
|
||||
);
|
||||
tiles_dirty = 1;
|
||||
}
|
||||
S_UpdateWorldFromDelta(world_arena, world, delta);
|
||||
}
|
||||
received_unseen_tick = 1;
|
||||
}
|
||||
@ -961,11 +960,12 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
S_Ent *player = S_EntFromKey(world, V.player_key);
|
||||
S_Ent *hovered_ent = &S_NilEnt;
|
||||
{
|
||||
// TODO: Real world query
|
||||
S_Shape cursor_shape = S_ShapeFromDesc(.count = 1, .points = { frame->world_cursor });
|
||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
{
|
||||
S_Shape ent_shape = S_MulXformShape(ent->xf, ent->local_shape);
|
||||
b32 is_hovered = S_CollisionDataFromShapes(ent_shape, cursor_shape, VEC2(0, 0)).collision_points_count > 0;
|
||||
b32 is_hovered = S_CollisionResultFromShapes(ent_shape, cursor_shape, VEC2(0, 0)).collision_points_count > 0;
|
||||
if (is_hovered)
|
||||
{
|
||||
hovered_ent = ent;
|
||||
@ -2518,6 +2518,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
if (frame->held_buttons[Button_W]) move.y -= 1;
|
||||
if (frame->held_buttons[Button_S]) move.y += 1;
|
||||
}
|
||||
f32 fire_held = frame->held_buttons[Button_M1];
|
||||
Vec2 look = Zi;
|
||||
{
|
||||
Vec2 center = MulXformV2(player->xf, player->local_shape.centroid);
|
||||
@ -2535,6 +2536,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
frame->move = move;
|
||||
frame->look = look;
|
||||
frame->fire_held = fire_held;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2544,6 +2546,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
cmd->target = V.player_key;
|
||||
cmd->move = frame->move;
|
||||
cmd->look = frame->look;
|
||||
cmd->fire_held = frame->fire_held;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
@ -2562,6 +2565,108 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
UnlockTicketMutex(&S.input_back_tm);
|
||||
|
||||
//////////////////////////////
|
||||
//- Process bullets
|
||||
|
||||
// TODO: Not like this
|
||||
|
||||
|
||||
{
|
||||
for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer))
|
||||
{
|
||||
if (firer->fire_held)
|
||||
{
|
||||
Xform firer_xf = firer->xf;
|
||||
S_Shape firer_world_shape = S_MulXformShape(firer_xf, firer->local_shape);
|
||||
|
||||
Vec2 ray_start = firer_world_shape.centroid;
|
||||
Vec2 ray_dir = firer->look;
|
||||
|
||||
// TODO: Real raycast query
|
||||
S_Ent *closest_victim = &S_NilEnt;
|
||||
S_RaycastResult victim_raycast = Zi;
|
||||
{
|
||||
f32 closest_len_sq = Inf;
|
||||
for (S_Ent *victim = S_FirstEnt(world); victim->valid; victim = S_NextEnt(victim))
|
||||
{
|
||||
if (victim != firer)
|
||||
{
|
||||
Xform victim_xf = victim->xf;
|
||||
S_Shape victim_world_shape = S_MulXformShape(victim_xf, victim->local_shape);
|
||||
|
||||
S_RaycastResult raycast = S_RaycastShape(victim_world_shape, ray_start, ray_dir);
|
||||
if (raycast.is_intersecting)
|
||||
{
|
||||
f32 len_sq = Vec2LenSq(SubVec2(raycast.p, ray_start));
|
||||
if (len_sq < closest_len_sq)
|
||||
{
|
||||
closest_len_sq = len_sq;
|
||||
closest_victim = victim;
|
||||
victim_raycast = raycast;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closest_victim->valid)
|
||||
{
|
||||
V_Emitter *emitter = 0;
|
||||
{
|
||||
V_EmitterNode *en = PushStruct(frame->arena, V_EmitterNode);
|
||||
SllQueuePush(frame->first_emitter_node, frame->last_emitter_node, en);
|
||||
frame->emitters_count += 1;
|
||||
emitter = &en->emitter;
|
||||
}
|
||||
V_ParticleFlag flags = 0;
|
||||
emitter->flags = flags;
|
||||
|
||||
Vec2 dir = victim_raycast.normal;
|
||||
emitter->pos = victim_raycast.p;
|
||||
|
||||
emitter->count = 50;
|
||||
// emitter->count = 100;
|
||||
// emitter->count = 500;
|
||||
|
||||
emitter->speed = 20;
|
||||
emitter->speed_spread = 40;
|
||||
|
||||
emitter->velocity_falloff = 30;
|
||||
emitter->velocity_falloff_spread = 60;
|
||||
|
||||
emitter->angle = AngleFromVec2(dir);
|
||||
// emitter->angle_spread = Tau / 4;
|
||||
// emitter->angle_spread = Tau / 20;
|
||||
emitter->angle_spread = Tau / 32;
|
||||
|
||||
emitter->color_lin = LinearFromSrgb(VEC4(0.5, 0.1, 0.1, 1));
|
||||
emitter->color_spread = VEC3(0.1, 0, 0);
|
||||
|
||||
// emitter->color = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
|
||||
|
||||
emitter->seed = RandU64FromState(&frame->rand);
|
||||
// emitter->angle_spread = 1;
|
||||
// emitter->angle_spread = 0.5;
|
||||
// emitter->angle_spread = Tau;
|
||||
|
||||
// V_DrawPoint(victim_raycast.p, Color_Green);
|
||||
// V_DrawLine(victim_raycast.p, AddVec2(victim_raycast.p, MulVec2(victim_raycast.normal, 0.5)), Color_White);
|
||||
}
|
||||
|
||||
|
||||
// for (S_QueryResult query = S_FirstRaycast(wrold, ray_start, ray_dir); query.
|
||||
// S_RaycastWorldResult hits = S_RaycastWorld(world, ray_start, ray_dir)
|
||||
// {
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//- Render
|
||||
|
||||
@ -2664,11 +2769,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Build emitters
|
||||
|
||||
i64 emitters_count = 0;
|
||||
V_EmitterNode *first_emitter_node = 0;
|
||||
V_EmitterNode *last_emitter_node = 0;
|
||||
//- Spawn test emitter
|
||||
|
||||
// Spawn test emitter
|
||||
|
||||
@ -2677,39 +2778,31 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
V_Emitter *emitter = 0;
|
||||
{
|
||||
V_EmitterNode *en = PushStruct(frame->arena, V_EmitterNode);
|
||||
SllQueuePush(first_emitter_node, last_emitter_node, en);
|
||||
emitters_count += 1;
|
||||
SllQueuePush(frame->first_emitter_node, frame->last_emitter_node, en);
|
||||
frame->emitters_count += 1;
|
||||
emitter = &en->emitter;
|
||||
}
|
||||
emitter->particle_kind = V_ParticleKind_Test;
|
||||
|
||||
Vec2 dir = frame->look;
|
||||
emitter->pos = frame->world_cursor;
|
||||
emitter->angle = AngleFromVec2(dir);
|
||||
|
||||
emitter->count = 100;
|
||||
emitter->count = 25;
|
||||
// emitter->count = 100;
|
||||
emitter->speed = 10;
|
||||
|
||||
emitter->color_lin = LinearFromSrgb(Color_Yellow);
|
||||
|
||||
emitter->seed = RandU64FromState(&frame->rand);
|
||||
emitter->speed_spread = 1;
|
||||
// emitter->angle_spread = 1;
|
||||
// emitter->angle_spread = 0.5;
|
||||
emitter->angle_spread = Tau / 4;
|
||||
}
|
||||
|
||||
// Flatten emitters list
|
||||
V_Emitter *flattened_emitters = PushStructsNoZero(frame->arena, V_Emitter, emitters_count);
|
||||
{
|
||||
i64 emitter_idx = 0;
|
||||
for (V_EmitterNode *en = first_emitter_node; en; en = en->next)
|
||||
{
|
||||
flattened_emitters[emitter_idx] = en->emitter;
|
||||
++emitter_idx;
|
||||
}
|
||||
// emitter->angle_spread = Tau;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Push data to GPU
|
||||
//- Begin gpu frame
|
||||
|
||||
// Target
|
||||
G_ResourceHandle draw_target = G_PushTexture2D(
|
||||
@ -2725,13 +2818,26 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
Rng2 scissor = RNG2(VEC2(viewport.p0.x, viewport.p0.y), VEC2(viewport.p1.x, viewport.p1.y));
|
||||
|
||||
// Verts
|
||||
G_ResourceHandle dverts_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena));
|
||||
G_ResourceHandle dvert_idxs_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena));
|
||||
G_ResourceHandle dverts_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena));
|
||||
G_ResourceHandle dvert_idxs_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena));
|
||||
G_StructuredBufferRef dverts_ro = G_PushStructuredBufferRef(frame->gpu_arena, dverts_buff, V_DVert);
|
||||
G_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff);
|
||||
|
||||
// Emitters
|
||||
G_ResourceHandle gpu_emitters = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStructs(flattened_emitters, emitters_count));
|
||||
G_ResourceHandle gpu_emitters = Zi;
|
||||
{
|
||||
// Flatten emitters list
|
||||
V_Emitter *flattened_emitters = PushStructsNoZero(frame->arena, V_Emitter, frame->emitters_count);
|
||||
{
|
||||
i64 emitter_idx = 0;
|
||||
for (V_EmitterNode *en = frame->first_emitter_node; en; en = en->next)
|
||||
{
|
||||
flattened_emitters[emitter_idx] = en->emitter;
|
||||
++emitter_idx;
|
||||
}
|
||||
}
|
||||
gpu_emitters = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStructs(flattened_emitters, frame->emitters_count));
|
||||
}
|
||||
G_StructuredBufferRef gpu_emitters_ref = G_PushStructuredBufferRef(frame->gpu_arena, gpu_emitters, V_Emitter);
|
||||
|
||||
// Params
|
||||
@ -2762,7 +2868,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
params.tiles = gpu_tiles_ref;
|
||||
params.shape_verts = dverts_ro;
|
||||
|
||||
params.emitters_count = emitters_count;
|
||||
params.emitters_count = frame->emitters_count;
|
||||
params.emitters = gpu_emitters_ref;
|
||||
|
||||
params.max_particles = max_particles;
|
||||
@ -2770,9 +2876,23 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
params.decals = gpu_decals_ref;
|
||||
}
|
||||
G_ResourceHandle gpu_params = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(¶ms));
|
||||
G_ResourceHandle gpu_params = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStruct(¶ms));
|
||||
G_StructuredBufferRef gpu_params_ref = G_PushStructuredBufferRef(frame->gpu_arena, gpu_params, V_GpuParams);
|
||||
|
||||
// Upload tiles
|
||||
if (tiles_dirty)
|
||||
{
|
||||
LogDebugF("Uploading tiles to gpu");
|
||||
G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite);
|
||||
G_CopyCpuToTexture(
|
||||
frame->cl,
|
||||
gpu_tiles, VEC3I32(0, 0, 0),
|
||||
world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1),
|
||||
RNG3I32(VEC3I32(0, 0, 0), VEC3I32(tiles_dims.x, tiles_dims.y, 1))
|
||||
);
|
||||
G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_ShaderRead);
|
||||
}
|
||||
|
||||
// Constants
|
||||
G_SetConstant(frame->cl, V_ShaderConst_State, gpu_state_ref);
|
||||
G_SetConstant(frame->cl, V_ShaderConst_Params, gpu_params_ref);
|
||||
@ -2782,37 +2902,41 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
G_DumbGlobalMemorySync(frame->cl);
|
||||
|
||||
//////////////////////////////
|
||||
//- Utility pass
|
||||
//- Setup pass
|
||||
|
||||
// Clear decals
|
||||
if (should_clear_decals)
|
||||
{
|
||||
G_Compute(frame->cl, V_ClearDecalsCS, V_ThreadGroupSizeFromTexSize(decals_dims));
|
||||
}
|
||||
|
||||
// Clear particles
|
||||
if (should_clear_particles)
|
||||
{
|
||||
G_Compute(frame->cl, V_ClearParticlesCS, V_ThreadGroupSizeFromBufferSize(max_particles));
|
||||
}
|
||||
|
||||
G_DumbGlobalMemorySync(frame->cl);
|
||||
|
||||
//////////////////////////////
|
||||
//- Discard pass
|
||||
|
||||
// Discard render target
|
||||
G_DiscardRenderTarget(frame->cl, draw_target);
|
||||
|
||||
// Sync
|
||||
G_DumbGlobalMemorySync(frame->cl);
|
||||
|
||||
//////////////////////////////
|
||||
//- Particle simulation pass
|
||||
|
||||
{
|
||||
// Emit particles
|
||||
G_Compute(frame->cl, V_EmitParticlesCS, V_ThreadGroupSizeFromBufferSize(emitters_count));
|
||||
G_Compute(frame->cl, V_EmitParticlesCS, V_ThreadGroupSizeFromBufferSize(frame->emitters_count));
|
||||
|
||||
// Barrier particles buffer
|
||||
G_DumbMemorySync(frame->cl, gpu_particles);
|
||||
|
||||
// Simulate particles
|
||||
G_Compute(frame->cl, V_SimParticlesCS, V_ThreadGroupSizeFromBufferSize(max_particles));
|
||||
|
||||
// Barrier since decals were written
|
||||
G_DumbGlobalMemorySync(frame->cl);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Command table
|
||||
|
||||
#define V_CmdsTableXMacro(X) \
|
||||
X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \
|
||||
X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \
|
||||
X(toggle_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_E, .ctrl = 1 ), 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_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 ) ) \
|
||||
X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \
|
||||
X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \
|
||||
X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \
|
||||
X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \
|
||||
X(clear_decals, Clear decals, V_CmdDescFlag_None, V_HOTKEY( Button_C ), ) \
|
||||
X(clear_particles, Clear particles, V_CmdDescFlag_None, V_HOTKEY( Button_C, .alt = 1 ), ) \
|
||||
#define V_CmdsTableXMacro(X) \
|
||||
X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \
|
||||
X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \
|
||||
X(toggle_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_E, .ctrl = 1 ), 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_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 ) ) \
|
||||
X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \
|
||||
X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \
|
||||
X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \
|
||||
X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \
|
||||
X(clear_decals, Clear decals, V_CmdDescFlag_None, V_HOTKEY( Button_C, .alt = 1 ), ) \
|
||||
X(clear_particles, Clear particles, V_CmdDescFlag_None, V_HOTKEY( Button_C ), ) \
|
||||
/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -267,11 +267,17 @@ Struct(V_Frame)
|
||||
// Control
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
f32 fire_held;
|
||||
|
||||
// Sim cmds
|
||||
u64 sim_cmds_count;
|
||||
S_CmdNode *first_sim_cmd_node;
|
||||
S_CmdNode *last_sim_cmd_node;
|
||||
|
||||
// Emitters
|
||||
i64 emitters_count;
|
||||
V_EmitterNode *first_emitter_node;
|
||||
V_EmitterNode *last_emitter_node;
|
||||
};
|
||||
|
||||
Struct(V_Ctx)
|
||||
|
||||
@ -5,11 +5,11 @@
|
||||
ComputeShader2D(V_ClearDecalsCS, 8, 8)
|
||||
{
|
||||
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
|
||||
RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals);
|
||||
RWTexture2D<Vec4> decals = G_Dereference<Vec4>(params.decals);
|
||||
Vec2 decal_idx = SV_DispatchThreadID;
|
||||
if (decal_idx.x < countof(decals).x && decal_idx.y < countof(decals).y)
|
||||
{
|
||||
decals[decal_idx] = V_ParticleKind_None;
|
||||
decals[decal_idx] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,11 +21,10 @@ ComputeShader(V_ClearParticlesCS, 64)
|
||||
u32 particle_idx = SV_DispatchThreadID;
|
||||
if (particle_idx < params.max_particles)
|
||||
{
|
||||
particles[particle_idx].kind = V_ParticleKind_None;
|
||||
particles[particle_idx].exists = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Backdrop shader
|
||||
|
||||
@ -148,21 +147,38 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: Remove this
|
||||
// Decals test
|
||||
{
|
||||
RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals);
|
||||
RWTexture2D<Vec4> decals = G_Dereference<Vec4>(params.decals);
|
||||
Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(world_pos, 1));
|
||||
// Vec2 decal_uv = decal_pos / countof(decals);
|
||||
V_ParticleKind decal = decals.Load(decal_pos);
|
||||
|
||||
if (decal == V_ParticleKind_Test)
|
||||
Vec4 decal = decals.Load(decal_pos);
|
||||
if (decal.a != 0)
|
||||
{
|
||||
result = Color_Yellow;
|
||||
// result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
|
||||
result = decal;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: Remove this
|
||||
// Decals test
|
||||
// {
|
||||
// RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals);
|
||||
// Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(world_pos, 1));
|
||||
// // Vec2 decal_uv = decal_pos / countof(decals);
|
||||
// V_ParticleKind decal = decals.Load(decal_pos);
|
||||
|
||||
// if (decal == V_ParticleKind_Test)
|
||||
// {
|
||||
// // result = Color_Yellow;
|
||||
// // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
|
||||
// // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
target[SV_DispatchThreadID] = result;
|
||||
@ -238,7 +254,7 @@ ComputeShader(V_EmitParticlesCS, 64)
|
||||
for (u32 particle_seq = first_particle_seq; particle_seq < last_particle_seq; ++particle_seq)
|
||||
{
|
||||
u32 particle_idx = particle_seq % params.max_particles;
|
||||
particles[particle_idx].kind = emitter.particle_kind;
|
||||
particles[particle_idx].exists = 1;
|
||||
particles[particle_idx].emitter_init_num = emitter_idx + 1;
|
||||
particles[particle_idx].idx_in_emitter = particles_created_count;
|
||||
particles_created_count += 1;
|
||||
@ -253,14 +269,13 @@ ComputeShader(V_SimParticlesCS, 64)
|
||||
{
|
||||
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
|
||||
RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(params.particles);
|
||||
RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals);
|
||||
Texture2D<S_TileKind> tiles = G_Dereference<S_TileKind>(params.tiles);
|
||||
RWTexture2D<Vec4> decals = G_Dereference<Vec4>(params.decals);
|
||||
|
||||
u32 particle_idx = SV_DispatchThreadID;
|
||||
if (particle_idx < params.max_particles)
|
||||
{
|
||||
V_Particle particle = particles[particle_idx];
|
||||
if (particle.kind != V_ParticleKind_None)
|
||||
if (particle.exists > 0)
|
||||
{
|
||||
// Initialize
|
||||
if (particle.emitter_init_num != 0)
|
||||
@ -268,128 +283,57 @@ ComputeShader(V_SimParticlesCS, 64)
|
||||
V_Emitter emitter = G_Dereference<V_Emitter>(params.emitters)[particle.emitter_init_num - 1];
|
||||
|
||||
u64 seed = MixU64(emitter.seed + particle.idx_in_emitter);
|
||||
u32 speed_noise = ((u32)seed >> 0) & 0xFFFF;
|
||||
u32 angle_noise = ((u32)seed >> 16) & 0xFFFF;
|
||||
f32 speed_rand = speed_noise / (f32)0xFFFF;
|
||||
f32 angle_rand = angle_noise / (f32)0xFFFF;
|
||||
|
||||
f32 speed = emitter.speed + ((speed_rand - 0.5) * emitter.speed_spread);
|
||||
f32 angle = emitter.angle + ((angle_rand - 0.5) * emitter.angle_spread);
|
||||
// u32 speed_noise = (u32)((seed >> 0) & 0xFF);
|
||||
// u32 angle_noise = (u32)((seed >> 8) & 0xFF);
|
||||
|
||||
// u32 r_noise = (u32)((seed >> 8) & 0xFF);
|
||||
// u32 g_noise = (u32)((seed >> 8) & 0xFF);
|
||||
// u32 b_noise = (u32)((seed >> 8) & 0xFF);
|
||||
// u32 a_noise = (u32)((seed >> 8) & 0xFF);
|
||||
|
||||
// f32 speed_rand = speed_noise / (f32)0xFFFF;
|
||||
// f32 angle_rand = angle_noise / (f32)0xFFFF;
|
||||
|
||||
f32 rand_speed = (f32)((seed >> 0) & 0xFF) / (f32)0xFF - 0.5;
|
||||
f32 rand_angle = (f32)((seed >> 8) & 0xFF) / (f32)0xFF - 0.5;
|
||||
f32 rand_falloff = (f32)((seed >> 16) & 0xFF) / (f32)0xFF - 0.5;
|
||||
f32 rand_r = (f32)((seed >> 24) & 0xFF) / (f32)0xFF - 0.5;
|
||||
f32 rand_g = (f32)((seed >> 32) & 0xFF) / (f32)0xFF - 0.5;
|
||||
f32 rand_b = (f32)((seed >> 48) & 0xFF) / (f32)0xFF - 0.5;
|
||||
|
||||
f32 speed = emitter.speed + rand_speed * emitter.speed_spread;
|
||||
f32 angle = emitter.angle + rand_angle * emitter.angle_spread;
|
||||
f32 velocity_falloff = emitter.velocity_falloff + rand_falloff * emitter.velocity_falloff;
|
||||
Vec3 color = emitter.color_lin.rgb + Vec3(rand_r, rand_g, rand_b) * emitter.color_spread;
|
||||
|
||||
particle.pos = emitter.pos;
|
||||
particle.velocity = Vec2(cos(angle), sin(angle)) * speed;
|
||||
particle.velocity_falloff = velocity_falloff;
|
||||
particle.color = color;
|
||||
|
||||
particle.emitter_init_num = 0;
|
||||
}
|
||||
|
||||
// Simulate
|
||||
{
|
||||
f32 dt = params.dt;
|
||||
|
||||
Vec2 pos_a = particle.pos;
|
||||
Vec2 pos_b = pos_a + particle.velocity * dt;
|
||||
|
||||
// TODO: Don't query tiles
|
||||
Vec2I32 tile_pos_a = S_TilePosFromWorldPos(pos_a);
|
||||
S_TileKind tile_a = tiles.Load(Vec3I32(tile_pos_a, 0));
|
||||
b32 is_blocked_a = tile_a == S_TileKind_Wall;
|
||||
|
||||
Vec2 pos_a_decal = mul(params.xf.world_to_decal, Vec3(pos_a, 1));
|
||||
Vec2 pos_b_decal = mul(params.xf.world_to_decal, Vec3(pos_b, 1));
|
||||
|
||||
Vec2 step_a = pos_a_decal;
|
||||
Vec2 step_b = pos_b_decal;
|
||||
Vec2 step_vab = step_b - step_a;
|
||||
|
||||
f32 slope = step_vab.y / step_vab.x;
|
||||
i32 x_dir = (step_vab.x >= 0) - (step_vab.x < 0);
|
||||
|
||||
if (!is_blocked_a)
|
||||
{
|
||||
i32 step_x = step_a.x;
|
||||
for (;;)
|
||||
{
|
||||
f32 step_y = step_a.y + slope * (step_x - step_a.x);
|
||||
Vec2 step = Vec2(step_x, step_y);
|
||||
|
||||
// TODO: Don't query tiles
|
||||
Vec2 world_step = mul(params.xf.decal_to_world, Vec3(step, 1));
|
||||
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_step);
|
||||
S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0));
|
||||
|
||||
b32 is_blocked = tile == S_TileKind_Wall;
|
||||
if (is_blocked)
|
||||
{
|
||||
// particle.velocity *= -1;
|
||||
particle.velocity.y *= -1;
|
||||
// particle.velocity.x *= -1;
|
||||
break;
|
||||
}
|
||||
|
||||
step_x += x_dir;
|
||||
if (x_dir > 0)
|
||||
{
|
||||
if (step_x > (step_b.x + x_dir))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (step_x < (step_b.x + x_dir))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // Line walk
|
||||
// // FIXME: Real line walk, not aabb check
|
||||
// b32 is_blocked = 0;
|
||||
// for (u32 step_y = step_a.y; step_y <= step_b.y; ++step_y)
|
||||
// {
|
||||
// for (u32 step_x = step_a.x; step_x <= step_b.x; ++step_x)
|
||||
// {
|
||||
// // TODO: Don't query tiles
|
||||
// Vec2 world_step = mul(params.xf.decal_to_world, Vec3(step_x, step_y, 1));
|
||||
// Vec2I32 tile_pos = S_TilePosFromWorldPos(world_step);
|
||||
// S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0));
|
||||
|
||||
// if (tile == S_TileKind_Wall)
|
||||
// {
|
||||
// if (is_blocked)
|
||||
// {
|
||||
// // particle.velocity *= -1;
|
||||
// particle.velocity.x *= -1;
|
||||
// break;
|
||||
// }
|
||||
// is_blocked = 1;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
// Vec2I32 tile_pos = S_TilePosFromWorldPos(pos_a);
|
||||
// S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0));
|
||||
|
||||
|
||||
particle.pos = pos_a + particle.velocity * dt;
|
||||
particle.velocity = lerp(particle.velocity, 0, 4 * params.dt);
|
||||
|
||||
|
||||
particle.pos += particle.velocity * params.dt;
|
||||
particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt);
|
||||
Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(particle.pos, 1));
|
||||
if (decal_pos.x >= 0 && decal_pos.y >= 0 && decal_pos.x < countof(decals).x && decal_pos.y < countof(decals).y)
|
||||
{
|
||||
// FIXME: Atomic write
|
||||
decals[floor(decal_pos)] = particle.kind;
|
||||
decals[floor(decal_pos)] = Vec4(particle.color, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prune out of bounds particle
|
||||
particle.kind = V_ParticleKind_None;
|
||||
particle.exists = 0;
|
||||
}
|
||||
|
||||
if (particle.exists < 0.0001)
|
||||
{
|
||||
particle.exists = 0;
|
||||
}
|
||||
}
|
||||
particles[particle_idx] = particle;
|
||||
|
||||
@ -80,35 +80,47 @@ Struct(V_GpuParams)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Particle types
|
||||
|
||||
Enum(V_ParticleKind)
|
||||
Enum(V_ParticleFlag)
|
||||
{
|
||||
V_ParticleKind_None,
|
||||
V_ParticleKind_Test
|
||||
V_ParticleFlag_None = (0),
|
||||
};
|
||||
|
||||
Struct(V_Emitter)
|
||||
{
|
||||
V_ParticleKind particle_kind;
|
||||
V_ParticleFlag flags;
|
||||
|
||||
Vec2 pos;
|
||||
f32 angle;
|
||||
u32 count;
|
||||
f32 speed;
|
||||
|
||||
u64 seed;
|
||||
f32 angle_spread;
|
||||
|
||||
f32 speed;
|
||||
f32 speed_spread;
|
||||
|
||||
f32 angle;
|
||||
f32 angle_spread;
|
||||
|
||||
f32 velocity_falloff;
|
||||
f32 velocity_falloff_spread;
|
||||
|
||||
Vec4 color_lin;
|
||||
Vec3 color_spread;
|
||||
};
|
||||
|
||||
// TODO: Pack this efficiently
|
||||
Struct(V_Particle)
|
||||
{
|
||||
V_ParticleKind kind;
|
||||
V_ParticleFlag flags;
|
||||
|
||||
u32 emitter_init_num; // if != 0, then initialize using emitter at index (emitter_init_num - 1)
|
||||
u32 idx_in_emitter;
|
||||
|
||||
Vec2 pos;
|
||||
Vec2 velocity;
|
||||
|
||||
f32 exists;
|
||||
|
||||
f32 velocity_falloff;
|
||||
Vec3 color;
|
||||
};
|
||||
|
||||
#if IsLanguageC
|
||||
|
||||
@ -1695,7 +1695,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
|
||||
|
||||
// Rects
|
||||
u64 rects_count = ArenaCount(frame->rects_arena, UI_DRect);
|
||||
G_ResourceHandle rects_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->rects_arena));
|
||||
G_ResourceHandle rects_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->rects_arena));
|
||||
G_StructuredBufferRef rects_ro = G_PushStructuredBufferRef(frame->gpu_arena, rects_buff, UI_DRect);
|
||||
|
||||
// Params
|
||||
@ -1708,7 +1708,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
|
||||
params.cursor_pos = frame->cursor_pos;
|
||||
params.aa = TweakFloat("UI anti-aliasing", 1, 0, 1);
|
||||
}
|
||||
G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(¶ms));
|
||||
G_ResourceHandle params_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStruct(¶ms));
|
||||
G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, UI_DParams);
|
||||
|
||||
// Constants
|
||||
@ -1721,6 +1721,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
|
||||
//- Dispatch shaders
|
||||
|
||||
//- Clear pass
|
||||
|
||||
{
|
||||
G_ClearRenderTarget(frame->cl, draw_target, VEC4(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user