diff --git a/src/base/base.cgh b/src/base/base.cgh index b17db15b..303d0264 100644 --- a/src/base/base.cgh +++ b/src/base/base.cgh @@ -387,8 +387,9 @@ //////////////////////////////////////////////////////////// //~ Bit helper macros -#define AllBits(a, b) (((a) & (b)) == (b)) -#define AnyBit(a, b) (((a) & (b)) != 0) +#define AllBits(a, b) (((a) & (b)) == (b)) +#define AnyBit(a, b) (((a) & (b)) != 0) +#define SetBit(a, b, v) ((v) ? ((a) | (b)) : ((a) & ~(b))) //////////////////////////////////////////////////////////// //~ Color helper macros diff --git a/src/pp/pp.c b/src/pp/pp.c index 53f3f3d9..c0da42f9 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -3477,7 +3477,10 @@ void P_StepFrame(P_Frame *frame) trail->trail_p0 = p0; trail->trail_p1 = bullet->xf.t; trail->lifetime_seconds = 0; - + if (is_first_bullet_tick) + { + trail->is_first_trail = 1; + } } // TODO: Remove this diff --git a/src/pp/pp.h b/src/pp/pp.h index b29b5547..2f4bec97 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -145,7 +145,13 @@ Struct(P_Ent) b32 is_bullet; u32 bullet_hits_count; - //- Hit + + //- Events + + b32 is_trail; + Vec2 trail_p0; + Vec2 trail_p1; + b32 is_first_trail; b32 is_hit; Vec2 hit_entry; @@ -153,12 +159,6 @@ Struct(P_Ent) Vec2 hit_entry_velocity; P_MaterialKind hit_material; - //- Trail - - b32 is_trail; - Vec2 trail_p0; - Vec2 trail_p1; - //- Bomb b32 is_bomb; @@ -459,7 +459,7 @@ Enum(P_MsgKind) // Server -> Client P_MsgKind_Tiles, - P_MsgKind_PublicState, + P_MsgKind_NetVars, P_MsgKind_COUNT }; @@ -554,12 +554,12 @@ Struct(P_RaycastResult) //~ State types // NOTE: -// Public state is scanned and reflected dumbly to clients each frame, -// so absurdly large data should not go here. +// Network vars are networked reliably to clients whenever any change is detected. +// Large or frequently updated data should not go here. // -Struct(P_PublicState) +Struct(P_NetVarState) { - b32 is_recording_demo; + f32 server_tweak; }; Struct(P_SimStatistics) diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index 4e871fdb..c628d6a9 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -69,14 +69,13 @@ void S_TickForever(WaveLaneCtx *lane) BB_Buff packer_bb = BB_AcquireDynamicBuff(Gibi(64)); BB_Writer packer_bbw = BB_WriterFromBuff(&packer_bb); - P_PublicState *public = &S.public_state; - // FIXME: Header Rng user_msg_tick_range = RNG(SIM_TICKS_PER_SECOND * -SIM_MAX_PING, SIM_TICKS_PER_SECOND * SIM_MAX_PING); P_MsgList queued_user_msgs = Zi; P_MsgNode *first_free_user_msg_node = 0; + P_NetVarState *nvars = &S.nvars; @@ -406,98 +405,9 @@ void S_TickForever(WaveLaneCtx *lane) } } - - - - - - - - - - - ////////////////////////////// - //- Apply demo controls - - - // FIXME: Remove this - PERSIST i64 current_demo_tick = 0; - PERSIST Demo *demo = 0; - PERSIST b32 is_playing_demo; - if (!demo) - { - demo = PushStruct(perm, Demo); - } - - { - // FIXME: Remove this - if (is_playing_demo) - { - // Init tracks - { - P_EntList ents_to_spawn = Zi; - for (DemoTrack *track = demo->first_track; track; track = track->next) - { - P_Ent *player = P_EntFromKey(world_frame, track->player); - if (!player->is_player) - { - player = P_PushTempEnt(frame_arena, &ents_to_spawn); - player->key = P_RandEntKey(); - player->is_player = 1; - } - for (DemoCmd *demo_cmd = track->first_cmd; demo_cmd; demo_cmd = demo_cmd->next) - { - P_Control control = demo_cmd->control; - } - } - P_SpawnEntsFromList(world_frame, ents_to_spawn); - } - - // FIXME: No linear search - for (DemoTrack *track = demo->first_track; track; track = track->next) - { - P_Ent *player = P_EntFromKey(world_frame, track->player); - for (DemoCmd *demo_cmd = track->first_cmd; demo_cmd; demo_cmd = demo_cmd->next) - { - if (demo_cmd->demo_tick == current_demo_tick) - { - P_Control control = demo_cmd->control; - player->control = demo_cmd->control; - break; - } - } - } - } - } - - - - - - - - - - - - - - - - - - ////////////////////////////// //- Apply client controls - - - - - - - - for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next) { P_Control *control = &client->controls[world_frame->tick % client->controls_cap]; @@ -507,40 +417,10 @@ void S_TickForever(WaveLaneCtx *lane) if (player->is_player) { player->control = *control; - - if (client->is_recording_demo) - { - // FIXME: No linear search - DemoTrack *track = 0; - { - { - for (track = demo->first_track; track; track = track->next) - { - if (P_MatchEntKey(track->player, player->key)) - { - break; - } - } - } - if (!track) - { - track = PushStruct(perm, DemoTrack); - track->player = player->key; - DllQueuePush(demo->first_track, demo->last_track, track); - } - } - DemoCmd *demo_cmd = PushStruct(perm, DemoCmd); - demo_cmd->demo_tick = current_demo_tick; - demo_cmd->control = player->control; - SllQueuePush(track->first_cmd, track->last_cmd, demo_cmd); - } } } } - - - ////////////////////////////// //- Apply bot controls @@ -839,25 +719,31 @@ void S_TickForever(WaveLaneCtx *lane) } ////////////////////////////// - //- Push public state messages - - // TODO: Don't network reliably - // TODO: Delta compress + //- Push net vars { - P_Msg *msg = P_PushMsg(P_MsgKind_PublicState, Zstr); - msg->kind = P_MsgKind_PublicState; - msg->data = StringFromStruct(public); + String nvars_str = StringFromStruct(nvars); + u64 nvars_hash = HashString(nvars_str); + for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next) + { + if (client->sent_nvars_hash != nvars_hash) + { + P_Msg *msg = P_PushMsg(P_MsgKind_NetVars, Zstr); + msg->kind = P_MsgKind_NetVars; + msg->data = nvars_str; + msg->dst = client->net_key; + client->sent_nvars_hash = nvars_hash; + } + } } ////////////////////////////// //- Push tile messages { - // TODO: Receive remote tile hashes via player snapshots for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next) { - if (tiles_dirty || client->remote_tiles_hash != world->tiles_hash) + if (tiles_dirty || client->sent_tiles_hash != world->tiles_hash) { P_Msg *msg = P_PushMsg(P_MsgKind_Tiles, Zstr); msg->kind = P_MsgKind_Tiles; @@ -866,7 +752,7 @@ void S_TickForever(WaveLaneCtx *lane) msg->dst = client->net_key; msg->data = STRING(P_TilesCount, world->tiles); msg->xf = XformIdentity; - client->remote_tiles_hash = world->tiles_hash; + client->sent_tiles_hash = world->tiles_hash; } } } diff --git a/src/pp/pp_sim/pp_sim_core.h b/src/pp/pp_sim/pp_sim_core.h index 8aa1c012..66305d4a 100644 --- a/src/pp/pp_sim/pp_sim_core.h +++ b/src/pp/pp_sim/pp_sim_core.h @@ -1,51 +1,3 @@ - - - - - - -//////////////////////////////////////////////////////////// -//~ Demo types - - - -// FIXME: Remove this - - - - -Struct(DemoCmd) -{ - DemoCmd *next; - - i64 demo_tick; - P_Control control; -}; - -Struct(DemoTrack) -{ - DemoTrack *next; - DemoTrack *prev; - - P_EntKey player; - - DemoCmd *first_cmd; - DemoCmd *last_cmd; -}; - -Struct(Demo) -{ - DemoTrack *first_track; - DemoTrack *last_track; -}; - - - - - - - - //////////////////////////////////////////////////////////// //~ Client types @@ -74,7 +26,8 @@ Struct(S_Client) i64 demo_record_tick_offset; b32 is_recording_demo; - u64 remote_tiles_hash; + u64 sent_tiles_hash; + u64 sent_nvars_hash; }; Struct(S_ClientBin) @@ -97,7 +50,7 @@ Struct(S_Ctx) i64 client_bins_count; S_ClientBin *client_bins; - P_PublicState public_state; + P_NetVarState nvars; }; extern S_Ctx S; diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 23007685..db39c068 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -32,17 +32,30 @@ V_Frame *V_PrevFrame(void) V_Cmd *V_PushVisCmd(String name) { - V_Frame *frame = V_CurrentFrame(); - V_CmdNode *cmd_node = PushStruct(frame->arena, V_CmdNode); - V_Cmd *cmd = &cmd_node->cmd; + V_CmdNode *cmd_node = V.first_free_cmd_node; { - cmd->name = name; + if (cmd_node) + { + SllStackPop(V.first_free_cmd_node); + } + else + { + cmd_node = PushStruct(PermArena(), V_CmdNode); + } + V.queued_cmds_count += 1; + DllQueuePush(V.first_queued_cmd_node, V.last_queued_cmd_node, cmd_node); } - ++frame->cmds_count; - DllQueuePush(frame->first_cmd_node, frame->last_cmd_node, cmd_node); + V_Cmd *cmd = &cmd_node->cmd; + cmd->name = name; return cmd; } +i64 V_CountVisCmds(V_CmdKind kind) +{ + V_Frame *frame = V_CurrentFrame(); + return frame->cmd_counts_by_kind[kind]; +} + String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey) { String result = Zi; @@ -714,8 +727,8 @@ void V_TickForever(WaveLaneCtx *lane) BB_Buff packer_bb = BB_AcquireDynamicBuff(Gibi(64)); BB_Writer packer_bbw = BB_WriterFromBuff(&packer_bb); - // TODO: Reset public state when connected to new server - P_PublicState *public = &V.public_state; + // TODO: Reset nvars when connected to new server + P_NetVarState *nvars = &V.nvars; ////////////////////////////// //- Init vis state @@ -947,11 +960,14 @@ void V_TickForever(WaveLaneCtx *lane) frame->look = prev_frame->look; frame->fire_presses = prev_frame->fire_presses; frame->roll_presses = prev_frame->roll_presses; + frame->show_consoles = prev_frame->show_consoles; + frame->show_profilers = prev_frame->show_profilers; frame->edit_mode = prev_frame->edit_mode; frame->equipped_tile = prev_frame->equipped_tile; frame->equipped_prefab = prev_frame->equipped_prefab ; frame->edit_camera_pos = prev_frame->edit_camera_pos; frame->edit_camera_zoom = prev_frame->edit_camera_zoom; + frame->camera_shake = prev_frame->camera_shake; frame->prev_timeline = prev_frame->timeline; frame->timeline = prev_frame->timeline; frame->sim_key = prev_frame->sim_key; @@ -1362,6 +1378,33 @@ void V_TickForever(WaveLaneCtx *lane) } } + ////////////////////////////// + //- Pop queued vis cmds + + { + for (V_CmdNode *cmd_node = V.first_queued_cmd_node; cmd_node; cmd_node = cmd_node->next) + { + String cmd_name = cmd_node->cmd.name; + for (V_CmdKind kind = V_CmdKind_nop; kind < V_CmdKind_COUNT; ++kind) + { + V_CmdDesc desc = V_cmd_descs[kind]; + if (MatchString(desc.name, cmd_name)) + { + frame->cmd_counts_by_kind[kind] += 1; + break; + } + } + } + if (V.last_queued_cmd_node) + { + V.last_queued_cmd_node->next = V.first_free_cmd_node; + } + V.first_free_cmd_node = V.first_queued_cmd_node; + V.first_queued_cmd_node = 0; + V.last_queued_cmd_node = 0; + V.queued_cmds_count = 0; + } + ////////////////////////////// //- Compute movement & look @@ -1528,6 +1571,37 @@ void V_TickForever(WaveLaneCtx *lane) frame->camera_pos = LerpVec2(prev_frame->camera_pos, target_camera_pos, frame->camera_lerp_rate); frame->camera_zoom = LerpF32(prev_frame->camera_zoom, target_camera_zoom, frame->camera_lerp_rate); } + + + + + + + // FIXME: Remove this + + // Apply shake + { + // FIXME: Remove this + + // shake_amount = 0; + f32 shake_strength = TweakFloat("Shake strength", 50, 0, 1); + if (frame->held_buttons[Button_R] && !prev_frame->held_buttons[Button_R]) + { + frame->camera_shake += shake_strength; + } + + u64 seed = MixU64(frame->tick); + f32 x = Norm16(seed >> 0) * 2 - 1; + f32 y = Norm16(seed >> 16) * 2 - 1; + // x -= 1; + // x *= 0.5; + // f32 x = (Norm24(MixU64(frame->tick)) - 2); + x *= frame->camera_shake * frame->dt; + y *= frame->camera_shake * frame->dt; + frame->camera_pos = AddVec2(frame->camera_pos, VEC2(x, y)); + + frame->camera_shake = LerpF32(frame->camera_shake, 0, 5 * frame->dt); + } } ////////////////////////////// @@ -1819,14 +1893,15 @@ void V_TickForever(WaveLaneCtx *lane) V_PushNotif(txt); } - //- Public state - if (msg->kind == P_MsgKind_PublicState) + //- Net var + if (msg->kind == P_MsgKind_NetVars) { + LogDebugF("Network variables received from server"); String data = msg->data; - u64 safe_copy_len = sizeof(*public); + u64 safe_copy_len = sizeof(*nvars); if (data.len == safe_copy_len) { - CopyBytes(public, data.text, safe_copy_len); + CopyBytes(nvars, data.text, safe_copy_len); } } @@ -2936,125 +3011,417 @@ void V_TickForever(WaveLaneCtx *lane) - - - - - - - - - //////////////////////////// - //- Push bullet trail particles - - - - - // TODO: Not like this - - for (P_Ent *trail = P_FirstEnt(local_frame); !P_IsEntNil(trail); trail = P_NextEnt(trail)) - { - if (trail->is_trail && trail->is_first_observation) - { - Vec2 p0 = trail->trail_p0; - Vec2 p1 = trail->trail_p1; - - f32 trail_len = Vec2Len(SubVec2(p1, p0)); - f32 particles_count = trail_len * frame->dt * Kibi(8); // Particles per meter per second - particles_count = MaxF32(particles_count, 1); - - f32 angle = AngleFromVec2(PerpVec2(SubVec2(p1, p0))); - // f32 angle = AngleFromVec2(NegVec2(SubVec2(p1, p0))); - - V_Emitter emitter = Zi; - { - emitter.kind = V_ParticleKind_BulletTrail; - emitter.count = particles_count; - - f32 angle_spread = Tau / 4.0; - - emitter.angle.min = angle - angle_spread / 2; - emitter.angle.max = angle + angle_spread / 2; - - emitter.pos.p0 = p0; - emitter.pos.p1 = p1; - - // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); - - // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); - - emitter.speed.min = -1; - emitter.speed.max = 1; - } - V_PushParticles(emitter); - } - } - - - - - - ////////////////////////////// - //- Push test impact particles + //- Process event entities - // TODO: Not like this - - - - // if (0) + for (P_Ent *event = P_FirstEnt(local_frame); !P_IsEntNil(event); event = P_NextEnt(event)) { - for (P_Ent *hit = P_FirstEnt(local_frame); !P_IsEntNil(hit); hit = P_NextEnt(hit)) + if (event->is_first_observation) { - if (hit->is_hit && hit->is_first_observation) + u64 angle_offset_basis = 0xf55070bae6e1d70c; + f32 rand_angle = (Norm24(MixU64s(event->key.v, angle_offset_basis)) * 2 - 1); + + ////////////////////////////// + //- Trail + + + // TODO: Remove this + + + if (event->is_trail) { - P_MaterialKind material = hit->hit_material; + Vec2 p0 = event->trail_p0; + Vec2 p1 = event->trail_p1; - Vec2 hit_entry = hit->hit_entry; - Vec2 hit_entry_normal = hit->hit_entry_normal; - Vec2 hit_entry_velocity = hit->hit_entry_velocity; + //- Smoke trail particles + // { + // f32 trail_len = Vec2Len(SubVec2(p1, p0)); + // f32 particles_count = trail_len * frame->dt * Kibi(8); // Particles per meter per second + // particles_count = MaxF32(particles_count, 1); - ////////////////////////////// - //- Wall particles + // f32 angle = AngleFromVec2(PerpVec2(SubVec2(p1, p0))); + // // f32 angle = AngleFromVec2(NegVec2(SubVec2(p1, p0))); - if (material != P_MaterialKind_Flesh) + // V_Emitter emitter = Zi; + // { + // emitter.kind = V_ParticleKind_BulletTrail; + // emitter.count = particles_count; + + // f32 angle_spread = Tau / 4.0; + + // emitter.angle.min = angle - angle_spread / 2; + // emitter.angle.max = angle + angle_spread / 2; + + // emitter.pos.p0 = p0; + // emitter.pos.p1 = p1; + + // // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + + // emitter.speed.min = -1; + // emitter.speed.max = 1; + // } + // V_PushParticles(emitter); + // } + + if (event->is_first_trail) { - //- Wall debris + //- Muzzle spark particles { V_Emitter emitter = Zi; - { - // emitter.flags |= V_ParticleFlag_PruneWhenStill; - // emitter.flags |= V_ParticleFlag_StainOnPrune; + emitter.kind = V_ParticleKind_Flash; + // emitter.count = MaxF32(1000 * frame->dt, 1); + // emitter.count = 128; + emitter.count = 8; + f32 angle = AngleFromVec2(SubVec2(p1, p0)); - emitter.kind = V_ParticleKind_Debris; - emitter.count = 4; + f32 angle_spread = Tau / 2; + emitter.angle.min = angle - angle_spread / 2; + emitter.angle.max = angle + angle_spread / 2; - emitter.pos.p0 = emitter.pos.p1 = hit_entry; + emitter.pos.p0 = + emitter.pos.p1 = p0; - emitter.speed.min = 0; - emitter.speed.max = 20; + // emitter.lifetime.min = 0.1 + // emitter.lifetime.max = 0.5; - // emitter.velocity_falloff = 5; - // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; + // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); - Vec2 dir = hit_entry_normal; + // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); - f32 angle = AngleFromVec2(dir); - f32 angle_spread = Tau * 0.5; + emitter.speed.min = 5; + emitter.speed.max = 20; - emitter.angle.min = angle - angle_spread / 2; - emitter.angle.max = angle + angle_spread / 2; + // emitter.angle.min = angle - angle_spread / 2; + // emitter.angle.max = angle + angle_spread / 2; + + // emitter.angle.min = + // emitter.angle.max = angle; + + emitter.pos.p0 = + emitter.pos.p1 = p0; + + // emitter.speed.min = + // emitter.speed.max = + + // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + // emitter.speed.min = + // emitter.speed.max = Vec2Len(SubVec2(p1, p0)) / frame->dt; - // emitter.lifetime = 0.25; - // emitter.lifetime = 0.05; - // emitter.lifetime = 0.04; - // emitter.lifetime_spread = emitter.lifetime * 2; - } V_PushParticles(emitter); } - //- Wall dust + + //- Wide muzzle flash particles + { + V_Emitter emitter = Zi; + emitter.kind = V_ParticleKind_Spark; + // emitter.count = MaxF32(1000 * frame->dt, 1); + // emitter.count = 128; + emitter.count = 1; + + f32 angle = AngleFromVec2(SubVec2(p1, p0)); + + f32 angle_spread = Tau / 2; + emitter.angle.min = angle - angle_spread / 2; + emitter.angle.max = angle + angle_spread / 2; + + emitter.pos.p0 = + emitter.pos.p1 = p0; + + // emitter.lifetime.min = 0.1 + // emitter.lifetime.max = 0.5; + + // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + + emitter.speed.min = 20; + emitter.speed.max = 100; + + // emitter.angle.min = angle - angle_spread / 2; + // emitter.angle.max = angle + angle_spread / 2; + + // emitter.angle.min = + // emitter.angle.max = angle; + + emitter.pos.p0 = + emitter.pos.p1 = p0; + + // emitter.speed.min = + // emitter.speed.max = + + // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + // emitter.speed.min = + // emitter.speed.max = Vec2Len(SubVec2(p1, p0)) / frame->dt; + + V_PushParticles(emitter); + } + + + + + + + + //- Narrow muzzle flash particles + { + V_Emitter emitter = Zi; + emitter.kind = V_ParticleKind_Flash; + // emitter.count = MaxF32(1000 * frame->dt, 1); + // emitter.count = 128; + emitter.count = 1; + + f32 angle = AngleFromVec2(SubVec2(p1, p0)); + + // f32 angle_spread = Tau / 64; + f32 angle_spread = 0; + emitter.angle.min = angle - angle_spread / 2; + emitter.angle.max = angle + angle_spread / 2; + + emitter.pos.p0 = + emitter.pos.p1 = p0; + + // emitter.lifetime.min = 0.1 + // emitter.lifetime.max = 0.5; + + // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + + emitter.speed.min = 35; + emitter.speed.max = 35; + + // emitter.angle.min = angle - angle_spread / 2; + // emitter.angle.max = angle + angle_spread / 2; + + // emitter.angle.min = + // emitter.angle.max = angle; + + emitter.pos.p0 = + emitter.pos.p1 = p0; + + // emitter.speed.min = + // emitter.speed.max = + + // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + // emitter.speed.min = + // emitter.speed.max = Vec2Len(SubVec2(p1, p0)) / frame->dt; + + V_PushParticles(emitter); + } + + + + + + + + + + + + + + //- Test bullet casing + // { + // V_Emitter emitter = Zi; + // emitter.kind = V_ParticleKind_Fire; + // // emitter.count = MaxF32(1000 * frame->dt, 1); + // emitter.count = 8; + + // f32 angle = AngleFromVec2(SubVec2(p1, p0)); + + // f32 angle_spread = Tau / 4; + // emitter.angle.min = angle - angle_spread / 2; + // emitter.angle.max = angle + angle_spread / 2; + + // emitter.pos.p0 = + // emitter.pos.p1 = p0; + + // // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + + // emitter.speed.min = 0; + // emitter.speed.max = 25; + + // // emitter.angle.min = angle - angle_spread / 2; + // // emitter.angle.max = angle + angle_spread / 2; + + // // emitter.angle.min = + // // emitter.angle.max = angle; + + // emitter.pos.p0 = + // emitter.pos.p1 = p0; + + // // emitter.speed.min = + // // emitter.speed.max = + + // // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + // // emitter.speed.min = + // // emitter.speed.max = Vec2Len(SubVec2(p1, p0)) / frame->dt; + + // V_PushParticles(emitter); + // } + + + + + + + + //- Test bullet particle + // { + // V_Emitter emitter = Zi; + // emitter.kind = V_ParticleKind_Fire; + // // emitter.count = MaxF32(1000 * frame->dt, 1); + // emitter.count = 1; + + // f32 angle = AngleFromVec2(SubVec2(p1, p0)); + + // // f32 angle_spread = Tau / 4.0; + + // // emitter.angle.min = angle - angle_spread / 2; + // // emitter.angle.max = angle + angle_spread / 2; + + // emitter.angle.min = + // emitter.angle.max = angle; + + // emitter.pos.p0 = + // emitter.pos.p1 = p0; + + // // emitter.speed.min = + // // emitter.speed.max = + + // // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + // emitter.speed.min = + // emitter.speed.max = Vec2Len(SubVec2(p1, p0)) / frame->dt; + + // V_PushParticles(emitter); + // } + } + } + + + + + + ////////////////////////////// + //- Hit + + if (event->is_hit) + { + P_MaterialKind material = event->hit_material; + + Vec2 hit_entry = event->hit_entry; + Vec2 hit_entry_normal = event->hit_entry_normal; + Vec2 hit_entry_velocity = event->hit_entry_velocity; + + //- Wall impact particles + if (material != P_MaterialKind_Flesh) + { + // Debris + // { + // V_Emitter emitter = Zi; + // { + // // emitter.flags |= V_ParticleFlag_PruneWhenStill; + // // emitter.flags |= V_ParticleFlag_StainOnPrune; + + + // emitter.kind = V_ParticleKind_Debris; + // emitter.count = 4; + + // emitter.pos.p0 = + // emitter.pos.p1 = hit_entry; + + // emitter.speed.min = 0; + // emitter.speed.max = 20; + + // // emitter.velocity_falloff = 5; + // // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; + + // Vec2 dir = hit_entry_normal; + + // f32 angle = AngleFromVec2(dir); + // f32 angle_spread = Tau * 0.5; + + // emitter.angle.min = angle - angle_spread / 2; + // emitter.angle.max = angle + angle_spread / 2; + + // // emitter.lifetime = 0.25; + // // emitter.lifetime = 0.05; + // // emitter.lifetime = 0.04; + // // emitter.lifetime_spread = emitter.lifetime * 2; + // } + // V_PushParticles(emitter); + // } + + // Fire + // { + // V_Emitter emitter = Zi; + // emitter.kind = V_ParticleKind_Fire; + // // emitter.count = MaxF32(1000 * frame->dt, 1); + // emitter.count = 2; + + // // f32 angle = AngleFromVec2(SubVec2(p1, p0)); + + // f32 angle = AngleFromVec2(hit_entry_normal); + // angle += rand_angle * (Tau * 0.05); + + // f32 angle_particle_spread = Tau / 4; + // emitter.angle.min = angle - angle_particle_spread / 2; + // emitter.angle.max = angle + angle_particle_spread / 2; + + // emitter.pos.p0 = + // emitter.pos.p1 = hit_entry; + + // // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + + // emitter.speed.min = 0; + // emitter.speed.max = 25; + + // // emitter.angle.min = angle - angle_spread / 2; + // // emitter.angle.max = angle + angle_spread / 2; + + // // emitter.angle.min = + // // emitter.angle.max = angle; + + // // emitter.pos.p0 = + // // emitter.pos.p1 = p0; + + // // emitter.speed.min = + // // emitter.speed.max = + + // // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + + // // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + // // emitter.speed.min = + // // emitter.speed.max = Vec2Len(SubVec2(p1, p0)) / frame->dt; + + // V_PushParticles(emitter); + // } + + + + + + + // Wall dust // { // V_Emitter emitter = Zi; // { @@ -3083,40 +3450,36 @@ void V_TickForever(WaveLaneCtx *lane) // } } - ////////////////////////////// - //- Blood particles - + //- Flesh impact particles if (material == P_MaterialKind_Flesh) { - { - V_Emitter emitter = Zi; + V_Emitter emitter = Zi; - emitter.kind = V_ParticleKind_BloodTrail; - // emitter.kind = V_ParticleKind_BloodDebris; + emitter.kind = V_ParticleKind_BloodTrail; + // emitter.kind = V_ParticleKind_BloodDebris; - Vec2 dir = NormVec2(NegVec2(hit_entry_velocity)); + Vec2 dir = NormVec2(NegVec2(hit_entry_velocity)); - f32 angle = AngleFromVec2(dir); - // f32 angle = 0; - // f32 angle_spread = Tau * 0.25; - f32 angle_spread = TweakFloat("Emitter angle spread", 0.1, 0, 1) * Tau; - // f32 angle_spread = Tau; - // f32 angle_spread = 0; + f32 angle = AngleFromVec2(dir); + // f32 angle = 0; + // f32 angle_spread = Tau * 0.25; + f32 angle_spread = TweakFloat("Emitter angle spread", 0.1, 0, 1) * Tau; + // f32 angle_spread = Tau; + // f32 angle_spread = 0; - // f32 speed = 5; - // f32 speed = 25; - f32 speed = 50; - // f32 speed = 100; - f32 speed_spread = speed * 2; + // f32 speed = 5; + // f32 speed = 25; + f32 speed = 50; + // f32 speed = 100; + f32 speed_spread = speed * 2; - emitter.pos.p0 = emitter.pos.p1 = hit_entry; - emitter.speed.min = speed - speed_spread * 0.5; - emitter.speed.max = speed + speed_spread * 0.5; - emitter.angle.min = angle - angle_spread * 0.5; - emitter.angle.max = angle + angle_spread * 0.5; - emitter.count = TweakFloat("Emitter count", 32, 0, Kibi(64)); - V_PushParticles(emitter); - } + emitter.pos.p0 = emitter.pos.p1 = hit_entry; + emitter.speed.min = speed - speed_spread * 0.5; + emitter.speed.max = speed + speed_spread * 0.5; + emitter.angle.min = angle - angle_spread * 0.5; + emitter.angle.max = angle + angle_spread * 0.5; + emitter.count = TweakFloat("Emitter count", 32, 0, Kibi(64)); + V_PushParticles(emitter); } // V_DrawPoint(victim_raycast.p, Color_Green); @@ -3141,219 +3504,6 @@ void V_TickForever(WaveLaneCtx *lane) - - // ////////////////////////////// - // //- Push test bullet particles - - // // TODO: Not like this - - // for (P_Ent *bullet = P_FirstEnt(local_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet)) - // { - // if (bullet->is_bullet) - // { - // // FIXME: Use 'last visible' pos - // P_Ent *old_bullet = P_EntFromKey(prev_local_frame, bullet->key); - // Vec2 start = old_bullet->xf.t; - // Vec2 end = bullet->xf.t; - // if (P_IsEntNil(old_bullet)) - // { - // start = end; - // } - - // b32 skip = 0; - // if (bullet->has_hit) - // { - // Vec2 hit_pos = bullet->hit_entry; - // if (DotVec2(SubVec2(hit_pos, start), SubVec2(end, start)) < 0) - // { - // skip = 1; - // } - // // V_DrawPoint(MulAffineVec2(frame->af.world_to_screen, start), Color_Red); - // // V_DrawPoint(MulAffineVec2(frame->af.world_to_screen, end), Color_Purple); - // end = hit_pos; - // } - - // if (!skip) - // { - // { - // f32 trail_len = Vec2Len(SubVec2(end, start)); - // f32 particles_count = trail_len * frame->dt * Kibi(8); // Particles per meter per second - // particles_count = MaxF32(particles_count, 1); - - // f32 angle = AngleFromVec2(PerpVec2(SubVec2(end, start))); - // // f32 angle = AngleFromVec2(NegVec2(SubVec2(end, start))); - - // V_Emitter emitter = Zi; - // { - // emitter.kind = V_ParticleKind_BulletTrail; - // emitter.count = particles_count; - - // f32 angle_spread = Tau / 4.0; - - // emitter.angle.min = angle - angle_spread / 2; - // emitter.angle.max = angle + angle_spread / 2; - - // emitter.pos.p0 = start; - // emitter.pos.p1 = end; - - // // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); - - // // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); - - // emitter.speed.min = -1; - // emitter.speed.max = 1; - // } - // V_PushParticles(emitter); - // } - // } - // } - // } - - - - - // ////////////////////////////// - // //- Push test impact particles - - // // TODO: Not like this - - - - // // if (0) - // { - // for (P_Ent *bullet = P_FirstEnt(local_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet)) - // { - // if (bullet->is_bullet && bullet->has_hit) - // { - // // FIXME: Use actual velocity - // P_Ent *old_bullet = P_EntFromKey(prev_local_frame, bullet->key); - // Vec2 start = old_bullet->xf.t; - // Vec2 end = bullet->xf.t; - // if (P_IsEntNil(old_bullet)) - // { - // start = end; - // } - - // P_MaterialKind material = bullet->hit_material; - - // Vec2 hit_entry = bullet->hit_entry; - // Vec2 hit_entry_normal = bullet->hit_entry_normal; - // Vec2 hit_entry_velocity = bullet->hit_entry_velocity; - - // ////////////////////////////// - // //- Wall particles - - // if (material != P_MaterialKind_Flesh) - // { - // //- Wall debris - // { - // V_Emitter emitter = Zi; - // { - // // emitter.flags |= V_ParticleFlag_PruneWhenStill; - // // emitter.flags |= V_ParticleFlag_StainOnPrune; - - - // emitter.kind = V_ParticleKind_Debris; - // emitter.count = 4; - - // emitter.pos.p0 = emitter.pos.p1 = hit_entry; - - // emitter.speed.min = 0; - // emitter.speed.max = 20; - - // // emitter.velocity_falloff = 5; - // // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; - - // Vec2 dir = hit_entry_normal; - - // f32 angle = AngleFromVec2(dir); - // f32 angle_spread = Tau * 0.5; - - // emitter.angle.min = angle - angle_spread / 2; - // emitter.angle.max = angle + angle_spread / 2; - - // // emitter.lifetime = 0.25; - // // emitter.lifetime = 0.05; - // // emitter.lifetime = 0.04; - // // emitter.lifetime_spread = emitter.lifetime * 2; - // } - // V_PushParticles(emitter); - // } - - // //- Wall dust - // // { - // // V_Emitter emitter = Zi; - // // { - // // emitter.kind = V_ParticleKind_Smoke; - // // emitter.count = 128; - - // // emitter.pos.p0 = emitter.pos.p1 = hit_entry; - - // // // emitter.color_lin = LinearFromSrgb(VEC4(0.5, 0.5, 0.5, 0.75)); - - // // emitter.speed.min = 10; - // // emitter.speed.max = 20; - - // // // emitter.velocity_falloff = 12; - // // // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; - - // // Vec2 dir = hit_entry_normal; - // // f32 angle = AngleFromVec2(dir); - // // f32 angle_spread = Tau * 0.1; - - // // emitter.angle.min = angle - angle_spread / 2; - // // emitter.angle.max = angle + angle_spread / 2; - - // // } - // // V_PushParticles(emitter); - // // } - // } - - // ////////////////////////////// - // //- Blood particles - - // if (material == P_MaterialKind_Flesh) - // { - // { - // V_Emitter emitter = Zi; - - // emitter.kind = V_ParticleKind_BloodTrail; - // // emitter.kind = V_ParticleKind_BloodDebris; - - // Vec2 dir = NormVec2(NegVec2(hit_entry_velocity)); - - // f32 angle = AngleFromVec2(dir); - // // f32 angle = 0; - // // f32 angle_spread = Tau * 0.25; - // f32 angle_spread = TweakFloat("Emitter angle spread", 0.1, 0, 1) * Tau; - // // f32 angle_spread = Tau; - // // f32 angle_spread = 0; - - // // f32 speed = 5; - // // f32 speed = 25; - // f32 speed = 50; - // // f32 speed = 100; - // f32 speed_spread = speed * 2; - - // emitter.pos.p0 = emitter.pos.p1 = hit_entry; - // emitter.speed.min = speed - speed_spread * 0.5; - // emitter.speed.max = speed + speed_spread * 0.5; - // emitter.angle.min = angle - angle_spread * 0.5; - // emitter.angle.max = angle + angle_spread * 0.5; - // emitter.count = TweakFloat("Emitter count", 1, 0, 100) * (Kibi(1) * frame->dt); - // V_PushParticles(emitter); - // } - // } - - // // V_DrawPoint(victim_raycast.p, Color_Green); - // // V_DrawLine(victim_raycast.p, AddVec2(victim_raycast.p, MulVec2(victim_raycast.normal, 0.5)), Color_White); - // } - // } - // } - - - - ////////////////////////////// //- Push test emitter @@ -3722,16 +3872,6 @@ void V_TickForever(WaveLaneCtx *lane) - - - - b32 show_panels = (frame->is_editing && !hide_editor_ui) || TweakBool("Show panels when not editing", 0); - - - - - - // FIXME: Limit dims based on sample buffer capacity // b32 should_draw_profiler_graph = frame->profiler.is_showing && frame->profiler.graph_dims.x > 0 && frame->profiler.graph_dims.y > 0; // frame->profiler_graph_dims = frame->profiler.graph_dims; @@ -3747,7 +3887,7 @@ void V_TickForever(WaveLaneCtx *lane) - if (show_panels && V.root_panel) + if (V.root_panel) { Struct(BfsPanel) { BfsPanel *next; V_Panel *panel; }; BfsPanel *first_bfs_panel = PushStruct(frame->arena, BfsPanel); @@ -5223,13 +5363,153 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// - //- Build panels + //- Init panel layout + + // TODO: Allow for custom layouts stored in config files + // TODO: Don't use rand keys for panels + + if (!V.root_panel) + { + V.root_panel = PushStruct(perm, V_Panel); + V_Panel *left_panel = PushStruct(perm, V_Panel); + V_Panel *right_panel = PushStruct(perm, V_Panel); + + //- Root panel + { + { + V_Panel *panel = V.root_panel; + panel->box = UI_KeyF("test root panel"); + panel->contents_box = vis_panels_box; + panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); + panel->pct = 1; + panel->is_organizational = 1; + panel->axis = Axis_X; + V.root_panel = panel; + } + + //- Left panel + { + V_Panel *panel = left_panel; + panel->parent = V.root_panel; + panel->axis = Axis_X; + DllQueuePush(panel->parent->first, panel->parent->last, panel); + panel->box = UI_RandKey(); + panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); + panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); + panel->pct = 0.10; + panel->is_organizational = 1; + } + + //- Right panel + { + V_Panel *panel = right_panel; + panel->parent = V.root_panel; + panel->axis = Axis_Y; + DllQueuePush(panel->parent->first, panel->parent->last, panel); + panel->box = UI_RandKey(); + panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); + panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); + panel->pct = 0.90; + panel->is_organizational = 1; + } + } + + // //- Test profiler panel + // { + // V_Panel *parent = right_bottom_panel; + // V_Panel *panel = PushStruct(perm, V_Panel); + // panel->axis = Axis_X; + // DllQueuePush(panel->parent->first, panel->parent->last, panel); + // panel->box = UI_KeyF("test raah profiler panel"); + // panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); + // panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); + // panel->flags |= V_PanelFlag_Profiler; + // panel->flags |= V_PanelFlag_Ignore; + // panel->pct = 2; + // } + + //- Test spawn panel + { + V_Panel *panel = PushStruct(perm, V_Panel); + panel->parent = left_panel; + panel->axis = Axis_X; + DllQueuePush(panel->parent->first, panel->parent->last, panel); + panel->box = UI_RandKey(); + panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); + panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); + panel->flags |= V_PanelFlag_Spawn; + panel->pct = 0.25; + } + + //- Test console panel + { + V_Panel *parent = right_panel; + V_Panel *panel = PushStruct(perm, V_Panel); + panel->axis = Axis_X; + DllQueuePush(parent->first, parent->last, panel); + panel->box = UI_KeyF("test raah console panel"); + panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); + panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); + panel->flags |= V_PanelFlag_Console; + // panel->flags |= V_PanelFlag_Spawn; + panel->pct = 0.25; + } + + //- Vis screen panel + { + V_Panel *panel = PushStruct(perm, V_Panel); + panel->parent = right_panel; + panel->axis = Axis_X; + DllQueuePush(panel->parent->first, panel->parent->last, panel); + panel->box = UI_RandKey(); + panel->contents_box = vis_screen_panel_box; + panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); + panel->flags |= V_PanelFlag_Screen; + panel->pct = 1; + } + } + ////////////////////////////// + //- Update panels from cmds + + b32 show_editor_panels = (frame->is_editing && !hide_editor_ui) || TweakBool("Show panels when not editing", 0); + { + Struct(PanelBfs) { PanelBfs *next; V_Panel *panel; }; + PanelBfs *first_panel_bfs = PushStruct(frame->arena, PanelBfs); + PanelBfs *last_panel_bfs = first_panel_bfs; + first_panel_bfs->panel = V.root_panel; + for (PanelBfs *bfs_parent = first_panel_bfs; bfs_parent; bfs_parent = first_panel_bfs) + { + SllQueuePop(first_panel_bfs, last_panel_bfs); + V_Panel *parent_panel = bfs_parent->panel; + for (V_Panel *panel = parent_panel->first; panel; panel = panel->next) + { + PanelBfs *bfs_panel = PushStruct(frame->arena, PanelBfs); + bfs_panel->panel = panel; + SllQueuePush(first_panel_bfs, last_panel_bfs, bfs_panel); + { + b32 should_show = 1; + b32 is_editor_panel = !panel->is_organizational && !AnyBit(panel->flags, V_PanelFlag_Screen | V_PanelFlag_Console); + should_show = should_show && (!is_editor_panel || show_editor_panels); + should_show = should_show && (!AnyBit(panel->flags, V_PanelFlag_Console) || frame->show_consoles); + should_show = should_show && (!AnyBit(panel->flags, V_PanelFlag_Profiler) || frame->show_profilers); + panel->flags = SetBit(panel->flags, V_PanelFlag_Ignore, !should_show); + } + } + } + } + + + + + + ////////////////////////////// + //- Build vis panel contents UI_PushDF(Tag, HashF("vis panels")) { @@ -5238,91 +5518,10 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Init test panels - // FIXME: Remove this - - - if (!V.root_panel) - { - V_Panel *subroot_panel = 0; - - //- Root panel - { - { - V_Panel *panel = PushStruct(perm, V_Panel); - panel->box = UI_KeyF("test root panel"); - panel->contents_box = vis_panels_box; - panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); - panel->pct = 1; - panel->axis = Axis_Y; - V.root_panel = panel; - } - - //- Sub-root panel - { - V_Panel *parent = V.root_panel; - V_Panel *panel = PushStruct(perm, V_Panel); - panel->parent = parent; - panel->axis = Axis_X; - DllQueuePush(parent->first, parent->last, panel); - panel->box = UI_KeyF("test raah subroot row panel"); - panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); - panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); - panel->pct = 1; - panel->is_organizational = 1; - subroot_panel = panel; - } - } - - //- Test profiler panel - { - V_Panel *parent = subroot_panel; - V_Panel *panel = PushStruct(perm, V_Panel); - panel->parent = parent; - panel->axis = Axis_X; - DllQueuePush(parent->first, parent->last, panel); - panel->box = UI_KeyF("test raah profiler panel"); - panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); - panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); - panel->flags |= V_PanelFlag_Profiler; - panel->flags |= V_PanelFlag_Ignore; - panel->pct = 2; - } - - //- Test console panel - { - V_Panel *parent = subroot_panel; - V_Panel *panel = PushStruct(perm, V_Panel); - panel->parent = parent; - panel->axis = Axis_X; - DllQueuePush(parent->first, parent->last, panel); - panel->box = UI_KeyF("test raah console panel"); - panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); - panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); - // panel->flags |= V_PanelFlag_Console; - panel->flags |= V_PanelFlag_Spawn; - panel->pct = 0.25; - } - - //- Vis screen panel - { - V_Panel *parent = subroot_panel; - V_Panel *panel = PushStruct(perm, V_Panel); - panel->parent = parent; - panel->axis = Axis_X; - DllQueuePush(parent->first, parent->last, panel); - panel->box = UI_KeyF("test vis ui panel"); - panel->contents_box = vis_screen_panel_box; - panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); - panel->pct = 1; - } - } - // // FIXME: Remove this (build it as a panel) - // BuildBoxEx(vis_screen_box); - @@ -5331,12 +5530,12 @@ void V_TickForever(WaveLaneCtx *lane) // UI_PushDF(Parent, vis_root_box) - if (!show_panels) - { - UI_SetNext(Flags, UI_BoxFlag_Floating); - UI_SetNext(Parent, vis_root_box); - UI_BuildColumnEx(vis_screen_panel_box); - } + // if (!show_panels) + // { + // UI_SetNext(Flags, UI_BoxFlag_Floating); + // UI_SetNext(Parent, vis_root_box); + // UI_BuildColumnEx(vis_screen_panel_box); + // } { b32 lock_screen_to_panel = TweakBool("Lock screen to panel", 0); @@ -5351,10 +5550,10 @@ void V_TickForever(WaveLaneCtx *lane) UI_BuildBoxEx(vis_screen_box); } - if (show_panels) { UI_SetNext(Flags, UI_BoxFlag_Floating); UI_SetNext(Parent, vis_root_box); + UI_SetNext(ChildLayoutAxis, V.root_panel->axis); UI_BuildBoxEx(vis_panels_box); Struct(PanelBfs) { PanelBfs *next; V_Panel *panel; }; @@ -5377,6 +5576,58 @@ void V_TickForever(WaveLaneCtx *lane) { f32 minimum_panel_pct = 0.05; + + // FIXME: Ignored panels should be skipped during sibling iteration as well + + + + //- Resize panels + for (V_Panel *panel = parent_panel->first; panel; panel = panel->next) + { + if (UI_Downs(panel->resizer_box, Button_M1)) + { + // FIXME: Don't need to store this state per-panel + panel->drag_resize_pct = panel->pct; + panel->drag_resize_pct_per_px = 1.0 / parent_contents_size_px; + } + if (UI_Held(panel->resizer_box, Button_M1)) + { + f32 drag_delta_px = UI_CursorPos().v[parent_axis] - UI_DragCursorPos().v[parent_axis]; + f32 drag_delta_pct = drag_delta_px * panel->drag_resize_pct_per_px; + + f32 old_pct = panel->pct; + f32 new_pct = MaxF32(panel->drag_resize_pct + drag_delta_pct, minimum_panel_pct); + f32 new_sibling_pct = 0; + if (panel->next) + { + f32 old_sibling_pct = panel->next->pct; + f32 desired_new_sibling_pct = panel->next->pct - (new_pct - old_pct); + new_sibling_pct = MaxF32(desired_new_sibling_pct, minimum_panel_pct); + new_pct -= (new_sibling_pct - desired_new_sibling_pct); + } + + if (panel->next) + { + panel->next->pct = new_sibling_pct; + } + panel->pct = new_pct; + } + if (UI_HotAbsolute(panel->resizer_box)) + { + if (parent_axis == Axis_X) + { + WND_SetCursor(window_frame, WND_CursorKind_HorizontalResize); + } + else + { + WND_SetCursor(window_frame, WND_CursorKind_VerticalResize); + } + } + } + + + + //- Adjust panel pcts to add to 1 { f32 pct_accum = 0; @@ -5394,12 +5645,50 @@ void V_TickForever(WaveLaneCtx *lane) { if (!V_ShouldIgnorePanel(panel)) { - panel->pct += violation / children_count; + panel->pct = panel->pct + violation / children_count; panel->pct = MaxF32(panel->pct, minimum_panel_pct); } } } + + + // //- Adjust panel pcts to add to 1 + // f32 children_pct_scale = 1; + // { + // f32 pct_accum = 0; + // for (V_Panel *panel = parent_panel->first; panel; panel = panel->next) + // { + // if (!V_ShouldIgnorePanel(panel)) + // { + // pct_accum += panel->pct; + // } + // } + // children_pct_scale = 1.0 / MinF32(pct_accum, 1); + // } + + + + // // //- Determine scale needed for sum of pcts to reach 1 + // // f32 children_pct_scale = 1; + // // { + // // f32 pct_accum = 0; + // // for (V_Panel *panel = parent_panel->first; panel; panel = panel->next) + // // { + // // if (!V_ShouldIgnorePanel(panel)) + // // { + // // pct_accum += panel->pct; + // // } + // // } + // // children_pct_scale = 1.0 / MaxF32(pct_accum, 0.0001); + // // } + + + + + + + //- Build panel boxes for (V_Panel *panel = parent_panel->first; panel; panel = panel->next) { @@ -5423,50 +5712,12 @@ void V_TickForever(WaveLaneCtx *lane) resizer_color.a *= theme.col.panel_resizer_opacity; panel_bd.a *= theme.col.panel_border_opacity; - if (UI_Downs(resizer_box, Button_M1)) - { - // FIXME: Don't need to store this state per-panel - panel->drag_resize_pct = panel->pct; - panel->drag_resize_pct_per_px = 1.0 / parent_contents_size_px; - } - if (UI_Held(resizer_box, Button_M1)) - { - f32 drag_delta_px = UI_CursorPos().v[parent_axis] - UI_DragCursorPos().v[parent_axis]; - f32 drag_delta_pct = drag_delta_px * panel->drag_resize_pct_per_px; - - f32 old_pct = panel->pct; - f32 new_pct = MaxF32(panel->drag_resize_pct + drag_delta_pct, minimum_panel_pct); - f32 new_sibling_pct = 0; - if (panel->next) - { - f32 old_sibling_pct = panel->next->pct; - f32 desired_new_sibling_pct = panel->next->pct - (new_pct - old_pct); - new_sibling_pct = MaxF32(desired_new_sibling_pct, minimum_panel_pct); - new_pct -= (new_sibling_pct - desired_new_sibling_pct); - } - - if (panel->next) - { - panel->next->pct = new_sibling_pct; - } - panel->pct = new_pct; - } - if (UI_HotAbsolute(resizer_box)) - { - if (parent_axis == Axis_X) - { - WND_SetCursor(window_frame, WND_CursorKind_HorizontalResize); - } - else - { - WND_SetCursor(window_frame, WND_CursorKind_VerticalResize); - } - } - - f32 panel_pct = panel->pct; + // f32 panel_pct = panel->pct; // UI_SetNext(AxisSize, UI_Grow(panel_pct, 1), .axis = parent_axis); - UI_SetNext(AxisSize, UI_Grow(panel_pct, 0), .axis = parent_axis); + // UI_SetNext(AxisSize, UI_Grow(panel_pct, 0), .axis = parent_axis); + UI_SetNext(AxisSize, UI_Grow(panel->pct, 0), .axis = parent_axis); + // UI_SetNext(AxisSize, UI_Grow(panel->solved_pct * children_pct_scale, 1), .axis = parent_axis); // UI_SetNext(AxisSize, UI_Px(panel_pct * parent_contents_size_px, 0), .axis = parent_axis); UI_SetNext(AxisSize, UI_Grow(1, 0), .axis = !parent_axis); UI_SetNext(ChildLayoutAxis, parent_axis); @@ -5476,7 +5727,7 @@ void V_TickForever(WaveLaneCtx *lane) // panel_bd.a = 0; // resizer_color.a = 0; - b32 is_screen_panel_box = UI_MatchKey(contents_box, vis_screen_panel_box); + b32 is_screen_panel_box = panel->flags & V_PanelFlag_Screen; if (is_screen_panel_box || panel->is_organizational) { panel_bg.a = 0; @@ -6831,7 +7082,6 @@ void V_TickForever(WaveLaneCtx *lane) G_Stats gpu_stats = G_QueryStats(); - // if (frame->show_console) if (0) { UI_Key dbg_box = UI_KeyF("Debug box"); @@ -7372,217 +7622,191 @@ void V_TickForever(WaveLaneCtx *lane) } ////////////////////////////// - //- Process vis commands + //- Process vis cmds - ProfZoneDF("Process vis cmds") - for (V_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next) { - String cmd_name = cmd_node->cmd.name; - V_CmdKind kind = V_CmdKind_nop; - for (V_CmdKind tmp_kind = V_CmdKind_nop; tmp_kind < V_CmdKind_COUNT; ++tmp_kind) + if (V_CountVisCmds(V_CmdKind_exit_program)) { - V_CmdDesc desc = V_cmd_descs[tmp_kind]; - if (MatchString(desc.name, cmd_name)) + SignalExit(0); + } + + if (V_CountVisCmds(V_CmdKind_toggle_palette)) + { + frame->palette.is_showing = !frame->palette.is_showing; + } + + if (V_CountVisCmds(V_CmdKind_zoom_in)) + { + if (frame->is_editing) { - kind = tmp_kind; - break; + frame->zooms += 1; } } - switch (kind) + if (V_CountVisCmds(V_CmdKind_zoom_out)) { - case V_CmdKind_exit_program: + if (frame->is_editing) { - SignalExit(0); - } break; + frame->zooms -= 1; + } + } - case V_CmdKind_toggle_palette: + if (V_CountVisCmds(V_CmdKind_toggle_editor)) + { + if (!prev_frame->is_editing) { - frame->palette.is_showing = !frame->palette.is_showing; - } break; + frame->is_editing = 1; + frame->edit_camera_pos = frame->camera_pos; + frame->edit_camera_zoom = frame->camera_zoom; + LogInfoF("Enabled editor"); + } + else + { + frame->is_editing = 0; + LogInfoF("Disabled editor"); + } + } - case V_CmdKind_zoom_in: + if (V_CountVisCmds(V_CmdKind_toggle_ui_debug)) + { + frame->ui_debug = !frame->ui_debug; + } + + if (V_CountVisCmds(V_CmdKind_toggle_console)) + { + frame->show_consoles = !frame->show_consoles; + } + + if (V_CountVisCmds(V_CmdKind_toggle_profiler)) + { + frame->show_profilers = !frame->show_profilers; + } + + if (V_CountVisCmds(V_CmdKind_toggle_timeline)) + { + frame->timeline.show = !frame->timeline.show; + } + + if (V_CountVisCmds(V_CmdKind_pause_timeline)) + { + frame->timeline.paused = !frame->timeline.paused; + } + + if (V_CountVisCmds(V_CmdKind_lock_timeline)) + { + frame->timeline.locked = !frame->timeline.locked; + } + + if (V_CountVisCmds(V_CmdKind_toggle_fullscreen)) + { + b32 new = !window_frame.fullscreen; + WND_PushCmd(window_frame, .kind = WND_CmdKind_SetFullscreen, .v = new); + LogInfoF("Toggled fullscreen: %F", FmtSint(new)); + } + + if (V_CountVisCmds(V_CmdKind_toggle_window_topmost)) + { + // TODO: Enable this + if (0) { - if (frame->is_editing) + b32 new = !window_frame.forced_top; + WND_PushCmd(window_frame, .kind = WND_CmdKind_SetForcedTop, .v = new); + LogInfoF("Toggled topmost: %F", FmtSint(new)); + } + } + + // if (V_CountVisCmds(V_CmdKind_reset_world)) + // if (V_CountVisCmds(V_CmdKind_spawn)) + // { + // // Reset world + // Vec2 guy_pos = VEC2(5, 0); + // if (kind == V_CmdKind_reset_world) + // { + // P_Msg *msg = P_PushMsg(P_MsgKind_ResetWorld, Zstr); + // } + // else + // { + // guy_pos = frame->world_cursor; + // } + // // Spawn guy + // { + // P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Zstr); + // P_Ent *ent = &cmd->ent; + // *ent = P_NilEnt; + // ent->key = V.guy_key; + // ent->af = AffineFromTranslation(guy_pos); + // ent->is_guy = 1; + // ent->has_weapon = 1; + // ent->exists = 1; + // } + // } + + if (V_CountVisCmds(V_CmdKind_reset_world)) + { + P_Msg *msg = P_PushMsg(P_MsgKind_ResetWorld, Zstr); + msg->affect_bots = 1; + } + + if (V_CountVisCmds(V_CmdKind_tp_player)) + { + P_Msg *msg = P_PushMsg(P_MsgKind_Teleport, Zstr); + msg->key = local_guy->key; + msg->xf.t = frame->world_cursor; + } + + if (V_CountVisCmds(V_CmdKind_spawn_tp_bot) || V_CountVisCmds(V_CmdKind_spawn_bot)) + { + P_Msg *msg = P_PushMsg(P_MsgKind_Prefab, Zstr); + msg->prefab = P_PrefabKind_Bot; + msg->key = P_RandEntKey(); + msg->xf.t = frame->world_cursor; + if (V_CountVisCmds(V_CmdKind_spawn_tp_bot)) + { + for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { - frame->zooms += 1; - } - } break; - - case V_CmdKind_zoom_out: - { - if (frame->is_editing) - { - frame->zooms -= 1; - } - } break; - - case V_CmdKind_toggle_editor: - { - if (!prev_frame->is_editing) - { - frame->is_editing = 1; - frame->edit_camera_pos = frame->camera_pos; - frame->edit_camera_zoom = frame->camera_zoom; - LogInfoF("Enabled editor"); - } - else - { - frame->is_editing = 0; - LogInfoF("Disabled editor"); - } - } break; - - case V_CmdKind_toggle_ui_debug: - { - frame->ui_debug = !frame->ui_debug; - } break; - - case V_CmdKind_toggle_console: - { - // frame->show_console = !frame->show_console; - } break; - - case V_CmdKind_toggle_profiler: - { - // frame->profiler.is_showing = !frame->profiler.is_showing; - // if (frame->profiler.is_showing) - // { - // frame->profiler.snap = 1; - // } - } break; - - case V_CmdKind_toggle_timeline: - { - frame->timeline.show = !frame->timeline.show; - } break; - - case V_CmdKind_pause_timeline: - { - frame->timeline.paused = !frame->timeline.paused; - } break; - - case V_CmdKind_lock_timeline: - { - frame->timeline.locked = !frame->timeline.locked; - } break; - - case V_CmdKind_toggle_fullscreen: - { - b32 new = !window_frame.fullscreen; - WND_PushCmd(window_frame, .kind = WND_CmdKind_SetFullscreen, .v = new); - LogInfoF("Toggled fullscreen: %F", FmtSint(new)); - } break; - - case V_CmdKind_toggle_window_topmost: - { - // TODO: Enable this - if (0) - { - b32 new = !window_frame.forced_top; - WND_PushCmd(window_frame, .kind = WND_CmdKind_SetForcedTop, .v = new); - LogInfoF("Toggled topmost: %F", FmtSint(new)); - } - } break; - - // case V_CmdKind_reset_world: - // case V_CmdKind_spawn: - // { - // // Reset world - // Vec2 guy_pos = VEC2(5, 0); - // if (kind == V_CmdKind_reset_world) - // { - // P_Msg *msg = P_PushMsg(P_MsgKind_ResetWorld, Zstr); - // } - // else - // { - // guy_pos = frame->world_cursor; - // } - // // Spawn guy - // { - // P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Zstr); - // P_Ent *ent = &cmd->ent; - // *ent = P_NilEnt; - // ent->key = V.guy_key; - // ent->af = AffineFromTranslation(guy_pos); - // ent->is_guy = 1; - // ent->has_weapon = 1; - // ent->exists = 1; - // } - // } break; - - case V_CmdKind_reset_world: - { - P_Msg *msg = P_PushMsg(P_MsgKind_ResetWorld, Zstr); - msg->affect_bots = 1; - } break; - - case V_CmdKind_tp_player: - { - P_Msg *msg = P_PushMsg(P_MsgKind_Teleport, Zstr); - msg->key = local_guy->key; - msg->xf.t = frame->world_cursor; - } break; - - case V_CmdKind_spawn_tp_bot: - case V_CmdKind_spawn_bot: - { - P_Msg *msg = P_PushMsg(P_MsgKind_Prefab, Zstr); - msg->prefab = P_PrefabKind_Bot; - msg->key = P_RandEntKey(); - msg->xf.t = frame->world_cursor; - if (kind == V_CmdKind_spawn_tp_bot) - { - for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + if (ent->is_bot) { - if (ent->is_bot) - { - msg->key = ent->key; - break; - } + msg->key = ent->key; + break; } } - } break; + } + } - case V_CmdKind_delete: + if (V_CountVisCmds(V_CmdKind_delete)) + { + if (!P_IsEntNil(hovered_ent)) { - if (!P_IsEntNil(hovered_ent)) - { - P_Msg *msg = P_PushMsg(P_MsgKind_Delete, Zstr); - msg->key = hovered_ent->key; - } - } break; + P_Msg *msg = P_PushMsg(P_MsgKind_Delete, Zstr); + msg->key = hovered_ent->key; + } + } - // case V_CmdKind_save_level: - // { - // if (frame->is_editing) - // { - // P_Msg *msg = P_PushMsg(P_MsgKind_SaveWorld, Zstr); - // } - // } break; + // if (V_CountVisCmds(V_CmdKind_save_level)) + // { + // if (frame->is_editing) + // { + // P_Msg *msg = P_PushMsg(P_MsgKind_SaveWorld, Zstr); + // } + // } - case V_CmdKind_clear_particles: - { - frame->should_clear_particles = 1; - } break; + if (V_CountVisCmds(V_CmdKind_clear_particles)) + { + frame->should_clear_particles = 1; + } - case V_CmdKind_clear_bullets: - { - P_Msg *msg = P_PushMsg(P_MsgKind_ClearBullets, Zstr); - } break; + if (V_CountVisCmds(V_CmdKind_clear_bullets)) + { + P_Msg *msg = P_PushMsg(P_MsgKind_ClearBullets, Zstr); + } - case V_CmdKind_test: - { - // V_PushNotif(Lit("Hello!!!")); - P_Msg *chat_msg = P_PushMsg(P_MsgKind_Chat, Lit("Hello!!!")); - } break; + if (V_CountVisCmds(V_CmdKind_test)) + { + // V_PushNotif(Lit("Hello!!!")); + P_Msg *chat_msg = P_PushMsg(P_MsgKind_Chat, Lit("Hello!!!")); } } - - - - ////////////////////////////// //- Begin gpu frame diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 67db7280..c69ecd21 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -317,9 +317,10 @@ Enum(V_PanelFlag) { V_PanelFlag_None = 0, V_PanelFlag_Ignore = (1 << 0), - V_PanelFlag_Spawn = (1 << 1), - V_PanelFlag_Profiler = (1 << 2), - V_PanelFlag_Console = (1 << 3), + V_PanelFlag_Screen = (1 << 1), + V_PanelFlag_Spawn = (1 << 2), + V_PanelFlag_Profiler = (1 << 3), + V_PanelFlag_Console = (1 << 4), }; Struct(V_Panel) @@ -426,9 +427,7 @@ Struct(V_Frame) String window_restore; // Vis commands - i64 cmds_count; - V_CmdNode *first_cmd_node; - V_CmdNode *last_cmd_node; + i64 cmd_counts_by_kind[V_CmdKind_COUNT]; // Unflattened emitters list V_EmitterNode *first_emitter_node; @@ -452,14 +451,15 @@ Struct(V_Ctx) - P_PublicState public_state; - - - - + P_NetVarState nvars; V_Panel *root_panel; + i64 queued_cmds_count; + V_CmdNode *first_queued_cmd_node; + V_CmdNode *last_queued_cmd_node; + V_CmdNode *first_free_cmd_node; + @@ -504,6 +504,7 @@ void V_Shutdown(void); V_Frame *V_CurrentFrame(void); V_Frame *V_PrevFrame(void); V_Cmd *V_PushVisCmd(String name); +i64 V_CountVisCmds(V_CmdKind kind); String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey); void V_PushParticles(V_Emitter src); diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index e619fed3..a04b529d 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -9,11 +9,12 @@ f32 V_RandFromPos(Vec3 pos) return rand; } -Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, u32 density) +Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, f32 alive_seconds, u32 density) { Vec4 result = 0; u64 seed = MixU64(V_ParticleColorBasis ^ particle_idx); f32 rand_color = Norm16(seed >> 0); + f32 rand_lifetime = Norm16(seed >> 16); result = desc.base_color; @@ -48,6 +49,36 @@ Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, u32 density) result.rgb = result.rgb + (rand_color - 0.5) * 0.05; + if (desc.lifetime_min < Inf && alive_seconds > 0) + { + f32 lifetime = desc.lifetime_min + (desc.lifetime_max - desc.lifetime_min) * rand_lifetime; + f32 lifetime_complete = saturate(alive_seconds / lifetime); + + f32 v = lifetime_complete * lifetime_complete; + + // result.a *= 1.0 - lifetime_complete; + result.a *= 1.0 - v; + // result.rgb *= 1.0 - lifetime_complete; + } + + + + + + // if (desc.lifetime < Inf && alive_seconds > 0) + // { + // // result.a *= desc.lifetime / alive_seconds; + + // f32 lifetime_complete = alive_seconds / desc.lifetime; + + // result.a *= lerp(1, 0, saturate(lifetime_complete)); + + // // result.a *= 0; + // // result.a *= 1.0 - saturate(alive_seconds / desc.lifetime); + // } + + + return result; } @@ -103,6 +134,7 @@ ComputeShader(V_PrepareCellsCS) RWTexture2D dry_stains = G_Deref(frame.dry_stains, RWTexture2D); RWTexture2D drynesses = G_Deref(frame.drynesses, RWTexture2D); RWTexture2D occluders = G_Deref(frame.occluders, RWTexture2D); + StructuredBuffer particles = G_Deref(frame.particles, StructuredBuffer); Vec2 cell_pos = SV_DispatchThreadID + 0.5; if (all(cell_pos < P_WorldCellsDims)) @@ -137,8 +169,9 @@ ComputeShader(V_PrepareCellsCS) V_ParticleDesc desc = V_DescFromParticleKind(particle_kind); u32 density = densities[cell_pos]; u32 particle_idx = packed & ((1 << 24) - 1); + f32 alive_seconds = 0; - Vec4 base_color = V_ColorFromParticle(desc, particle_idx, density); + Vec4 base_color = V_ColorFromParticle(desc, particle_idx, 0, density); Vec4 dry_color = base_color * desc.dry_factor; base_color.rgb *= base_color.a; @@ -444,7 +477,7 @@ ComputeShader(V_SimParticlesCS) particle = (V_Particle)0; particle.kind = emitter.kind; - particle.life = 0; + particle.alive_seconds = 0; particle.pos = lerp(emitter.pos.p0, emitter.pos.p1, rand_offset); particle.velocity = Vec2(cos(initial_angle), sin(initial_angle)) * initial_speed; } @@ -464,7 +497,7 @@ ComputeShader(V_SimParticlesCS) StaticAssert(V_ParticlesCap <= (1 << 24)); // particle idx must fit in 24 bits StaticAssert(V_ParticleKind_COUNT <= 0x7F); // particle kind must fit in 7 bits - if (particle.life == 0) + if (particle.alive_seconds == 0) { Vec2 cell_pos = mul(frame.af.world_to_cell, Vec3(particle.pos, 1)); if (IsInside(cell_pos, P_WorldCellsDims)) @@ -663,13 +696,14 @@ ComputeShader(V_SimParticlesCS) } // f32 falloff = saturate(lerp(1, 2, rand_falloff) * frame.dt); - f32 falloff = saturate(lerp(10, 20, rand_falloff) * frame.dt); + // f32 falloff = saturate(lerp(10, 20, rand_falloff) * frame.dt); + f32 falloff = 0; particle.velocity *= 1.0f - falloff; particle.pos = p0 + (p1 - p0) * t; } - particle.life += frame.dt; + particle.alive_seconds += frame.dt; } ////////////////////////////// @@ -859,8 +893,20 @@ ComputeShader(V_CompositeCS) Vec4 albedo_tex_color = albedo_tex[screen_pos]; + + + + + + + + + + + + ////////////////////////////// - //- Particles + //- Particles / stains // FIXME: Stain Vec4 stain_color = 0; @@ -878,14 +924,17 @@ ComputeShader(V_CompositeCS) { Texture2D cells = G_Deref(frame.particle_cells[layer], Texture2D); Texture2D densities = G_Deref(frame.particle_densities[layer], Texture2D); + u32 packed = cells[cell_pos]; V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); if (particle_kind != V_ParticleKind_None) { + u32 particle_idx = packed & ((1 << 24) - 1); + V_Particle particle = particles[particle_idx]; + u32 density = densities[cell_pos]; V_ParticleDesc desc = V_DescFromParticleKind(particle_kind); - u32 particle_idx = packed & ((1 << 24) - 1); - Vec4 cell_color = V_ColorFromParticle(desc, particle_idx, density); + Vec4 cell_color = V_ColorFromParticle(desc, particle_idx, particle.alive_seconds, density); cell_color.rgb *= cell_color.a; if (layer == V_ParticleLayer_Ground) @@ -907,6 +956,64 @@ ComputeShader(V_CompositeCS) stain_color *= 0.5; } + + + + + // ////////////////////////////// + // //- Particles / stains + + // // FIXME: Stain + // Vec4 stain_color = 0; + // { + // Vec4 wet_stain = stains[cell_pos]; + // Vec4 dry_stain = dry_stains[cell_pos]; + // f32 dryness = drynesses[cell_pos]; + // stain_color = max(lerp(wet_stain, dry_stain, dryness), 0); + // } + + // Vec4 ground_particle_color = 0; + // Vec4 air_particle_color = 0; + + // for (V_ParticleLayer layer = (V_ParticleLayer)0; layer < V_ParticleLayer_COUNT; layer += (V_ParticleLayer)1) + // { + // Texture2D cells = G_Deref(frame.particle_cells[layer], Texture2D); + // Texture2D densities = G_Deref(frame.particle_densities[layer], Texture2D); + // u32 packed = cells[cell_pos]; + // V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); + // if (particle_kind != V_ParticleKind_None) + // { + // u32 density = densities[cell_pos]; + // V_ParticleDesc desc = V_DescFromParticleKind(particle_kind); + // u32 particle_idx = packed & ((1 << 24) - 1); + // Vec4 cell_color = V_ColorFromParticle(desc, particle_idx, density); + // cell_color.rgb *= cell_color.a; + + // if (layer == V_ParticleLayer_Ground) + // { + // ground_particle_color = BlendPremul(cell_color, ground_particle_color); + // } + // else + // { + // air_particle_color = BlendPremul(cell_color, air_particle_color); + // } + // } + // } + + // // Darken wall particles / stains + // if (tile == P_TileKind_Wall) + // { + // ground_particle_color *= 0.5; + // air_particle_color *= 0.5; + // stain_color *= 0.5; + // } + + + + + + + ////////////////////////////// //- Compose world diff --git a/src/pp/pp_vis/pp_vis_gpu.gh b/src/pp/pp_vis/pp_vis_gpu.gh index 6e949162..40124e87 100644 --- a/src/pp/pp_vis/pp_vis_gpu.gh +++ b/src/pp/pp_vis/pp_vis_gpu.gh @@ -45,7 +45,7 @@ Struct(V_DVertPSOutput) //~ Helpers f32 V_RandFromPos(Vec3 pos); -Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, u32 density); +Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, f32 alive_seconds, u32 density); //////////////////////////////////////////////////////////// //~ Shaders diff --git a/src/pp/pp_vis/pp_vis_shared.cg b/src/pp/pp_vis/pp_vis_shared.cg index 876e33fa..83589632 100644 --- a/src/pp/pp_vis/pp_vis_shared.cg +++ b/src/pp/pp_vis/pp_vis_shared.cg @@ -4,17 +4,18 @@ V_ParticleDesc V_DescFromParticleKind(V_ParticleKind kind) { V_ParticleDesc descs[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, prune_speed_threshold, base_color, dry_factor) \ - { \ - V_ParticleKind_##name, \ - flags, \ - layer, \ - stain_rate, \ - pen_rate, \ - lifetime, \ - prune_speed_threshold, \ - LinearFromSrgb(base_color), \ - LinearFromSrgb(dry_factor) \ + #define X(name, flags, layer, stain_rate, pen_rate, lifetime_min, lifetime_max, prune_speed_threshold, base_color, dry_factor) \ + { \ + V_ParticleKind_##name, \ + flags, \ + layer, \ + stain_rate, \ + pen_rate, \ + lifetime_min, \ + lifetime_max, \ + prune_speed_threshold, \ + LinearFromSrgb(base_color), \ + LinearFromSrgb(dry_factor) \ }, V_ParticlesXList(X) #undef X diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index 5aab052e..bee2edb7 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -50,7 +50,7 @@ Enum(V_ParticleLayer) /* Flags */ V_ParticleFlag_None, \ /* Layer */ V_ParticleLayer_Ground, \ /* Stain rate, pen chance */ 30, 0, \ - /* Lifetime */ Inf, \ + /* Lifetime */ Inf, Inf, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(0, 0, 0, 0), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ @@ -62,7 +62,7 @@ Enum(V_ParticleLayer) /* Flags */ V_ParticleFlag_NoReflect | V_ParticleFlag_StainWhenPruned, \ /* Layer */ V_ParticleLayer_Ground, \ /* Stain rate, pen chance */ 100, 0.25, \ - /* Lifetime */ Inf, \ + /* Lifetime */ Inf, Inf, \ /* Prune speed threshold */ 0.5, \ /* Base color */ VEC4(0.6, 0.1, 0.1, 0.05), \ /* Dry color factor */ VEC4(0.4, 0.4, 0.4, 1) \ @@ -72,7 +72,7 @@ Enum(V_ParticleLayer) /* Flags */ V_ParticleFlag_StainWhenPruned, \ /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 30, 0, \ - /* Lifetime */ Inf, \ + /* Lifetime */ Inf, Inf, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(0.5, 0.1, 0.1, 0.8), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ @@ -82,7 +82,7 @@ Enum(V_ParticleLayer) /* Flags */ V_ParticleFlag_StainWhenPruned, \ /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ - /* Lifetime */ Inf, \ + /* Lifetime */ Inf, Inf, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(0.4, 0.3, 0.2, 1), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ @@ -92,7 +92,17 @@ Enum(V_ParticleLayer) /* Flags */ V_ParticleFlag_StainWhenPruned, \ /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ - /* Lifetime */ Inf, \ + /* Lifetime */ Inf, Inf, \ + /* Prune speed threshold */ 0.1, \ + /* Base color */ VEC4(2, 0.5, 0, 1), \ + /* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \ + ) \ + X( \ + /* Name */ Spark, \ + /* Flags */ V_ParticleFlag_StainWhenPruned, \ + /* Layer */ V_ParticleLayer_Mid, \ + /* Stain rate, pen chance */ 0, 0, \ + /* Lifetime */ 0.2, 5, \ /* Prune speed threshold */ 0.1, \ /* Base color */ VEC4(2, 0.5, 0, 1), \ /* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \ @@ -104,7 +114,7 @@ Enum(V_ParticleLayer) /* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_GasBlend, \ /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ - /* Lifetime */ 0.075, \ + /* Lifetime */ 0.075, 0.075, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(0.8, 0.6, 0.2, 0.25), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ @@ -114,10 +124,20 @@ Enum(V_ParticleLayer) /* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_GasBlend, \ /* Layer */ V_ParticleLayer_Air, \ /* Stain rate, pen chance */ 0, 0, \ - /* Lifetime */ Inf, \ + /* Lifetime */ Inf, Inf, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(0.25, 0.25, 0.25, 0.75), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ + ) \ + X( \ + /* Name */ Flash, \ + /* Flags */ V_ParticleFlag_None, \ + /* Layer */ V_ParticleLayer_Air, \ + /* Stain rate, pen chance */ 0, 0, \ + /* Lifetime */ 0.0, .05, \ + /* Prune speed threshold */ 0, \ + /* Base color */ VEC4(10, 3.5, 0, 1), \ + /* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \ ) \ \ /* Test particles */ \ @@ -126,7 +146,7 @@ Enum(V_ParticleLayer) /* Flags */ V_ParticleFlag_None, \ /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ - /* Lifetime */ Inf, \ + /* Lifetime */ Inf, Inf, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(1, 1, 0, 1), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ @@ -159,7 +179,7 @@ Struct(V_Particle) i32 kind; // If >= 0, then this maps to V_ParticleKind. Otherwise it represent a particle to be initialized using emitter at index [abs(kind) - 1] u32 origin_occluder; u32 prev_occluder; // TODO: Remove this - f32 life; + f32 alive_seconds; f32 stain_accum; u32 cells_count; Vec2 pos; @@ -173,7 +193,8 @@ Struct(V_ParticleDesc) V_ParticleLayer layer; f32 stain_rate; f32 pen_rate; - f32 lifetime; + f32 lifetime_min; + f32 lifetime_max; f32 prune_speed_threshold; Vec4 base_color; Vec4 dry_factor; @@ -314,6 +335,8 @@ Struct(V_SharedFrame) b32 is_looking; b32 is_moving; + b32 show_consoles; + b32 show_profilers; b32 is_editing; b32 ui_debug; b32 is_selecting; @@ -337,6 +360,7 @@ Struct(V_SharedFrame) Vec2 world_selection_start; Vec2 edit_camera_pos; f32 edit_camera_zoom; + f32 camera_shake; //- Camera diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index ac96855a..3ee5984d 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -321,8 +321,8 @@ void UI_PushDefaults(void) case UI_StyleKind_HotRate: { desc.style.HotRate = 15; } break; case UI_StyleKind_HoveredRate: { desc.style.HoveredRate = 15; } break; case UI_StyleKind_ExistsRate: { desc.style.ExistsRate = 30; } break; - case UI_StyleKind_MiscRate: { desc.style.MiscRate = Inf; } break; - case UI_StyleKind_DimsRate: { desc.style.DimsRate = VEC2(Inf, Inf); } break; + case UI_StyleKind_MiscRate: { desc.style.MiscRate = 1000; } break; + case UI_StyleKind_DimsRate: { desc.style.DimsRate = VEC2(1000, 1000); } break; }; UI_PushStyle(desc); } @@ -862,6 +862,30 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags) f32 target_exists = feedback->exists_absolute ? upper_target : lower_target; f64 target_misc = box->desc.misc; + // f32 delta_active_rate = box->desc.active_rate * frame->dt; + // f32 delta_hot_rate = box->desc.hot_rate * frame->dt; + // f32 delta_hovered_rate = box->desc.hovered_rate * frame->dt; + // f32 delta_exists_rate = box->desc.exists_rate * frame->dt; + // f32 delta_misc_rate = box->desc.misc_rate * frame->dt; + // // delta_active_rate = IsNan(delta_active_rate) ? 1 : delta_active_rate; + // // delta_hot_rate = IsNan(delta_hot_rate) ? 1 : delta_hot_rate; + // // delta_hovered_rate = IsNan(delta_hovered_rate) ? 1 : delta_hovered_rate; + // // delta_exists_rate = IsNan(delta_exists_rate) ? 1 : delta_exists_rate; + // // delta_misc_rate = IsNan(delta_misc_rate) ? 1 : delta_misc_rate; + + // feedback->active_smooth = SaturateF32(LerpF32(feedback->active_smooth, target_active, delta_active_rate)); + // feedback->hot_smooth = SaturateF32(LerpF32(feedback->hot_smooth, target_hot, delta_hot_rate)); + // feedback->hovered_smooth = SaturateF32(LerpF32(feedback->hovered_smooth, target_hovered, delta_hovered_rate)); + // feedback->exists_smooth = SaturateF32(LerpF32(feedback->exists_smooth, target_exists, delta_exists_rate)); + // feedback->misc_smooth = SaturateF64(LerpF64(feedback->misc_smooth, target_misc, delta_misc_rate)); + + + + + + + + feedback->active_smooth = SaturateF32(LerpF32(feedback->active_smooth, target_active, box->desc.active_rate * frame->dt)); feedback->hot_smooth = SaturateF32(LerpF32(feedback->hot_smooth, target_hot, box->desc.hot_rate * frame->dt)); feedback->hovered_smooth = SaturateF32(LerpF32(feedback->hovered_smooth, target_hovered, box->desc.hovered_rate * frame->dt)); @@ -869,6 +893,9 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags) feedback->misc_smooth = SaturateF64(LerpF64(feedback->misc_smooth, target_misc, box->desc.misc_rate * frame->dt)); + + + // f32 active_blend_rate = (15 * frame->dt); // f32 hot_blend_rate = (15 * frame->dt); // f32 hovered_blend_rate = (15 * frame->dt);