fp: Various camera fixes for varying window sizes
This commit is contained in:
parent
9b1e40a368
commit
dca59a1241
2
External/tely
vendored
2
External/tely
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 9ec8c2953c3726276c44d7ab58dba3a938da6f97
|
Subproject commit 29843741bf51c8ed38af467cff8b781a912f15a7
|
@ -475,6 +475,7 @@ static void FP_PlayReset(FP_Game *game, TELY_Platform *platform)
|
|||||||
// NOTE: Camera ================================================================================
|
// NOTE: Camera ================================================================================
|
||||||
play->camera.world_pos = base_mid_p - Dqn_V2_InitV2I(platform->core.window_size * .5f);
|
play->camera.world_pos = base_mid_p - Dqn_V2_InitV2I(platform->core.window_size * .5f);
|
||||||
play->camera.scale = Dqn_V2_InitNx1(1);
|
play->camera.scale = Dqn_V2_InitNx1(1);
|
||||||
|
play->camera.size = Dqn_V2_InitNx2(1826, 1046);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DQN_OS_WIN32)
|
#if defined(DQN_OS_WIN32)
|
||||||
@ -1444,6 +1445,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
|||||||
{
|
{
|
||||||
Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate);
|
Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate);
|
||||||
|
|
||||||
|
FP_GameCameraM2x3 const camera_xforms = FP_Game_CameraModelViewM2x3(game->play.camera);
|
||||||
game->play.update_counter++;
|
game->play.update_counter++;
|
||||||
game->play.clock_ms = DQN_CAST(uint64_t)(platform->input.timer_s * 1000.f);
|
game->play.clock_ms = DQN_CAST(uint64_t)(platform->input.timer_s * 1000.f);
|
||||||
Dqn_ProfilerZone update_zone = Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8("FP_Update: Entity loop"), FP_ProfileZone_FPUpdate_EntityLoop);
|
Dqn_ProfilerZone update_zone = Dqn_Profiler_BeginZoneWithIndex(DQN_STRING8("FP_Update: Entity loop"), FP_ProfileZone_FPUpdate_EntityLoop);
|
||||||
@ -1991,9 +1993,10 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
|||||||
|
|
||||||
// NOTE: Move entity by mouse ==============================================================
|
// NOTE: Move entity by mouse ==============================================================
|
||||||
if (game->play.active_entity == entity->handle && entity->flags & FP_GameEntityFlag_MoveByMouse) {
|
if (game->play.active_entity == entity->handle && entity->flags & FP_GameEntityFlag_MoveByMouse) {
|
||||||
|
Dqn_V2 mouse_p_delta = input->mouse_p_delta * (Dqn_V2_One / game->play.camera.scale);
|
||||||
entity->velocity = {};
|
entity->velocity = {};
|
||||||
acceleration_meters_per_s = {};
|
acceleration_meters_per_s = {};
|
||||||
entity->local_pos += input->mouse_p_delta;
|
entity->local_pos += mouse_p_delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game->play.clicked_entity == entity->handle) {
|
if (game->play.clicked_entity == entity->handle) {
|
||||||
@ -2002,8 +2005,10 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
|||||||
game->play.in_game_menu = DQN_CAST(FP_GameInGameMenu)(DQN_CAST(uint32_t)game->play.in_game_menu ^ FP_GameInGameMenu_Build);
|
game->play.in_game_menu = DQN_CAST(FP_GameInGameMenu)(DQN_CAST(uint32_t)game->play.in_game_menu ^ FP_GameInGameMenu_Build);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity->flags & FP_GameEntityFlag_CameraTracking)
|
if (entity->flags & FP_GameEntityFlag_CameraTracking) {
|
||||||
game->play.camera.world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle) - Dqn_V2_InitV2I(platform->core.window_size) * .5f;
|
FP_GameCamera *camera = &game->play.camera;
|
||||||
|
camera->world_pos = FP_Game_CalcEntityWorldPos(game, entity->handle) * camera->scale;
|
||||||
|
}
|
||||||
|
|
||||||
FP_GamePlaceableBuilding placeable_building = PLACEABLE_BUILDINGS[game->play.build_mode_building_index];
|
FP_GamePlaceableBuilding placeable_building = PLACEABLE_BUILDINGS[game->play.build_mode_building_index];
|
||||||
game->play.build_mode_can_place_building = false;
|
game->play.build_mode_can_place_building = false;
|
||||||
@ -2160,7 +2165,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Mob spawner =======================================================================
|
// NOTE: Mob spawner =======================================================================
|
||||||
if (entity->type == FP_EntityType_MobSpawner) {
|
if (entity->type == FP_EntityType_MobSpawner && 0) {
|
||||||
// NOTE: Flush any spawn entities that are dead
|
// NOTE: Flush any spawn entities that are dead
|
||||||
for (FP_SentinelListLink<FP_GameEntityHandle> *link = nullptr; FP_SentinelList_Iterate<FP_GameEntityHandle>(&entity->spawn_list, &link); ) {
|
for (FP_SentinelListLink<FP_GameEntityHandle> *link = nullptr; FP_SentinelList_Iterate<FP_GameEntityHandle>(&entity->spawn_list, &link); ) {
|
||||||
FP_GameEntity *spawned_entity = FP_Game_GetEntity(game, link->data);
|
FP_GameEntity *spawned_entity = FP_Game_GetEntity(game, link->data);
|
||||||
@ -2298,14 +2303,21 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!FP_Game_IsNilEntityHandle(game, game->play.clicked_entity)) {
|
if (!FP_Game_IsNilEntityHandle(game, game->play.clicked_entity)) {
|
||||||
Dqn_V2 target_camera_size = Dqn_V2_InitNx2(1826, 1046);
|
|
||||||
Dqn_V2 window_size = Dqn_V2_InitV2I(platform->core.window_size);
|
Dqn_V2 window_size = Dqn_V2_InitV2I(platform->core.window_size);
|
||||||
FP_GamePlay *play = &game->play;
|
FP_GamePlay *play = &game->play;
|
||||||
play->camera.scale = window_size / target_camera_size;
|
|
||||||
play->camera.world_pos.x = DQN_MIN(play->camera.world_pos.x, play->map->local_hit_box_size.w * +0.5f - target_camera_size.w);
|
FP_GameCamera *camera = &play->camera;
|
||||||
play->camera.world_pos.x = DQN_MAX(play->camera.world_pos.x, play->map->local_hit_box_size.w * -0.5f);
|
camera->scale = window_size / camera->size;
|
||||||
play->camera.world_pos.y = DQN_MAX(play->camera.world_pos.y, play->map->local_hit_box_size.h * -0.5f);
|
Dqn_V2 camera_size_screen = camera->size * camera->scale;
|
||||||
play->camera.world_pos.y = DQN_MIN(play->camera.world_pos.y, play->map->local_hit_box_size.h * +0.5f - target_camera_size.h);
|
|
||||||
|
Dqn_V2 map_world_size = play->map->local_hit_box_size;
|
||||||
|
Dqn_V2 map_screen_size = map_world_size * camera->scale;
|
||||||
|
Dqn_V2 half_map_screen_size = map_screen_size * .5f;
|
||||||
|
|
||||||
|
camera->world_pos.x = DQN_MIN(camera->world_pos.x, half_map_screen_size.w - (camera_size_screen.w * .5f));
|
||||||
|
camera->world_pos.x = DQN_MAX(camera->world_pos.x, -half_map_screen_size.w + (camera_size_screen.w * .5f));
|
||||||
|
camera->world_pos.y = DQN_MAX(camera->world_pos.y, -half_map_screen_size.h + (camera_size_screen.h * .5f));
|
||||||
|
camera->world_pos.y = DQN_MIN(camera->world_pos.y, half_map_screen_size.h - (camera_size_screen.h * .5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
Dqn_Profiler_EndZone(update_zone);
|
Dqn_Profiler_EndZone(update_zone);
|
||||||
@ -2325,9 +2337,9 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
|
|||||||
TELY_RFui_PushFont(rfui, game->jetbrains_mono_font);
|
TELY_RFui_PushFont(rfui, game->jetbrains_mono_font);
|
||||||
TELY_RFui_PushLabelColourV4(rfui, TELY_COLOUR_BLACK_MIDNIGHT_V4);
|
TELY_RFui_PushLabelColourV4(rfui, TELY_COLOUR_BLACK_MIDNIGHT_V4);
|
||||||
|
|
||||||
Dqn_M2x3 model_view = FP_Game_CameraModelViewM2x3(game->play.camera, platform);
|
FP_GameCameraM2x3 camera_xforms = FP_Game_CameraModelViewM2x3(game->play.camera);
|
||||||
TELY_Render_PushTransform(renderer, model_view);
|
TELY_Render_PushTransform(renderer, camera_xforms.model_view);
|
||||||
Dqn_V2 world_mouse_p = input->mouse_p + game->play.camera.world_pos;
|
Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(camera_xforms.view_model, input->mouse_p);
|
||||||
|
|
||||||
// NOTE: Draw tiles ============================================================================
|
// NOTE: Draw tiles ============================================================================
|
||||||
Dqn_usize tile_count_x = DQN_CAST(Dqn_usize)(platform->core.window_size.w / game->play.tile_size);
|
Dqn_usize tile_count_x = DQN_CAST(Dqn_usize)(platform->core.window_size.w / game->play.tile_size);
|
||||||
@ -3446,8 +3458,8 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (0) {
|
||||||
next_y += TELY_Asset_GetFont(assets, TELY_RFui_ActiveFont(rfui))->pixel_height;
|
next_y += TELY_Asset_GetFont(assets, TELY_RFui_ActiveFont(rfui))->pixel_height;
|
||||||
{
|
|
||||||
TELY_RFuiResult bar = TELY_RFui_Column(rfui, DQN_STRING8("Memory bar"));
|
TELY_RFuiResult bar = TELY_RFui_Column(rfui, DQN_STRING8("Memory bar"));
|
||||||
bar.widget->semantic_position[TELY_RFuiAxis_X].kind = TELY_RFuiPositionKind_Absolute;
|
bar.widget->semantic_position[TELY_RFuiAxis_X].kind = TELY_RFuiPositionKind_Absolute;
|
||||||
bar.widget->semantic_position[TELY_RFuiAxis_X].value = 10.f;
|
bar.widget->semantic_position[TELY_RFuiAxis_X].value = 10.f;
|
||||||
@ -3498,6 +3510,7 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer,
|
|||||||
DQN_DEFER { TELY_RFui_PopParent(rfui); };
|
DQN_DEFER { TELY_RFui_PopParent(rfui); };
|
||||||
|
|
||||||
TELY_RFui_TextF(rfui, "Camera: %.1f, %.1f", game->play.camera.world_pos.x, game->play.camera.world_pos.y);
|
TELY_RFui_TextF(rfui, "Camera: %.1f, %.1f", game->play.camera.world_pos.x, game->play.camera.world_pos.y);
|
||||||
|
TELY_RFui_TextF(rfui, "Mouse: %.1f, %.1f", input->mouse_p.x, input->mouse_p.y);
|
||||||
|
|
||||||
// TODO(doyle): On emscripten we need to use Dqn_OS_PerfCounterNow() however those
|
// TODO(doyle): On emscripten we need to use Dqn_OS_PerfCounterNow() however those
|
||||||
// require OS functions which need to be exposed into the platform layer.
|
// require OS functions which need to be exposed into the platform layer.
|
||||||
@ -3656,7 +3669,8 @@ void TELY_DLL_FrameUpdate(void *user_data)
|
|||||||
if (game->play.prev_active_entity.id)
|
if (game->play.prev_active_entity.id)
|
||||||
game->play.active_entity = game->play.prev_active_entity;
|
game->play.active_entity = game->play.prev_active_entity;
|
||||||
} else {
|
} else {
|
||||||
Dqn_V2 world_mouse_p = input->mouse_p + game->play.camera.world_pos;
|
FP_GameCameraM2x3 const camera_xforms = FP_Game_CameraModelViewM2x3(game->play.camera);
|
||||||
|
Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(camera_xforms.view_model, input->mouse_p);
|
||||||
for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->play.root_entity); ) {
|
for (FP_GameEntityIterator it = {}; FP_Game_DFSPreOrderWalkEntityTree(game, &it, game->play.root_entity); ) {
|
||||||
FP_GameEntity *entity = it.entity;
|
FP_GameEntity *entity = it.entity;
|
||||||
if (entity->local_hit_box_size.x <= 0 || entity->local_hit_box_size.y <= 0)
|
if (entity->local_hit_box_size.x <= 0 || entity->local_hit_box_size.y <= 0)
|
||||||
|
@ -30,17 +30,29 @@ struct FP_GameCameraM2x3
|
|||||||
Dqn_M2x3 view_model;
|
Dqn_M2x3 view_model;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Dqn_M2x3 FP_Game_CameraModelViewM2x3(FP_GameCamera camera, TELY_Platform *platform)
|
static FP_GameCameraM2x3 FP_Game_CameraModelViewM2x3(FP_GameCamera camera)
|
||||||
{
|
{
|
||||||
Dqn_M2x3 result = Dqn_M2x3_Identity();
|
FP_GameCameraM2x3 result = {};
|
||||||
if (platform) {
|
result.model_view = Dqn_M2x3_Identity();
|
||||||
Dqn_V2 center_offset = Dqn_V2_InitV2I(platform->core.window_size) * .5f;
|
result.view_model = Dqn_M2x3_Identity();
|
||||||
Dqn_V2 rotate_origin = -camera.world_pos - center_offset;
|
|
||||||
result = Dqn_M2x3_Mul(result, Dqn_M2x3_Translate(rotate_origin));
|
Dqn_V2 center_offset = camera.size * .5f;
|
||||||
result = Dqn_M2x3_Mul(result, Dqn_M2x3_Rotate(camera.rotate_rads));
|
Dqn_V2 rotate_origin = -camera.world_pos;
|
||||||
result = Dqn_M2x3_Mul(result, Dqn_M2x3_Scale(camera.scale));
|
result.model_view = Dqn_M2x3_Mul(result.model_view, Dqn_M2x3_Translate(rotate_origin));
|
||||||
result = Dqn_M2x3_Mul(result, Dqn_M2x3_Translate(center_offset));
|
result.model_view = Dqn_M2x3_Mul(result.model_view, Dqn_M2x3_Rotate(camera.rotate_rads));
|
||||||
}
|
result.model_view = Dqn_M2x3_Mul(result.model_view, Dqn_M2x3_Scale(camera.scale));
|
||||||
|
result.model_view = Dqn_M2x3_Mul(result.model_view, Dqn_M2x3_Translate(center_offset));
|
||||||
|
|
||||||
|
Dqn_V2 inverse_scale = Dqn_V2_InitNx1(1) / camera.scale;
|
||||||
|
result.view_model = Dqn_M2x3_Mul(result.view_model, Dqn_M2x3_Translate(-center_offset));
|
||||||
|
result.view_model = Dqn_M2x3_Mul(result.view_model, Dqn_M2x3_Scale(inverse_scale));
|
||||||
|
result.view_model = Dqn_M2x3_Mul(result.view_model, Dqn_M2x3_Rotate(-camera.rotate_rads));
|
||||||
|
result.view_model = Dqn_M2x3_Mul(result.view_model, Dqn_M2x3_Translate(-rotate_origin));
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
Dqn_M2x3 identity = Dqn_M2x3_Mul(result.model_view, result.view_model);
|
||||||
|
DQN_ASSERT(identity == Dqn_M2x3_Identity());
|
||||||
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +255,7 @@ struct FP_GameEntityIterator
|
|||||||
|
|
||||||
struct FP_GameCamera
|
struct FP_GameCamera
|
||||||
{
|
{
|
||||||
|
Dqn_V2 size;
|
||||||
Dqn_V2 world_pos;
|
Dqn_V2 world_pos;
|
||||||
Dqn_f32 rotate_rads;
|
Dqn_f32 rotate_rads;
|
||||||
Dqn_V2 scale;
|
Dqn_V2 scale;
|
||||||
|
Loading…
Reference in New Issue
Block a user