Browse Source

Improve subframe interpolation. Remove tweens from scene objects. Clean up scene object classes

master
C. J. Howard 1 year ago
parent
commit
8d0610649d
71 changed files with 1089 additions and 1785 deletions
  1. +0
    -1
      CMakeLists.txt
  2. +0
    -1
      src/engine/animation/screen-transition.cpp
  3. +2
    -2
      src/engine/physics/kinematics/constraints/spring-constraint.cpp
  4. +18
    -4
      src/engine/physics/kinematics/rigid-body.cpp
  5. +109
    -16
      src/engine/physics/kinematics/rigid-body.hpp
  6. +0
    -24
      src/engine/render/context.hpp
  7. +26
    -22
      src/engine/render/passes/material-pass.cpp
  8. +7
    -13
      src/engine/render/passes/shadow-map-pass.cpp
  9. +13
    -15
      src/engine/render/passes/sky-pass.cpp
  10. +1
    -10
      src/engine/render/renderer.cpp
  11. +4
    -3
      src/engine/render/stages/culling-stage.cpp
  12. +23
    -0
      src/engine/scene/ambient-light.hpp
  13. +42
    -0
      src/engine/scene/billboard-type.hpp
  14. +64
    -46
      src/engine/scene/billboard.cpp
  15. +37
    -43
      src/engine/scene/billboard.hpp
  16. +44
    -118
      src/engine/scene/camera.cpp
  17. +171
    -225
      src/engine/scene/camera.hpp
  18. +8
    -17
      src/engine/scene/collection.cpp
  19. +7
    -12
      src/engine/scene/collection.hpp
  20. +12
    -28
      src/engine/scene/directional-light.cpp
  21. +41
    -28
      src/engine/scene/directional-light.hpp
  22. +19
    -9
      src/engine/scene/light-type.hpp
  23. +1
    -29
      src/engine/scene/light.cpp
  24. +4
    -84
      src/engine/scene/light.hpp
  25. +0
    -80
      src/engine/scene/lod-group.cpp
  26. +0
    -131
      src/engine/scene/lod-group.hpp
  27. +2
    -25
      src/engine/scene/object.cpp
  28. +24
    -54
      src/engine/scene/object.hpp
  29. +0
    -14
      src/engine/scene/point-light.cpp
  30. +24
    -15
      src/engine/scene/point-light.hpp
  31. +1
    -14
      src/engine/scene/scene.hpp
  32. +4
    -35
      src/engine/scene/spot-light.cpp
  33. +38
    -46
      src/engine/scene/spot-light.hpp
  34. +29
    -32
      src/engine/scene/static-mesh.cpp
  35. +10
    -26
      src/engine/scene/static-mesh.hpp
  36. +66
    -92
      src/engine/scene/text.cpp
  37. +39
    -63
      src/engine/scene/text.hpp
  38. +1
    -2
      src/game/ant/ant-swarm.cpp
  39. +2
    -4
      src/game/commands/commands.cpp
  40. +1
    -1
      src/game/commands/commands.hpp
  41. +2
    -2
      src/game/components/scene-component.hpp
  42. +0
    -2
      src/game/components/transform-component.hpp
  43. +2
    -2
      src/game/controls.cpp
  44. +13
    -27
      src/game/game.cpp
  45. +10
    -3
      src/game/game.hpp
  46. +1
    -2
      src/game/loaders/entity-archetype-loader.cpp
  47. +8
    -20
      src/game/menu.cpp
  48. +0
    -1
      src/game/menu.hpp
  49. +1
    -3
      src/game/spawn.cpp
  50. +2
    -7
      src/game/states/collection-menu-state.cpp
  51. +0
    -1
      src/game/states/controls-menu-state.cpp
  52. +4
    -6
      src/game/states/credits-state.cpp
  53. +0
    -1
      src/game/states/extras-menu-state.cpp
  54. +0
    -3
      src/game/states/gamepad-config-menu-state.cpp
  55. +0
    -10
      src/game/states/graphics-menu-state.cpp
  56. +0
    -3
      src/game/states/keyboard-config-menu-state.cpp
  57. +0
    -2
      src/game/states/language-menu-state.cpp
  58. +5
    -9
      src/game/states/main-menu-state.cpp
  59. +82
    -168
      src/game/states/nest-selection-state.cpp
  60. +0
    -4
      src/game/states/nest-selection-state.hpp
  61. +9
    -13
      src/game/states/nuptial-flight-state.cpp
  62. +0
    -1
      src/game/states/options-menu-state.cpp
  63. +0
    -1
      src/game/states/pause-menu-state.cpp
  64. +0
    -7
      src/game/states/sound-menu-state.cpp
  65. +2
    -5
      src/game/states/splash-state.cpp
  66. +4
    -4
      src/game/systems/astronomy-system.cpp
  67. +36
    -52
      src/game/systems/physics-system.cpp
  68. +3
    -2
      src/game/systems/physics-system.hpp
  69. +4
    -28
      src/game/systems/render-system.cpp
  70. +0
    -1
      src/game/systems/terrain-system.cpp
  71. +7
    -11
      src/game/world.cpp

+ 0
- 1
CMakeLists.txt View File

@ -1,6 +1,5 @@
cmake_minimum_required(VERSION 3.25)
option(APPLICATION_NAME "Application name" "Antkeeper")
option(APPLICATION_VERSION "Application version string" "0.0.0")
option(APPLICATION_AUTHOR "Application author" "C. J. Howard")

+ 0
- 1
src/engine/animation/screen-transition.cpp View File

@ -107,7 +107,6 @@ void screen_transition::transition(float duration, bool reverse, ::animation
// Update tweens
progress->set(initial_state);
//material.update_tweens();
// Reset and play transition animation
animation.stop();

+ 2
- 2
src/engine/physics/kinematics/constraints/spring-constraint.cpp View File

@ -33,8 +33,8 @@ void spring_constraint::solve(float dt)
const math::vector<float, 3> radius_b = m_body_b->get_orientation() * m_point_b;
// Get world-space spring attachment points
const math::vector<float, 3> point_a = m_body_a->get_center_of_mass() + radius_a;
const math::vector<float, 3> point_b = m_body_b->get_center_of_mass() + radius_b;
const math::vector<float, 3> point_a = m_body_a->get_position() + radius_a;
const math::vector<float, 3> point_b = m_body_b->get_position() + radius_b;
// Calculate relative velocity between the attachment points
const math::vector<float, 3> velocity = m_body_b->get_point_velocity(radius_b) - m_body_a->get_point_velocity(radius_a);

+ 18
- 4
src/engine/physics/kinematics/rigid-body.cpp View File

@ -18,6 +18,7 @@
*/
#include <engine/physics/kinematics/rigid-body.hpp>
#include <engine/math/interpolation.hpp>
#include <algorithm>
namespace physics {
@ -43,12 +44,25 @@ void rigid_body::integrate_forces(float dt) noexcept
void rigid_body::integrate_velocities(float dt) noexcept
{
// Update center of mass
m_center_of_mass += m_linear_velocity * dt;
// Record previous state
m_previous_transform = m_current_transform;
// Update position
m_current_transform.translation += m_linear_velocity * dt;
// Update orientation
const math::quaternion<float> spin = math::quaternion<float>{0.0f, m_angular_velocity * 0.5f} * m_orientation;
m_orientation = math::normalize(m_orientation + spin * dt);
const math::quaternion<float> spin = math::quaternion<float>{0.0f, m_angular_velocity * 0.5f} * m_current_transform.rotation;
m_current_transform.rotation = math::normalize(m_current_transform.rotation + spin * dt);
}
math::transform<float> rigid_body::interpolate(float alpha) const
{
return
{
math::lerp(m_previous_transform.translation, m_current_transform.translation, alpha),
math::nlerp(m_previous_transform.rotation, m_current_transform.rotation, alpha),
math::lerp(m_previous_transform.scale, m_current_transform.scale, alpha),
};
}
} // namespace physics

+ 109
- 16
src/engine/physics/kinematics/rigid-body.hpp View File

@ -23,6 +23,7 @@
#include <engine/math/vector.hpp>
#include <engine/math/quaternion.hpp>
#include <engine/physics/kinematics/collider.hpp>
#include <engine/math/transform-type.hpp>
#include <memory>
namespace physics {
@ -34,23 +35,73 @@ class rigid_body
{
public:
/**
* Sets the center of mass of the rigid body.
* Sets the transformation representing the current state of the rigid body.
*
* @param point World-space center of mass.
* @param transform Transformation representing the current state of the rigid body.
*/
inline void set_center_of_mass(const math::vector<float, 3>& point) noexcept
inline void set_transform(const math::transform<float>& transform) noexcept
{
m_center_of_mass = point;
m_current_transform = transform;
}
/**
* Sets the world-space orientation of the rigid body.
* Sets the current position of the rigid body.
*
* @param orientation World-space orientation.
* @param position Position of the rigid body.
*/
inline void set_position(const math::vector<float, 3>& position) noexcept
{
m_current_transform.translation = position;
}
/**
* Sets the current orientation of the rigid body.
*
* @param orientation Orientation of the rigid body.
*/
inline void set_orientation(const math::quaternion<float>& orientation) noexcept
{
m_orientation = orientation;
m_current_transform.rotation = orientation;
}
/**
* Sets the transformation representing the previous state of the rigid body.
*
* @param transform Transformation representing the previous state of the rigid body.
*/
inline void set_previous_transform(const math::transform<float>& transform) noexcept
{
m_previous_transform = transform;
}
/**
* Sets the previous position of the rigid body.
*
* @param position Position of the rigid body.
*/
inline void set_previous_position(const math::vector<float, 3>& position) noexcept
{
m_previous_transform.translation = position;
}
/**
* Sets the previous orientation of the rigid body.
*
* @param orientation Orientation of the rigid body.
*/
inline void set_previous_orientation(const math::quaternion<float>& orientation) noexcept
{
m_previous_transform.rotation = orientation;
}
/**
* Sets the center of mass of the rigid body.
*
* @param point World-space center of mass.
*/
inline void set_center_of_mass(const math::vector<float, 3>& point) noexcept
{
m_center_of_mass = point;
}
/**
@ -149,16 +200,46 @@ public:
m_angular_momentum = m_inertia * m_angular_velocity;
}
/// Returns the world-space center of mass of the rigid body.
[[nodiscard]] inline const math::vector<float, 3>& get_center_of_mass() const noexcept
/// Returns the transformation representing the current state of the rigid body.
[[nodiscard]] inline const math::transform<float>& get_transform() const noexcept
{
return m_center_of_mass;
return m_current_transform;
}
/// Returns the current position of the rigid body.
[[nodiscard]] inline const math::vector<float, 3>& get_position() const noexcept
{
return m_current_transform.translation;
}
/// Returns the world-space orientation of the rigid body.
/// Returns the current orientation of the rigid body.
[[nodiscard]] inline const math::quaternion<float>& get_orientation() const noexcept
{
return m_orientation;
return m_current_transform.rotation;
}
/// Returns the transformation representing the previous state of the rigid body.
[[nodiscard]] inline const math::transform<float>& get_previous_transform() const noexcept
{
return m_previous_transform;
}
/// Returns the previous position of the rigid body.
[[nodiscard]] inline const math::vector<float, 3>& get_previous_position() const noexcept
{
return m_previous_transform.translation;
}
/// Returns the previous orientation of the rigid body.
[[nodiscard]] inline const math::quaternion<float>& get_previous_orientation() const noexcept
{
return m_previous_transform.rotation;
}
/// Returns the center of mass of the rigid body.
[[nodiscard]] inline const math::vector<float, 3>& get_center_of_mass() const noexcept
{
return m_center_of_mass;
}
/// Returns the mass of the rigid body, in kg.
@ -365,12 +446,24 @@ public:
integrate_velocities(dt);
}
/**
* Returns a transformation representing a state of the rigid body between its current and previous states.
*
* @param alpha State interpolation factor.
*
* @return Interpolated transformation.
*/
[[nodiscard]] math::transform<float> interpolate(float alpha) const;
private:
/// World-space center of mass.
math::vector<float, 3> m_center_of_mass{math::vector<float, 3>::zero()};
/// Transformation representing the current state of the rigid body.
math::transform<float> m_current_transform{math::transform<float>::identity};
/// World-space orientation.
math::quaternion<float> m_orientation{math::quaternion<float>::identity()};
/// Transformation representing the previous state of the rigid body.
math::transform<float> m_previous_transform{math::transform<float>::identity};
/// Center of mass.
math::vector<float, 3> m_center_of_mass{math::vector<float, 3>::zero()};
/// Mass, in kg.
float m_mass{1.0f};

+ 0
- 24
src/engine/render/context.hpp View File

@ -44,33 +44,9 @@ struct context
/// Pointer to the camera.
const scene::camera* camera;
/// Camera transform.
math::transform<float> camera_transform;
/// Camera forward vector
float3 camera_forward;
/// Camera up vector.
float3 camera_up;
/// Camera culling volume.
const geom::bounding_volume<float>* camera_culling_volume;
/// Near clipping plane of the camera.
geom::plane<float> clip_near;
/// Camera view matrix.
float4x4 view;
/// Camera projection matrix.
float4x4 projection;
/// Camera view projection matrix.
float4x4 view_projection;
/// Camera exposure normalization factor.
float exposure;
/// Collection of scene objects being rendered.
const scene::collection* collection;

+ 26
- 22
src/engine/render/passes/material-pass.cpp View File

@ -293,15 +293,15 @@ void material_pass::set_fallback_material(std::shared_ptr fall
void material_pass::evaluate_camera(const render::context& ctx)
{
view = &ctx.view;
projection = &ctx.projection;
view_projection = &ctx.view_projection;
camera_position = &ctx.camera_transform.translation;
camera_exposure = ctx.exposure;
view = &ctx.camera->get_view();
projection = &ctx.camera->get_projection();
view_projection = &ctx.camera->get_view_projection();
camera_position = &ctx.camera->get_translation();
camera_exposure = ctx.camera->get_exposure_normalization();
clip_depth =
{
ctx.camera->get_clip_near_tween().interpolate(ctx.alpha),
ctx.camera->get_clip_far_tween().interpolate(ctx.alpha)
ctx.camera->get_clip_near(),
ctx.camera->get_clip_far()
};
log_depth_coef = 2.0f / std::log2(clip_depth[1] + 1.0f);
}
@ -324,8 +324,8 @@ void material_pass::evaluate_lighting(const render::context& ctx)
continue;
}
const scene::light* light = static_cast<const scene::light*>(object);
switch (light->get_light_type())
const scene::light& light = static_cast<const scene::light&>(*object);
switch (light.get_light_type())
{
// Add ambient light
case scene::light_type::ambient:
@ -338,13 +338,17 @@ void material_pass::evaluate_lighting(const render::context& ctx)
ambient_light_colors.resize(ambient_light_count);
}
ambient_light_colors[index] = light->get_scaled_color_tween().interpolate(ctx.alpha) * ctx.exposure;
ambient_light_colors[index] = static_cast<const scene::ambient_light&>(light).get_illuminance() * ctx.camera->get_exposure_normalization();
break;
}
// Add point light
case scene::light_type::point:
{
const scene::point_light& point_light = static_cast<const scene::point_light&>(light);
const std::size_t index = point_light_count;
++point_light_count;
@ -355,16 +359,16 @@ void material_pass::evaluate_lighting(const render::context& ctx)
point_light_attenuations.resize(point_light_count);
}
point_light_colors[index] = light->get_scaled_color_tween().interpolate(ctx.alpha) * ctx.exposure;
point_light_positions[index] = light->get_transform_tween().interpolate(ctx.alpha).translation;
point_light_attenuations[index] = static_cast<const scene::point_light*>(light)->get_attenuation_tween().interpolate(ctx.alpha);
point_light_colors[index] = point_light.get_luminous_flux() * ctx.camera->get_exposure_normalization();
point_light_positions[index] = point_light.get_translation();
point_light_attenuations[index] = point_light.get_attenuation();
break;
}
// Add directional light
case scene::light_type::directional:
{
const scene::directional_light& directional_light = static_cast<const scene::directional_light&>(*light);
const scene::directional_light& directional_light = static_cast<const scene::directional_light&>(light);
const std::size_t index = directional_light_count;
@ -375,8 +379,8 @@ void material_pass::evaluate_lighting(const render::context& ctx)
directional_light_directions.resize(directional_light_count);
}
directional_light_colors[index] = directional_light.get_scaled_color_tween().interpolate(ctx.alpha) * ctx.exposure;
directional_light_directions[index] = directional_light.get_direction_tween().interpolate(ctx.alpha);
directional_light_colors[index] = directional_light.get_illuminance() * ctx.camera->get_exposure_normalization();
directional_light_directions[index] = directional_light.get_direction();
// Add directional shadow
if (directional_light.is_shadow_caster() && directional_light.get_shadow_framebuffer())
@ -403,7 +407,7 @@ void material_pass::evaluate_lighting(const render::context& ctx)
// Add spot_light
case scene::light_type::spot:
{
const scene::spot_light& spot_light = static_cast<const scene::spot_light&>(*light);
const scene::spot_light& spot_light = static_cast<const scene::spot_light&>(light);
const std::size_t index = spot_light_count;
@ -417,11 +421,11 @@ void material_pass::evaluate_lighting(const render::context& ctx)
spot_light_cutoffs.resize(spot_light_count);
}
spot_light_colors[index] = spot_light.get_scaled_color_tween().interpolate(ctx.alpha) * ctx.exposure;
spot_light_positions[index] = spot_light.get_transform_tween().interpolate(ctx.alpha).translation;
spot_light_directions[index] = spot_light.get_direction_tween().interpolate(ctx.alpha);
spot_light_attenuations[index] = spot_light.get_attenuation_tween().interpolate(ctx.alpha);
spot_light_cutoffs[index] = spot_light.get_cosine_cutoff_tween().interpolate(ctx.alpha);
spot_light_colors[index] = spot_light.get_luminous_flux() * ctx.camera->get_exposure_normalization();
spot_light_positions[index] = spot_light.get_translation();
spot_light_directions[index] = spot_light.get_direction();
spot_light_attenuations[index] = spot_light.get_attenuation();
spot_light_cutoffs[index] = spot_light.get_cosine_cutoff();
break;
}

+ 7
- 13
src/engine/render/passes/shadow-map-pass.cpp View File

@ -134,14 +134,8 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render::
// Get camera
const scene::camera& camera = *ctx.camera;
// Get tweened camera parameters
const float camera_fov = camera.get_fov_tween().interpolate(ctx.alpha);
const float camera_aspect_ratio = camera.get_aspect_ratio_tween().interpolate(ctx.alpha);
const float camera_clip_near = camera.get_clip_near_tween().interpolate(ctx.alpha);
const float camera_clip_far = camera.get_clip_far_tween().interpolate(ctx.alpha);
// Calculate distance to shadow cascade depth clipping planes
const float shadow_clip_far = math::lerp(camera_clip_near, camera_clip_far, light.get_shadow_cascade_coverage());
const float shadow_clip_far = math::lerp(camera.get_clip_near(), camera.get_clip_far(), light.get_shadow_cascade_coverage());
const unsigned int cascade_count = light.get_shadow_cascade_count();
@ -156,8 +150,8 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render::
const float weight = static_cast<float>(i + 1) / static_cast<float>(cascade_count);
// Calculate linear and logarithmic distribution distances
const float linear_distance = math::lerp(camera_clip_near, shadow_clip_far, weight);
const float log_distance = math::log_lerp(camera_clip_near, shadow_clip_far, weight);
const float linear_distance = math::lerp(camera.get_clip_near(), shadow_clip_far, weight);
const float log_distance = math::log_lerp(camera.get_clip_near(), shadow_clip_far, weight);
// Interpolate between linear and logarithmic distribution distances
cascade_distances[i] = math::lerp(linear_distance, log_distance, light.get_shadow_cascade_distribution());
@ -180,7 +174,7 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render::
}
// Calculate a view-projection matrix from the directional light's transform
math::transform<float> light_transform = light.get_transform_tween().interpolate(ctx.alpha);
const auto& light_transform = light.get_transform();
float3 forward = light_transform.rotation * config::global_forward;
float3 up = light_transform.rotation * config::global_up;
float4x4 light_view = math::look_at(light_transform.translation, light_transform.translation + forward, up);
@ -202,12 +196,12 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render::
rasterizer->set_viewport(viewport[0], viewport[1], viewport[2], viewport[3]);
// Calculate projection matrix for view camera subfrustum
const float subfrustum_near = (i) ? cascade_distances[i - 1] : camera_clip_near;
const float subfrustum_near = (i) ? cascade_distances[i - 1] : camera.get_clip_near();
const float subfrustum_far = cascade_distances[i];
float4x4 subfrustum_projection = math::perspective_half_z(camera_fov, camera_aspect_ratio, subfrustum_near, subfrustum_far);
float4x4 subfrustum_projection = math::perspective_half_z(camera.get_fov(), camera.get_aspect_ratio(), subfrustum_near, subfrustum_far);
// Calculate view camera subfrustum
geom::view_frustum<float> subfrustum(subfrustum_projection * ctx.view);
geom::view_frustum<float> subfrustum(subfrustum_projection * camera.get_view());
// Create AABB containing the view camera subfrustum corners
const std::array<float3, 8>& subfrustum_corners = subfrustum.get_corners();

+ 13
- 15
src/engine/render/passes/sky-pass.cpp View File

@ -191,13 +191,11 @@ void sky_pass::render(render::context& ctx)
// Construct matrices
const scene::camera& camera = *ctx.camera;
float clip_near = camera.get_clip_near_tween().interpolate(ctx.alpha);
float clip_far = camera.get_clip_far_tween().interpolate(ctx.alpha);
float3 model_scale = float3{1.0f, 1.0f, 1.0f} * (clip_near + clip_far) * 0.5f;
float3 model_scale = float3{1.0f, 1.0f, 1.0f} * (camera.get_clip_near() + camera.get_clip_far()) * 0.5f;
float4x4 model = math::scale(math::matrix4<float>::identity(), model_scale);
float4x4 view = float4x4(float3x3(ctx.view));
float4x4 view = float4x4(float3x3(camera.get_view()));
float4x4 model_view = view * model;
const float4x4& projection = ctx.projection;
const float4x4& projection = camera.get_projection();
float4x4 view_projection = projection * view;
float4x4 model_view_projection = projection * model_view;
@ -216,12 +214,12 @@ void sky_pass::render(render::context& ctx)
float3 sun_direction = math::normalize(sun_position);
// Interpolate and expose sun luminance and illuminance
float3 sun_illuminance = sun_illuminance_tween.interpolate(ctx.alpha) * ctx.exposure;
float3 sun_luminance = sun_luminance_tween.interpolate(ctx.alpha) * ctx.exposure;
float3 sun_illuminance = sun_illuminance_tween.interpolate(ctx.alpha) * camera_exposure;
float3 sun_luminance = sun_luminance_tween.interpolate(ctx.alpha) * camera_exposure;
float3 moon_position = moon_position_tween.interpolate(ctx.alpha);
float3 moon_direction = math::normalize(moon_position);
float3 moon_illuminance = moon_illuminance_tween.interpolate(ctx.alpha) * ctx.exposure;
float3 moon_illuminance = moon_illuminance_tween.interpolate(ctx.alpha) * camera_exposure;
float moon_angular_radius = moon_angular_radius_tween.interpolate(ctx.alpha) * magnification;
float sun_y = color::aces::ap1<float>.luminance(sun_transmitted_illuminance);
@ -234,7 +232,7 @@ void sky_pass::render(render::context& ctx)
sun_luminance *= 0.0f;
}
camera_exposure = ctx.exposure;
camera_exposure = camera.get_exposure_normalization();
// Render sky illuminance LUT
for (const auto& command: sky_lut_command_buffer)
@ -286,7 +284,7 @@ void sky_pass::render(render::context& ctx)
// Draw stars
if (star_shader_program)
{
float star_distance = (clip_near + clip_far) * 0.5f;
float star_distance = (camera.get_clip_near() + camera.get_clip_far()) * 0.5f;
model = float4x4(float3x3(icrf_to_eus.r));
model = math::scale(model, {star_distance, star_distance, star_distance});
@ -301,7 +299,7 @@ void sky_pass::render(render::context& ctx)
if (star_distance_var)
star_distance_var->update(star_distance);
if (star_exposure_var)
star_exposure_var->update(ctx.exposure);
star_exposure_var->update(camera_exposure);
//star_material->update(ctx.alpha);
@ -312,7 +310,7 @@ void sky_pass::render(render::context& ctx)
//if (moon_position.y() >= -moon_angular_radius)
if (moon_shader_program)
{
float moon_distance = (clip_near + clip_far) * 0.5f;
float moon_distance = (camera.get_clip_near() + camera.get_clip_far()) * 0.5f;
float moon_radius = moon_angular_radius * moon_distance;
math::transform<float> moon_transform;
@ -331,15 +329,15 @@ void sky_pass::render(render::context& ctx)
if (moon_normal_model_var)
moon_normal_model_var->update(normal_model);
if (moon_camera_position_var)
moon_camera_position_var->update(ctx.camera_transform.translation);
moon_camera_position_var->update(camera.get_translation());
if (moon_sunlight_direction_var)
moon_sunlight_direction_var->update(math::normalize(moon_sunlight_direction_tween.interpolate(ctx.alpha)));
if (moon_sunlight_illuminance_var)
moon_sunlight_illuminance_var->update(moon_sunlight_illuminance_tween.interpolate(ctx.alpha) * ctx.exposure);
moon_sunlight_illuminance_var->update(moon_sunlight_illuminance_tween.interpolate(ctx.alpha) * camera_exposure);
if (moon_planetlight_direction_var)
moon_planetlight_direction_var->update(math::normalize(moon_planetlight_direction_tween.interpolate(ctx.alpha)));
if (moon_planetlight_illuminance_var)
moon_planetlight_illuminance_var->update(moon_planetlight_illuminance_tween.interpolate(ctx.alpha) * ctx.exposure);
moon_planetlight_illuminance_var->update(moon_planetlight_illuminance_tween.interpolate(ctx.alpha) * camera_exposure);
//moon_material->update(ctx.alpha);
rasterizer->draw_arrays(*moon_model_vao, moon_model_drawing_mode, moon_model_start_index, moon_model_index_count);

+ 1
- 10
src/engine/render/renderer.cpp View File

@ -24,7 +24,6 @@
#include <engine/scene/camera.hpp>
#include <engine/scene/static-mesh.hpp>
#include <engine/scene/billboard.hpp>
#include <engine/scene/lod-group.hpp>
#include <engine/scene/text.hpp>
#include <engine/render/model.hpp>
#include <engine/gl/drawing-mode.hpp>
@ -73,16 +72,8 @@ void renderer::render(float t, float dt, float alpha, const scene::collection& c
continue;
}
// Update render context with camera-specific parameters
// Update render context camera
ctx.camera = &camera;
ctx.camera_transform = camera.get_transform_tween().interpolate(alpha);
ctx.camera_forward = ctx.camera_transform.rotation * config::global_forward;
ctx.camera_up = ctx.camera_transform.rotation * config::global_up;
ctx.clip_near = camera.get_view_frustum().get_near(); ///< @TODO: tween this
ctx.view = camera.get_view_tween().interpolate(alpha);
ctx.projection = camera.get_projection_tween().interpolate(alpha);
ctx.view_projection = ctx.projection * ctx.view;
ctx.exposure = std::exp2(-camera.get_exposure_tween().interpolate(alpha));
// Clear render queues
ctx.objects.clear();

+ 4
- 3
src/engine/render/stages/culling-stage.cpp View File

@ -35,8 +35,9 @@ void culling_stage::execute(render::context& ctx)
ctx.camera_culling_volume = ctx.camera->get_culling_mask();
if (!ctx.camera_culling_volume)
{
ctx.camera_culling_volume = &ctx.camera->get_world_bounds();
ctx.camera_culling_volume = &ctx.camera->get_view_frustum().get_bounds();
}
const auto& culling_volume = *ctx.camera_culling_volume;
// Construct mutex to guard set of visible objects
std::mutex mutex;
@ -63,11 +64,11 @@ void culling_stage::execute(render::context& ctx)
const geom::bounding_volume<float>* object_culling_volume = object->get_culling_mask();
if (!object_culling_volume)
{
object_culling_volume = &object->get_world_bounds();
object_culling_volume = &object->get_bounds();
}
// Cull object if it's outside of the camera culling volume
if (!ctx.camera_culling_volume->intersects(*object_culling_volume))
if (!culling_volume.intersects(*object_culling_volume))
{
return;
}

+ 23
- 0
src/engine/scene/ambient-light.hpp View File

@ -21,9 +21,13 @@
#define ANTKEEPER_SCENE_AMBIENT_LIGHT_HPP
#include <engine/scene/light.hpp>
#include <engine/math/vector.hpp>
namespace scene {
/**
* Omnidirectional source of illuminance.
*/
class ambient_light: public light
{
public:
@ -31,6 +35,25 @@ public:
{
return light_type::ambient;
}
/**
* Sets the illuminance of the ambient light.
*
* @param illuminance Illuminance, in *lx*.
*/
inline void set_illuminance(const math::vector<float, 3>& illuminance) noexcept
{
m_illuminance = illuminance;
}
/// Returns the illuminance of the ambient light, in *lx*.
[[nodiscard]] inline const math::vector<float, 3>& get_illuminance() const noexcept
{
return m_illuminance;
}
private:
math::vector<float, 3> m_illuminance{0.0f, 0.0f, 0.0f};
};
} // namespace scene

+ 42
- 0
src/engine/scene/billboard-type.hpp View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_SCENE_BILLBOARD_TYPE_HPP
#define ANTKEEPER_SCENE_BILLBOARD_TYPE_HPP
#include <cstdint>
namespace scene {
/// Billboard types.
enum class billboard_type: std::uint8_t
{
/// Billboard is unaligned.
flat,
/// Billboard aligns to face camera.
spherical,
/// Billboard rotates about an alignment axis to face camera.
cylindrical
};
} // namespace scene
#endif // ANTKEEPER_SCENE_BILLBOARD_TYPE_HPP

+ 64
- 46
src/engine/scene/billboard.cpp View File

@ -21,15 +21,11 @@
#include <engine/config.hpp>
#include <engine/render/vertex-attribute.hpp>
#include <engine/geom/projection.hpp>
#include <engine/scene/camera.hpp>
namespace scene {
const typename billboard::aabb_type billboard::local_bounds = {{-1, -1, -1}, {1, 1, 1}};
billboard::billboard():
world_bounds(local_bounds),
type(billboard_type::flat),
alignment_axis(config::global_up)
billboard::billboard()
{
const float vertex_data[] =
{
@ -45,13 +41,13 @@ billboard::billboard():
const std::size_t vertex_stride = sizeof(float) * vertex_size;
const std::size_t vertex_count = 6;
vbo = std::make_unique<gl::vertex_buffer>(gl::buffer_usage::static_draw, sizeof(float) * vertex_size * vertex_count, std::as_bytes(std::span{vertex_data}));
m_vbo = std::make_unique<gl::vertex_buffer>(gl::buffer_usage::static_draw, sizeof(float) * vertex_size * vertex_count, std::as_bytes(std::span{vertex_data}));
std::size_t attribute_offset = 0;
// Define position vertex attribute
gl::vertex_attribute position_attribute;
position_attribute.buffer = vbo.get();
position_attribute.buffer = m_vbo.get();
position_attribute.offset = attribute_offset;
position_attribute.stride = vertex_stride;
position_attribute.type = gl::vertex_attribute_type::float_32;
@ -60,7 +56,7 @@ billboard::billboard():
// Define UV vertex attribute
gl::vertex_attribute uv_attribute;
uv_attribute.buffer = vbo.get();
uv_attribute.buffer = m_vbo.get();
uv_attribute.offset = attribute_offset;
uv_attribute.stride = vertex_stride;
uv_attribute.type = gl::vertex_attribute_type::float_32;
@ -69,7 +65,7 @@ billboard::billboard():
// Define barycentric vertex attribute
gl::vertex_attribute barycentric_attribute;
barycentric_attribute.buffer = vbo.get();
barycentric_attribute.buffer = m_vbo.get();
barycentric_attribute.offset = attribute_offset;
barycentric_attribute.stride = vertex_stride;
barycentric_attribute.type = gl::vertex_attribute_type::float_32;
@ -77,65 +73,87 @@ billboard::billboard():
//attribute_offset += barycentric_attribute.components * sizeof(float);
// Bind vertex attributes to VAO
vao = std::make_unique<gl::vertex_array>();
vao->bind(render::vertex_attribute::position, position_attribute);
vao->bind(render::vertex_attribute::uv, uv_attribute);
vao->bind(render::vertex_attribute::barycentric, barycentric_attribute);
m_vao = std::make_unique<gl::vertex_array>();
m_vao->bind(render::vertex_attribute::position, position_attribute);
m_vao->bind(render::vertex_attribute::uv, uv_attribute);
m_vao->bind(render::vertex_attribute::barycentric, barycentric_attribute);
// Init render operation
render_op.vertex_array = vao.get();
render_op.drawing_mode = gl::drawing_mode::triangles;
render_op.start_index = 0;
render_op.index_count = 6;
m_render_op.vertex_array = m_vao.get();
m_render_op.drawing_mode = gl::drawing_mode::triangles;
m_render_op.start_index = 0;
m_render_op.index_count = 6;
m_render_op.transform = float4x4::identity();
}
void billboard::render(render::context& ctx) const
{
auto transform = get_transform_tween().interpolate(ctx.alpha);
// Align billboard
if (type == scene::billboard_type::spherical)
switch (m_billboard_type)
{
transform.rotation = math::normalize(math::look_rotation(ctx.camera_forward, ctx.camera_up) * transform.rotation);
}
else if (type == scene::billboard_type::cylindrical)
{
float3 look = math::normalize(geom::project_on_plane(transform.translation - ctx.camera_transform.translation, {0.0f, 0.0f, 0.0f}, alignment_axis));
float3 right = math::normalize(math::cross(alignment_axis, look));
look = math::cross(right, alignment_axis);
float3 up = math::cross(look, right);
transform.rotation = math::normalize(math::look_rotation(look, up) * transform.rotation);
case scene::billboard_type::spherical:
{
auto transform = get_transform();
transform.rotation = math::normalize(math::look_rotation(ctx.camera->get_forward(), ctx.camera->get_up()) * transform.rotation);
m_render_op.transform = math::matrix_cast(transform);
break;
}
case scene::billboard_type::cylindrical:
{
auto transform = get_transform();
auto look = math::normalize(geom::project_on_plane(transform.translation - ctx.camera->get_translation(), {0.0f, 0.0f, 0.0f}, m_alignment_axis));
const auto right = math::normalize(math::cross(m_alignment_axis, look));
look = math::cross(right, m_alignment_axis);
const auto up = math::cross(look, right);
transform.rotation = math::normalize(math::look_rotation(look, up) * transform.rotation);
m_render_op.transform = math::matrix_cast(transform);
break;
}
case scene::billboard_type::flat:
break;
default:
break;
}
render_op.transform = math::matrix_cast(transform);
render_op.depth = ctx.clip_near.signed_distance(transform.translation);
m_render_op.depth = ctx.camera->get_view_frustum().get_near().signed_distance(get_translation());
ctx.operations.emplace_back(&render_op);
ctx.operations.emplace_back(&m_render_op);
}
void billboard::set_material(std::shared_ptr<render::material> material)
{
render_op.material = material;
m_render_op.material = material;
}
void billboard::set_billboard_type(billboard_type type)
{
this->type = type;
}
void billboard::set_alignment_axis(const float3& axis)
{
this->alignment_axis = axis;
m_billboard_type = type;
if (m_billboard_type == scene::billboard_type::flat)
{
m_render_op.transform = math::matrix_cast(get_transform());
}
}
void billboard::transformed()
{
world_bounds = aabb_type::transform(local_bounds, get_transform());
}
void billboard::update_tweens()
{
object_base::update_tweens();
static const aabb_type untransformed_bounds{{-1, -1, -1}, {1, 1, 1}};
m_bounds = aabb_type::transform(untransformed_bounds, get_transform());
if (m_billboard_type == scene::billboard_type::flat)
{
m_render_op.transform = math::matrix_cast(get_transform());
}
}
} // namespace scene

+ 37
- 43
src/engine/scene/billboard.hpp View File

@ -22,88 +22,82 @@
#include <engine/scene/object.hpp>
#include <engine/geom/aabb.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <engine/math/vector.hpp>
#include <engine/render/material.hpp>
#include <engine/render/operation.hpp>
#include <engine/gl/vertex-array.hpp>
#include <engine/gl/vertex-buffer.hpp>
#include <cstdint>
#include <engine/scene/billboard-type.hpp>
#include <memory>
namespace scene {
/// Enumerates billboard types.
enum class billboard_type: std::uint8_t
{
/// No alignment
flat,
/// Aligns to face camera
spherical,
/// Rotates about an alignment axis to face camera
cylindrical
};
/**
* A 2D unit quad with one material.
* 2D unit quad with a single material.
*/
class billboard: public object<billboard>
{
public:
typedef geom::aabb<float> aabb_type;
using aabb_type = geom::aabb<float>;
/// Constructs a billboard.
billboard();
void render(render::context& ctx) const override;
/**
* Sets the billboard material.
*
* @param material Billboard material.
*/
void set_material(std::shared_ptr<render::material> material);
/// Sets the billboard alignment mode.
/**
* Sets the billboard type.
*
* @param type Billboard type.
*/
void set_billboard_type(billboard_type type);
/// Sets the axis around which the billboard will be rotated when the alignment is set to billboard_alignment::cylindrical.
void set_alignment_axis(const float3& axis);
[[nodiscard]] inline virtual const bounding_volume_type& get_local_bounds() const noexcept
/**
* Sets alignment axis for cylindrical billboards.
*
* @param axis Cylindral billboard aligmment axis.
*/
inline void set_alignment_axis(const math::vector<float, 3>& axis) noexcept
{
return local_bounds;
m_alignment_axis = axis;
}
[[nodiscard]] inline virtual const bounding_volume_type& get_world_bounds() const noexcept
[[nodiscard]] inline const bounding_volume_type& get_bounds() const noexcept override
{
return world_bounds;
return m_bounds;
}
[[nodiscard]] inline std::shared_ptr<render::material> get_material() const noexcept
{
return render_op.material;
return m_render_op.material;
}
[[nodiscard]] inline billboard_type get_billboard_type() const noexcept
{
return type;
return m_billboard_type;
}
[[nodiscard]] inline const float3& get_alignment_axis() const noexcept
[[nodiscard]] inline const math::vector<float, 3>& get_alignment_axis() const noexcept
{
return alignment_axis;
return m_alignment_axis;
}
virtual void update_tweens();
private:
static const aabb_type local_bounds;
virtual void transformed();
std::unique_ptr<gl::vertex_buffer> vbo;
std::unique_ptr<gl::vertex_array> vao;
void transformed() override;
mutable render::operation render_op;
aabb_type world_bounds;
billboard_type type;
float3 alignment_axis;
std::unique_ptr<gl::vertex_buffer> m_vbo;
std::unique_ptr<gl::vertex_array> m_vao;
mutable render::operation m_render_op;
aabb_type m_bounds{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}};
billboard_type m_billboard_type{billboard_type::flat};
math::vector<float, 3> m_alignment_axis{0.0f, 1.0f, 0.0f};
};
} // namespace scene

+ 44
- 118
src/engine/scene/camera.cpp View File

@ -18,70 +18,14 @@
*/
#include <engine/scene/camera.hpp>
#include <engine/config.hpp>
#include <engine/math/numbers.hpp>
#include <engine/math/interpolation.hpp>
#include <engine/math/quaternion.hpp>
#include <engine/math/projection.hpp>
namespace scene {
static float4x4 interpolate_view(const camera* camera, const float4x4& x, const float4x4& y, float a)
{
math::transform<float> transform = camera->get_transform_tween().interpolate(a);
float3 forward = transform.rotation * config::global_forward;
float3 up = transform.rotation * config::global_up;
return math::look_at(transform.translation, transform.translation + forward, up);
}
static float4x4 interpolate_projection(const camera* camera, const float4x4& x, const float4x4& y, float a)
{
if (camera->is_orthographic())
{
return math::ortho(
camera->get_clip_left_tween().interpolate(a),
camera->get_clip_right_tween().interpolate(a),
camera->get_clip_bottom_tween().interpolate(a),
camera->get_clip_top_tween().interpolate(a),
camera->get_clip_far_tween().interpolate(a),
camera->get_clip_near_tween().interpolate(a));
}
else
{
return math::perspective(
camera->get_fov_tween().interpolate(a),
camera->get_aspect_ratio_tween().interpolate(a),
camera->get_clip_far_tween().interpolate(a),
camera->get_clip_near_tween().interpolate(a));
}
}
static float4x4 interpolate_view_projection(const camera* camera, const float4x4& x, const float4x4& y, float a)
{
return camera->get_projection_tween().interpolate(a) * camera->get_view_tween().interpolate(a);
}
camera::camera():
compositor(nullptr),
composite_index(0),
orthographic(true),
clip_left(-1.0f, math::lerp<float, float>),
clip_right(1.0f, math::lerp<float, float>),
clip_bottom(-1.0f, math::lerp<float, float>),
clip_top(1.0f, math::lerp<float, float>),
clip_near(-1.0f, math::lerp<float, float>),
clip_far(1.0f, math::lerp<float, float>),
fov(math::half_pi<float>, math::lerp<float, float>),
aspect_ratio(1.0f, math::lerp<float, float>),
view(math::matrix4<float>::identity(), std::bind(&interpolate_view, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)),
projection(math::matrix4<float>::identity(), std::bind(&interpolate_projection, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)),
view_projection(math::matrix4<float>::identity(), std::bind(&interpolate_view_projection, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)),
exposure(0.0f, math::lerp<float, float>)
{}
geom::primitive::ray<float, 3> camera::pick(const float2& ndc) const
{
const float4x4 inverse_view_projection = math::inverse(view_projection[1]);
const float4x4 inverse_view_projection = math::inverse(m_view_projection);
const float4 near = inverse_view_projection * float4{ndc[0], ndc[1], 1.0f, 1.0f};
const float4 far = inverse_view_projection * float4{ndc[0], ndc[1], 0.0f, 1.0f};
@ -94,7 +38,7 @@ geom::primitive::ray camera::pick(const float2& ndc) const
float3 camera::project(const float3& object, const float4& viewport) const
{
float4 result = view_projection[1] * float4{object[0], object[1], object[2], 1.0f};
float4 result = m_view_projection * float4{object[0], object[1], object[2], 1.0f};
result[0] = (result[0] / result[3]) * 0.5f + 0.5f;
result[1] = (result[1] / result[3]) * 0.5f + 0.5f;
result[2] = (result[2] / result[3]) * 0.5f + 0.5f;
@ -115,96 +59,78 @@ float3 camera::unproject(const float3& window, const float4& viewport) const
result[2] = 1.0f - window[2]; // z: [1, 0]
result[3] = 1.0f;
result = math::inverse(view_projection[1]) * result;
result = math::inverse(m_view_projection) * result;
return math::vector<float, 3>(result) * (1.0f / result[3]);
}
void camera::set_perspective(float fov, float aspect_ratio, float clip_near, float clip_far)
{
orthographic = false;
this->fov[1] = fov;
this->aspect_ratio[1] = aspect_ratio;
this->clip_near[1] = clip_near;
this->clip_far[1] = clip_far;
projection[1] = math::perspective_half_z(fov, aspect_ratio, clip_far, clip_near);
m_orthographic = false;
// Update perspective projection parameters
m_fov = fov;
m_aspect_ratio = aspect_ratio;
m_clip_near = clip_near;
m_clip_far = clip_far;
// Recalculate projection matrix
m_projection = math::perspective_half_z(m_fov, m_aspect_ratio, m_clip_far, m_clip_near);
// Recalculate view-projection matrix
view_projection[1] = projection[1] * view[1];
m_view_projection = m_projection * m_view;
// Recalculate view frustum
/// @TODO: this is a hack to fix the half z projection matrix view frustum
view_frustum.set_matrix(math::perspective(this->fov[1], this->aspect_ratio[1], this->clip_near[1], this->clip_far[1]) * view[1]);
m_view_frustum.set_matrix(math::perspective(m_fov, m_aspect_ratio, m_clip_near, m_clip_far) * m_view);
}
void camera::set_orthographic(float clip_left, float clip_right, float clip_bottom, float clip_top, float clip_near, float clip_far)
{
orthographic = true;
this->clip_left[1] = clip_left;
this->clip_right[1] = clip_right;
this->clip_bottom[1] = clip_bottom;
this->clip_top[1] = clip_top;
this->clip_near[1] = clip_near;
this->clip_far[1] = clip_far;
projection[1] = math::ortho_half_z(clip_left, clip_right, clip_bottom, clip_top, clip_far, clip_near);
m_orthographic = true;
// Update signed distances to clipping planes
m_clip_left = clip_left;
m_clip_right = clip_right;
m_clip_bottom = clip_bottom;
m_clip_top = clip_top;
m_clip_near = clip_near;
m_clip_far = clip_far;
// Update projection matrix
m_projection = math::ortho_half_z(m_clip_left, m_clip_right, m_clip_bottom, m_clip_top, m_clip_far, m_clip_near);
// Recalculate view-projection matrix
view_projection[1] = projection[1] * view[1];
m_view_projection = m_projection * m_view;
// Recalculate view frustum
view_frustum.set_matrix(view_projection[1]);
}
void camera::set_exposure(float ev100)
{
exposure[1] = ev100;
}
void camera::set_compositor(render::compositor* compositor)
{
this->compositor = compositor;
m_view_frustum.set_matrix(m_view_projection);
}
void camera::set_composite_index(int index)
void camera::set_exposure_value(float ev100)
{
composite_index = index;
}
void camera::update_tweens()
{
object_base::update_tweens();
clip_left.update();
clip_right.update();
clip_bottom.update();
clip_top.update();
clip_near.update();
clip_far.update();
fov.update();
aspect_ratio.update();
view.update();
projection.update();
view_projection.update();
exposure.update();
m_exposure_value = ev100;
m_exposure_normalization = 1.0f / (std::exp2(m_exposure_value) * 1.2f);
}
void camera::transformed()
{
// Recalculate view and view-projection matrices
float3 forward = get_rotation() * config::global_forward;
float3 up = get_rotation() * config::global_up;
view[1] = math::look_at(get_translation(), get_translation() + forward, up);
view_projection[1] = projection[1] * view[1];
m_forward = get_rotation() * math::vector<float, 3>{0.0f, 0.0f, -1.0f};
m_up = get_rotation() * math::vector<float, 3>{0.0f, 1.0f, 0.0f};
m_view = math::look_at(get_translation(), get_translation() + m_forward, m_up);
m_view_projection = m_projection * m_view;
// Recalculate view frustum
/// @TODO: this is a hack to fix the half z projection matrix view frustum
if (orthographic)
view_frustum.set_matrix(view_projection[1]);
if (m_orthographic)
{
m_view_frustum.set_matrix(m_view_projection);
}
else
view_frustum.set_matrix(math::perspective(fov[1], aspect_ratio[1], clip_near[1], clip_far[1]) * view[1]);
{
/// @TODO: this is a hack to fix the half z projection matrix view frustum
m_view_frustum.set_matrix(math::perspective(m_fov, m_aspect_ratio, m_clip_near, m_clip_far) * m_view);
}
}
} // namespace scene

+ 171
- 225
src/engine/scene/camera.hpp View File

@ -25,6 +25,7 @@
#include <engine/geom/primitives/ray.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <engine/render/compositor.hpp>
#include <engine/math/numbers.hpp>
namespace scene {
@ -34,9 +35,7 @@ namespace scene {
class camera: public object<camera>
{
public:
typedef geom::view_frustum<float> view_frustum_type;
camera();
using view_frustum_type = geom::view_frustum<float>;
/**
* Constructs a picking ray from normalized device coordinates (NDC).
@ -45,7 +44,7 @@ public:
*
* @return Picking ray.
*/
geom::primitive::ray<float, 3> pick(const float2& ndc) const;
[[nodiscard]] geom::primitive::ray<float, 3> pick(const float2& ndc) const;
/**
* Maps object coordinates to window coordinates.
@ -54,7 +53,7 @@ public:
* @param viewport Vector containing the `x`, `y`, `w`, and `h` of the viewport.
* @return Projected window coordinates.
*/
float3 project(const float3& object, const float4& viewport) const;
[[nodiscard]] float3 project(const float3& object, const float4& viewport) const;
/**
* Maps window coordinates to object coordinates.
@ -63,7 +62,7 @@ public:
* @param viewport Vector containing the `x`, `y`, `w`, and `h` of the viewport.
* @return Unprojected object coordinates.
*/
float3 unproject(const float3& window, const float4& viewport) const;
[[nodiscard]] float3 unproject(const float3& window, const float4& viewport) const;
/**
* Sets the camera's projection matrix using perspective projection.
@ -88,241 +87,188 @@ public:
void set_orthographic(float clip_left, float clip_right, float clip_bottom, float clip_top, float clip_near, float clip_far);
/**
* Sets the camera's ISO 100 exposure value directly
* Sets the camera's ISO 100 exposure value.
*
* @param ev100 ISO 100 exposure value.
*/
void set_exposure(float ev100);
void set_compositor(render::compositor* compositor);
void set_composite_index(int index);
void set_exposure_value(float ev100);
/**
* Sets the camera's compositor.
*
* @param compositor Compositor.
*/
inline void set_compositor(render::compositor* compositor) noexcept
{
m_compositor = compositor;
}
/**
* Sets the composite index of the camera.
*
* @param index Composite index.
*/
inline void set_composite_index(int index) noexcept
{
m_composite_index = index;
}
/**
* Returns the camera's compositor.
*/
/// @{
[[nodiscard]] inline const render::compositor* get_compositor() const noexcept
{
return m_compositor;
}
[[nodiscard]] inline render::compositor* get_compositor() noexcept
{
return m_compositor;
}
/// @}
/// Returns the composite index of the camera.
[[nodiscard]] inline int get_composite_index() const noexcept
{
return m_composite_index;
}
[[nodiscard]] inline const bounding_volume_type& get_bounds() const noexcept override
{
return m_view_frustum.get_bounds();
}
/// Returns `true` if the camera uses an orthographic projection matrix, `false` otherwise.
[[nodiscard]] inline bool is_orthographic() const noexcept
{
return m_orthographic;
}
/// Returns the signed distance to the camera's left clipping plane.
[[nodiscard]] inline float get_clip_left() const noexcept
{
return m_clip_left;
}
/// Returns the signed distance to the camera's right clipping plane.
[[nodiscard]] inline float get_clip_right() const noexcept
{
return m_clip_right;
}
/// Returns the signed distance to the camera's bottom clipping plane.
[[nodiscard]] inline float get_clip_bottom() const noexcept
{
return m_clip_bottom;
}
/// Returns the signed distance to the camera's top clipping plane.
[[nodiscard]] inline float get_clip_top() const noexcept
{
return m_clip_top;
}
/// Returns the signed distance to the camera's near clipping plane.
[[nodiscard]] inline float get_clip_near() const noexcept
{
return m_clip_near;
}
/// Returns the signed distance to the camera's far clipping plane.
[[nodiscard]] inline float get_clip_far() const noexcept
{
return m_clip_far;
}
/// Returns the camera's field of view, in radians.
[[nodiscard]] inline float get_fov() const noexcept
{
return m_fov;
}
/// Returns the camera's aspect ratio.
[[nodiscard]] inline float get_aspect_ratio() const noexcept
{
return m_aspect_ratio;
}
/// Returns the camera's ISO 100 exposure value.
[[nodiscard]] inline float get_exposure_value() const noexcept
{
return m_exposure_value;
}
/// Returns the camera's exposure normalization factor.
[[nodiscard]] inline float get_exposure_normalization() const noexcept
{
return m_exposure_normalization;
}
virtual const bounding_volume_type& get_local_bounds() const;
virtual const bounding_volume_type& get_world_bounds() const;
float is_orthographic() const;
float get_clip_left() const;
float get_clip_right() const;
float get_clip_bottom() const;
float get_clip_top() const;
float get_clip_near() const;
float get_clip_far() const;
float get_fov() const;
float get_aspect_ratio() const;
/// Returns the camera's view matrix.
const float4x4& get_view() const;
[[nodiscard]] inline const float4x4& get_view() const noexcept
{
return m_view;
}
/// Returns the camera's projection matrix.
const float4x4& get_projection() const;
[[nodiscard]] inline const float4x4& get_projection() const noexcept
{
return m_projection;
}
/// Returns the camera's view-projection matrix.
const float4x4& get_view_projection() const;
[[nodiscard]] inline const float4x4& get_view_projection() const noexcept
{
return m_view_projection;
}
/// Returns the camera's view frustum.
const view_frustum_type& get_view_frustum() const;
/// Returns the camera's forward vector.
[[nodiscard]] inline const math::vector<float, 3>& get_forward() const noexcept
{
return m_forward;
}
/// Returns the camera's ISO 100 exposure value.
float get_exposure() const;
const render::compositor* get_compositor() const;
render::compositor* get_compositor();
int get_composite_index() const;
const tween<float>& get_clip_left_tween() const;
const tween<float>& get_clip_right_tween() const;
const tween<float>& get_clip_bottom_tween() const;
const tween<float>& get_clip_top_tween() const;
const tween<float>& get_clip_near_tween() const;
const tween<float>& get_clip_far_tween() const;
const tween<float>& get_fov_tween() const;
const tween<float>& get_aspect_ratio_tween() const;
const tween<float4x4>& get_view_tween() const;
const tween<float4x4>& get_projection_tween() const;
const tween<float4x4>& get_view_projection_tween() const;
const tween<float>& get_exposure_tween() const;
/// @copydoc object_base::update_tweens();
virtual void update_tweens();
/// Returns the camera's up vector.
[[nodiscard]] inline const math::vector<float, 3>& get_up() const noexcept
{
return m_up;
}
/// Returns the camera's view frustum.
[[nodiscard]] inline const view_frustum_type& get_view_frustum() const noexcept
{
return m_view_frustum;
}
private:
virtual void transformed();
render::compositor* compositor;
int composite_index;
bool orthographic;
tween<float> clip_left;
tween<float> clip_right;
tween<float> clip_bottom;
tween<float> clip_top;
tween<float> clip_near;
tween<float> clip_far;
tween<float> fov;
tween<float> aspect_ratio;
tween<float4x4> view;
tween<float4x4> projection;
tween<float4x4> view_projection;
tween<float> exposure;
view_frustum_type view_frustum;
render::compositor* m_compositor{nullptr};
int m_composite_index{0};
bool m_orthographic{true};
float m_clip_left{-1.0f};
float m_clip_right{1.0f};
float m_clip_bottom{-1.0f};
float m_clip_top{1.0f};
float m_clip_near{-1.0f};
float m_clip_far{1.0f};
float m_fov{math::half_pi<float>};
float m_aspect_ratio{1.0f};
float m_exposure_value{0.0f};
float m_exposure_normalization{1.0f / 1.2f};
float4x4 m_view{float4x4::identity()};
float4x4 m_projection{float4x4::identity()};
float4x4 m_view_projection{float4x4::identity()};
math::vector<float, 3> m_forward{0.0f, 0.0f, -1.0f};
math::vector<float, 3> m_up{0.0f, 1.0f, 0.0f};
view_frustum_type m_view_frustum;
};
inline const typename object_base::bounding_volume_type& camera::get_local_bounds() const
{
/// @TODO: return local bounds, not world bounds
return view_frustum.get_bounds();
}
inline const typename object_base::bounding_volume_type& camera::get_world_bounds() const
{
return view_frustum.get_bounds();
}
inline float camera::is_orthographic() const
{
return orthographic;
}
inline float camera::get_clip_left() const
{
return clip_left[1];
}
inline float camera::get_clip_right() const
{
return clip_right[1];
}
inline float camera::get_clip_bottom() const
{
return clip_bottom[1];
}
inline float camera::get_clip_top() const
{
return clip_top[1];
}
inline float camera::get_clip_near() const
{
return clip_near[1];
}
inline float camera::get_clip_far() const
{
return clip_far[1];
}
inline float camera::get_fov() const
{
return fov[1];
}
inline float camera::get_aspect_ratio() const
{
return aspect_ratio[1];
}
inline const float4x4& camera::get_view() const
{
return view[1];
}
inline const float4x4& camera::get_projection() const
{
return projection[1];
}
inline const float4x4& camera::get_view_projection() const
{
return view_projection[1];
}
inline const typename camera::view_frustum_type& camera::get_view_frustum() const
{
return view_frustum;
}
inline float camera::get_exposure() const
{
return exposure[1];
}
inline const render::compositor* camera::get_compositor() const
{
return compositor;
}
inline render::compositor* camera::get_compositor()
{
return compositor;
}
inline int camera::get_composite_index() const
{
return composite_index;
}
inline const tween<float>& camera::get_clip_left_tween() const
{
return clip_left;
}
inline const tween<float>& camera::get_clip_right_tween() const
{
return clip_right;
}
inline const tween<float>& camera::get_clip_bottom_tween() const
{
return clip_bottom;
}
inline const tween<float>& camera::get_clip_top_tween() const
{
return clip_top;
}
inline const tween<float>& camera::get_clip_near_tween() const
{
return clip_near;
}
inline const tween<float>& camera::get_clip_far_tween() const
{
return clip_far;
}
inline const tween<float>& camera::get_fov_tween() const
{
return fov;
}
inline const tween<float>& camera::get_aspect_ratio_tween() const
{
return aspect_ratio;
}
inline const tween<float4x4>& camera::get_view_tween() const
{
return view;
}
inline const tween<float4x4>& camera::get_projection_tween() const
{
return projection;
}
inline const tween<float4x4>& camera::get_view_projection_tween() const
{
return view_projection;
}
inline const tween<float>& camera::get_exposure_tween() const
{
return exposure;
}
} // namespace scene
#endif // ANTKEEPER_SCENE_CAMERA_HPP

+ 8
- 17
src/engine/scene/collection.cpp View File

@ -18,34 +18,25 @@
*/
#include <engine/scene/collection.hpp>
#include <engine/scene/object.hpp>
namespace scene {
void collection::add_object(object_base* object)
void collection::add_object(object_base& object)
{
objects.emplace_back(object);
object_map[object->get_object_type_id()].emplace_back(object);
m_objects.emplace_back(&object);
m_object_map[object.get_object_type_id()].emplace_back(&object);
}
void collection::remove_object(object_base* object)
void collection::remove_object(const object_base& object)
{
std::erase(objects, object);
std::erase(object_map[object->get_object_type_id()], object);
std::erase(m_objects, &object);
std::erase(m_object_map[object.get_object_type_id()], &object);
}
void collection::remove_objects()
{
objects.clear();
object_map.clear();
}
void collection::update_tweens()
{
for (object_base* object: objects)
{
object->update_tweens();
}
m_objects.clear();
m_object_map.clear();
}
} // namespace scene

+ 7
- 12
src/engine/scene/collection.hpp View File

@ -20,13 +20,12 @@
#ifndef ANTKEEPER_SCENE_COLLECTION_HPP
#define ANTKEEPER_SCENE_COLLECTION_HPP
#include <engine/scene/object.hpp>
#include <vector>
#include <unordered_map>
namespace scene {
class object_base;
/**
* Collection of scene objects.
*/
@ -38,25 +37,22 @@ public:
*
* @param object Object to add.
*/
void add_object(object_base* object);
void add_object(object_base& object);
/**
* Removes an object from the collection.
*
* @param object Object to remove.
*/
void remove_object(object_base* object);
void remove_object(const object_base& object);
/// Removes all objects from the collection.
void remove_objects();
/// Updates the tweens of all objects in the collection.
void update_tweens();
/// Returns all objects in the collection.
[[nodiscard]] inline const std::vector<object_base*>& get_objects() const noexcept
{
return objects;
return m_objects;
}
/**
@ -68,13 +64,12 @@ public:
*/
[[nodiscard]] inline const std::vector<object_base*>& get_objects(std::size_t type_id) const
{
return object_map[type_id];
return m_object_map[type_id];
}
private:
std::vector<object_base*> objects;
mutable std::unordered_map<std::size_t, std::vector<object_base*>> object_map;
std::vector<object_base*> m_objects;
mutable std::unordered_map<std::size_t, std::vector<object_base*>> m_object_map;
};
} // namespace scene

+ 12
- 28
src/engine/scene/directional-light.cpp View File

@ -18,67 +18,51 @@
*/
#include <engine/scene/directional-light.hpp>
#include <engine/config.hpp>
#include <engine/math/quaternion.hpp>
#include <engine/math/interpolation.hpp>
namespace scene {
static float3 interpolate_direction(const float3& x, const float3& y, float a)
{
math::quaternion<float> q0 = math::rotation(config::global_forward, x);
math::quaternion<float> q1 = math::rotation(config::global_forward, y);
return math::normalize(math::slerp(q0, q1, a) * config::global_forward);
}
directional_light::directional_light():
direction(config::global_forward, interpolate_direction)
{
shadow_cascade_distances.resize(shadow_cascade_count);
shadow_cascade_matrices.resize(shadow_cascade_count);
}
m_shadow_cascade_distances(m_shadow_cascade_count),
m_shadow_cascade_matrices(m_shadow_cascade_count)
{}
void directional_light::set_shadow_caster(bool caster) noexcept
{
shadow_caster = caster;
m_shadow_caster = caster;
}
void directional_light::set_shadow_framebuffer(const gl::framebuffer* framebuffer) noexcept
{
shadow_framebuffer = framebuffer;
m_shadow_framebuffer = framebuffer;
}
void directional_light::set_shadow_bias(float bias) noexcept
{
shadow_bias = bias;
m_shadow_bias = bias;
}
void directional_light::set_shadow_cascade_count(unsigned int count) noexcept
{
shadow_cascade_count = count;
shadow_cascade_distances.resize(shadow_cascade_count);
shadow_cascade_matrices.resize(shadow_cascade_count);
m_shadow_cascade_count = count;
m_shadow_cascade_distances.resize(m_shadow_cascade_count);
m_shadow_cascade_matrices.resize(m_shadow_cascade_count);
}
void directional_light::set_shadow_cascade_coverage(float factor) noexcept
{
shadow_cascade_coverage = factor;
m_shadow_cascade_coverage = factor;
}
void directional_light::set_shadow_cascade_distribution(float weight) noexcept
{
shadow_cascade_distribution = weight;
}
void directional_light::update_tweens()
{
light::update_tweens();
direction.update();
m_shadow_cascade_distribution = weight;
}
void directional_light::transformed()
{
direction[1] = math::normalize(get_transform().rotation * config::global_forward);
m_direction = get_rotation() * math::vector<float, 3>{0.0f, 0.0f, -1.0f};
}
} // namespace scene

+ 41
- 28
src/engine/scene/directional-light.hpp View File

@ -41,20 +41,33 @@ public:
{
return light_type::directional;
}
/// Returns the normalized direction vector of the light.
[[nodiscard]] inline const float3& get_direction() const noexcept
[[nodiscard]] inline const math::vector<float, 3>& get_direction() const noexcept
{
return direction[1];
return m_direction;
}
inline const tween<float3>& get_direction_tween() const noexcept
/// @name Light
/// @{
/**
* Sets the illuminance of the directional light.
*
* @param illuminance Illuminance, in *lx*.
*/
inline void set_illuminance(const math::vector<float, 3>& illuminance) noexcept
{
return direction;
m_illuminance = illuminance;
}
/// @copydoc object_base::update_tweens();
void update_tweens() override;
/// Returns the illuminance of the directional light, in *lx*.
[[nodiscard]] inline const math::vector<float, 3>& get_illuminance() const noexcept
{
return m_illuminance;
}
/// @}
/// @name Shadow
/// @{
@ -104,48 +117,48 @@ public:
/// Returns `true` if the light casts shadows, `false` otherwise.
[[nodiscard]] inline bool is_shadow_caster() const noexcept
{
return shadow_caster;
return m_shadow_caster;
}
/// Returns the shadow map framebuffer, of `nullptr` if no shadow map framebuffer is set.
[[nodiscard]] inline const gl::framebuffer* get_shadow_framebuffer() const noexcept
{
return shadow_framebuffer;
return m_shadow_framebuffer;
}
/// Returns the shadow bias factor.
[[nodiscard]] inline float get_shadow_bias() const noexcept
{
return shadow_bias;
return m_shadow_bias;
}
/// Returns the number of shadow cascades.
[[nodiscard]] inline unsigned int get_shadow_cascade_count() const noexcept
{
return shadow_cascade_count;
return m_shadow_cascade_count;
}
/// Returns the shadow cascade coverage factor.
[[nodiscard]] inline float get_shadow_cascade_coverage() const noexcept
{
return shadow_cascade_coverage;
return m_shadow_cascade_coverage;
}
/// Returns the shadow cascade distribution weight.
[[nodiscard]] inline float get_shadow_cascade_distribution() const noexcept
{
return shadow_cascade_distribution;
return m_shadow_cascade_distribution;
}
/// Returns the array of shadow cascade far clipping plane distances.
/// @{
[[nodiscard]] inline const std::vector<float>& get_shadow_cascade_distances() const noexcept
{
return shadow_cascade_distances;
return m_shadow_cascade_distances;
}
[[nodiscard]] inline std::vector<float>& get_shadow_cascade_distances() noexcept
{
return shadow_cascade_distances;
return m_shadow_cascade_distances;
}
/// @}
@ -153,11 +166,11 @@ public:
/// @{
[[nodiscard]] inline const std::vector<float4x4>& get_shadow_cascade_matrices() const noexcept
{
return shadow_cascade_matrices;
return m_shadow_cascade_matrices;
}
[[nodiscard]] inline std::vector<float4x4>& get_shadow_cascade_matrices() noexcept
{
return shadow_cascade_matrices;
return m_shadow_cascade_matrices;
}
/// @}
@ -165,17 +178,17 @@ public:
private:
void transformed() override;
tween<float3> direction;
bool shadow_caster{false};
const gl::framebuffer* shadow_framebuffer{nullptr};
float shadow_bias{0.005f};
unsigned int shadow_cascade_count{4};
float shadow_cascade_coverage{1.0f};
float shadow_cascade_distribution{0.8f};
mutable std::vector<float> shadow_cascade_distances;
mutable std::vector<float4x4> shadow_cascade_matrices;
math::vector<float, 3> m_illuminance{0.0f, 0.0f, 0.0f};
math::vector<float, 3> m_direction{0.0f, 0.0f, -1.0f};
bool m_shadow_caster{false};
const gl::framebuffer* m_shadow_framebuffer{nullptr};
float m_shadow_bias{0.005f};
unsigned int m_shadow_cascade_count{4};
float m_shadow_cascade_coverage{1.0f};
float m_shadow_cascade_distribution{0.8f};
mutable std::vector<float> m_shadow_cascade_distances;
mutable std::vector<float4x4> m_shadow_cascade_matrices;
};
} // namespace scene

src/game/components/camera-component.hpp → src/engine/scene/light-type.hpp View File

@ -17,19 +17,29 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GAME_CAMERA_COMPONENT_HPP
#define ANTKEEPER_GAME_CAMERA_COMPONENT_HPP
#ifndef ANTKEEPER_SCENE_LIGHT_TYPE_HPP
#define ANTKEEPER_SCENE_LIGHT_TYPE_HPP
#include <engine/scene/camera.hpp>
#include <cstdint>
namespace scene {
/// Camera scene object component.
struct camera_component
/// Light types.
enum class light_type: std::uint8_t
{
/// Pointer to camera scene object
scene::camera* object;
/// Ambient light.
ambient,
/// Directional light.
directional,
/// Point light.
point,
/// Spot light.
spot
};
} // namespace scene
#endif // ANTKEEPER_GAME_CAMERA_COMPONENT_HPP
#endif // ANTKEEPER_SCENE_LIGHT_TYPE_HPP

+ 1
- 29
src/engine/scene/light.cpp View File

@ -22,37 +22,9 @@
namespace scene {
light::light():
local_bounds{{0.0f, 0.0f, 0.0f}, 0.0f},
world_bounds{{0.0f, 0.0f, 0.0f}, 0.0f},
color(float3{1.0f, 1.0f, 1.0f}, math::lerp<float3, float>),
intensity(1.0f, math::lerp<float, float>),
scaled_color(float3{1.0f, 1.0f, 1.0f}, math::lerp<float3, float>)
{}
void light::set_color(const float3& color)
{
this->color[1] = color;
scaled_color[1] = color * intensity[1];
}
void light::set_intensity(float intensity)
{
this->intensity[1] = intensity;
scaled_color[1] = color[1] * intensity;
}
void light::update_tweens()
{
object_base::update_tweens();
color.update();
intensity.update();
scaled_color.update();
}
void light::transformed()
{
world_bounds = {get_translation(), 0.0f};
m_bounds = {get_translation(), 0.0f};
}
} // namespace scene

+ 4
- 84
src/engine/scene/light.hpp View File

@ -22,26 +22,10 @@
#include <engine/scene/object.hpp>
#include <engine/geom/sphere.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <engine/scene/light-type.hpp>
namespace scene {
/// Light object type enumerations.
enum class light_type
{
/// Denotes an ambient light.
ambient,
/// Denotes a directional light.
directional,
/// Denotes a point light.
point,
/// Denotes a spot light.
spot
};
/**
* Abstract base class for light objects.
*/
@ -49,83 +33,19 @@ class light: public object
{
public:
typedef geom::sphere<float> sphere_type;
/// Creates a light.
light();
/// Returns an enumeration denoting the light object type.
[[nodiscard]] virtual light_type get_light_type() const noexcept = 0;
/**
* Sets the color of the light.
*
* @param color Scene-linear light color.
*/
void set_color(const float3& color);
/**
* Sets the intensity of the light.
*
* @param intensity Light intensity.
*/
void set_intensity(float intensity);
/// Returns the local-space bounding volume of the light.
inline const bounding_volume_type& get_local_bounds() const noexcept override
{
return local_bounds;
}
/// Returns the world-space bounding volume of the light.
inline const bounding_volume_type& get_world_bounds() const noexcept override
inline const bounding_volume_type& get_bounds() const noexcept override
{
return world_bounds;
return m_bounds;
}
/// Returns the light color.
[[nodiscard]] inline const float3& get_color() const noexcept
{
return color[1];
}
/// Returns the light intensity.
[[nodiscard]] inline float get_intensity() const noexcept
{
return intensity[1];
}
/// Returns the intensity-scaled light color.
[[nodiscard]] inline const float3& get_scaled_color() const noexcept
{
return scaled_color[1];
}
[[nodiscard]] inline const tween<float3>& get_color_tween() const noexcept
{
return color;
}
[[nodiscard]] inline const tween<float>& get_intensity_tween() const noexcept
{
return intensity;
}
[[nodiscard]] inline const tween<float3>& get_scaled_color_tween() const noexcept
{
return scaled_color;
}
/// @copydoc object_base::update_tweens();
virtual void update_tweens();
private:
virtual void transformed();
tween<float3> color;
tween<float> intensity;
tween<float3> scaled_color;
sphere_type local_bounds;
sphere_type world_bounds;
sphere_type m_bounds{{0.0f, 0.0f, 0.0f}, 0.0f};
};
} // namespace scene

+ 0
- 80
src/engine/scene/lod-group.cpp View File

@ -1,80 +0,0 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include <engine/scene/lod-group.hpp>
#include <engine/scene/camera.hpp>
namespace scene {
lod_group::lod_group(std::size_t level_count):
local_bounds{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}},
world_bounds{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}
{
resize(level_count);
}
lod_group::lod_group():
lod_group(1)
{}
void lod_group::resize(std::size_t level_count)
{
levels.resize(level_count);
}
std::size_t lod_group::select_lod(const camera& camera) const
{
float distance = camera.get_view_frustum().get_near().signed_distance(get_translation());
if (distance < 300.0f)
return 0;
else if (distance < 500.0f)
return 1;
else if (distance < 600.0f)
return 2;
return 3;
}
void lod_group::add_object(std::size_t level, object_base* object)
{
levels[level].push_back(object);
}
void lod_group::remove_object(std::size_t level, object_base* object)
{
levels[level].remove(object);
}
void lod_group::remove_objects(std::size_t level)
{
levels[level].clear();
}
void lod_group::update_bounds()
{
world_bounds = {get_translation(), get_translation()};
}
void lod_group::transformed()
{
update_bounds();
}
} // namespace scene

+ 0
- 131
src/engine/scene/lod-group.hpp View File

@ -1,131 +0,0 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_SCENE_LOD_GROUP_HPP
#define ANTKEEPER_SCENE_LOD_GROUP_HPP
#include <engine/scene/object.hpp>
#include <engine/geom/aabb.hpp>
#include <list>
#include <vector>
namespace scene {
class camera;
class lod_group: public object<lod_group>
{
public:
typedef geom::aabb<float> aabb_type;
/**
* Creates a LOD group.
*
* @param level_count Number of detail levels in the group.
*/
explicit lod_group(std::size_t level_count);
/// Creates a LOD group with one level of detail.
lod_group();
/**
* Resizes the LOD group to accommodate the specified number of detail levels.
*
* @param level_count Number of desired detail levels in the group.
*/
void resize(std::size_t level_count);
/**
* Selects the appropriate level of detail for a camera.
*
* @param camera Camera for which the LOD should be selected.
* @return Selected level of detail.
*/
std::size_t select_lod(const camera& camera) const;
/**
* Adds an object to the LOD group.
*
* @param level Level of detail of the object to add.
* @param object Object to add.
*/
void add_object(std::size_t level, object_base* object);
/**
* Removes an object from the LOD group.
*
* @param level Level of detail of the object to remove.
* @param object Object to remove.
*/
void remove_object(std::size_t level, object_base* object);
/**
* Removes all objects with the specified level of detail.
*
* @param level Level of detail of the objects to remove.
*/
void remove_objects(std::size_t level);
virtual const bounding_volume_type& get_local_bounds() const;
virtual const bounding_volume_type& get_world_bounds() const;
/// Returns the number of detail levels in the group.
std::size_t get_level_count() const;
/**
* Returns a list containing all objects in the LOD group with the specified detail level.
*
* @param level Level of detail.
* @return List of all objects in the group with the specified detail level.
*/
const std::list<object_base*>& get_objects(std::size_t level) const;
private:
void update_bounds();
virtual void transformed();
aabb_type local_bounds;
aabb_type world_bounds;
std::vector<std::list<object_base*>> levels;
};
inline const typename object_base::bounding_volume_type& lod_group::get_local_bounds() const
{
return local_bounds;
}
inline const typename object_base::bounding_volume_type& lod_group::get_world_bounds() const
{
return world_bounds;
}
inline std::size_t lod_group::get_level_count() const
{
return levels.size();
}
inline const std::list<object_base*>& lod_group::get_objects(std::size_t level) const
{
return levels[level];
}
} // namespace scene
#endif // ANTKEEPER_SCENE_LOD_GROUP_HPP

+ 2
- 25
src/engine/scene/object.cpp View File

@ -18,43 +18,20 @@
*/
#include <engine/scene/object.hpp>
#include <engine/math/interpolation.hpp>
namespace scene {
typename object_base::transform_type object_base::interpolate_transforms(const transform_type& x, const transform_type& y, float a)
{
return
{
math::lerp(x.translation, y.translation, a),
math::nlerp(x.rotation, y.rotation, a),
math::lerp(x.scale, y.scale, a),
};
}
object_base::object_base():
transform(math::transform<float>::identity, interpolate_transforms)
{}
std::size_t object_base::next_object_type_id()
{
static std::atomic<std::size_t> id{0};
return id++;
}
void object_base::update_tweens()
{
transform.update();
}
void object_base::look_at(const vector_type& position, const vector_type& target, const vector_type& up)
{
transform[1].translation = position;
transform[1].rotation = math::look_rotation(math::normalize(math::sub(target, position)), up);
m_transform.translation = position;
m_transform.rotation = math::look_rotation(math::normalize(math::sub(target, position)), up);
transformed();
}
void object_base::transformed()
{}
} // namespace scene

+ 24
- 54
src/engine/scene/object.hpp View File

@ -20,7 +20,6 @@
#ifndef ANTKEEPER_SCENE_OBJECT_HPP
#define ANTKEEPER_SCENE_OBJECT_HPP
#include <engine/animation/tween.hpp>
#include <engine/geom/bounding-volume.hpp>
#include <engine/math/vector.hpp>
#include <engine/math/quaternion.hpp>
@ -32,23 +31,18 @@
namespace scene {
/**
* Internal base class for scene objects.
* Abstract base class for scene objects.
*/
class object_base
{
public:
typedef math::vector<float, 3> vector_type;
typedef math::quaternion<float> quaternion_type;
typedef math::transform<float> transform_type;
typedef geom::bounding_volume<float> bounding_volume_type;
using vector_type = math::vector<float, 3>;
using quaternion_type = math::quaternion<float>;
using transform_type = math::transform<float>;
using bounding_volume_type = geom::bounding_volume<float>;
/// Returns the type ID for this scene object type.
virtual const std::size_t get_object_type_id() const noexcept = 0;
/**
* Creates a scene object base.
*/
object_base();
/**
* Adds render operations to a render context.
@ -56,18 +50,13 @@ public:
* @param ctx Render context.
*/
inline virtual void render(render::context& ctx) const {}
/**
* Updates all tweens in the scene object.
*/
virtual void update_tweens();
/**
* Activates or deactivates the scene object.
*/
inline void set_active(bool active) noexcept
{
this->active = active;
m_active = active;
}
/**
@ -80,7 +69,7 @@ public:
*/
inline void set_transform(const transform_type& transform)
{
this->transform[1] = transform;
m_transform = transform;
transformed();
}
@ -89,7 +78,7 @@ public:
*/
inline void set_translation(const vector_type& translation)
{
transform[1].translation = translation;
m_transform.translation = translation;
transformed();
}
@ -98,7 +87,7 @@ public:
*/
inline void set_rotation(const quaternion_type& rotation)
{
transform[1].rotation = rotation;
m_transform.rotation = rotation;
transformed();
}
@ -107,7 +96,7 @@ public:
*/
inline void set_scale(const vector_type& scale)
{
transform[1].scale = scale;
m_transform.scale = scale;
transformed();
}
@ -116,13 +105,13 @@ public:
*/
inline void set_culling_mask(const bounding_volume_type* culling_mask) noexcept
{
this->culling_mask = culling_mask;
m_culling_mask = culling_mask;
}
/// Returns whether the scene object is active.
[[nodiscard]] inline bool is_active() const noexcept
{
return active;
return m_active;
}
/**
@ -130,7 +119,7 @@ public:
*/
[[nodiscard]] inline const transform_type& get_transform() const noexcept
{
return transform[1];
return m_transform;
}
/**
@ -138,7 +127,7 @@ public:
*/
[[nodiscard]] inline const vector_type& get_translation() const noexcept
{
return transform[1].translation;
return m_transform.translation;
}
/**
@ -146,7 +135,7 @@ public:
*/
[[nodiscard]] inline const quaternion_type& get_rotation() const noexcept
{
return transform[1].rotation;
return m_transform.rotation;
}
/**
@ -154,39 +143,20 @@ public:
*/
[[nodiscard]] inline const vector_type& get_scale() const noexcept
{
return transform[1].scale;
}
/**
* Returns the transform tween.
*/
/// @{
[[nodiscard]] inline const tween<transform_type>& get_transform_tween() const noexcept
{
return transform;
return m_transform.scale;
}
[[nodiscard]] inline tween<transform_type>& get_transform_tween() noexcept
{
return transform;
}
/// @}
/**
* Returns the local-space (untransformed) bounds of the object.
*/
[[nodiscard]] virtual const bounding_volume_type& get_local_bounds() const = 0;
/**
* Returns the world-space (transformed) bounds of the object.
* Returns the bounds of the object.
*/
[[nodiscard]] virtual const bounding_volume_type& get_world_bounds() const = 0;
[[nodiscard]] virtual const bounding_volume_type& get_bounds() const noexcept = 0;
/**
* Returns the culling mask of the object.
*/
[[nodiscard]] inline const bounding_volume_type* get_culling_mask() const noexcept
{
return culling_mask;
return m_culling_mask;
}
protected:
@ -199,11 +169,11 @@ private:
/**
* Called every time the scene object's tranform is changed.
*/
virtual void transformed();
bool active{true};
tween<transform_type> transform;
const bounding_volume_type* culling_mask{nullptr};
inline virtual void transformed() {}
bool m_active{true};
transform_type m_transform{transform_type::identity};
const bounding_volume_type* m_culling_mask{nullptr};
};
/**

+ 0
- 14
src/engine/scene/point-light.cpp View File

@ -18,23 +18,9 @@
*/
#include <engine/scene/point-light.hpp>
#include <engine/math/interpolation.hpp>
namespace scene {
point_light::point_light():
attenuation(float3{1, 0, 0}, math::lerp<float3, float>)
{}
void point_light::set_attenuation(const float3& attenuation)
{
this->attenuation[1] = attenuation;
}
void point_light::update_tweens()
{
light::update_tweens();
attenuation.update();
}
} // namespace scene

+ 24
- 15
src/engine/scene/point-light.hpp View File

@ -21,7 +21,7 @@
#define ANTKEEPER_SCENE_POINT_LIGHT_HPP
#include <engine/scene/light.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <engine/math/vector.hpp>
namespace scene {
@ -31,40 +31,49 @@ namespace scene {
class point_light: public light
{
public:
point_light();
/// Returns light_type::point
[[nodiscard]] inline light_type get_light_type() const noexcept override
{
return light_type::point;
}
/**
* Sets the luminous flux of the point light.
*
* @param luminous_flux Luminous flux, in *lm*.
*/
inline void set_luminous_flux(const math::vector<float, 3>& luminous_flux) noexcept
{
m_luminous_flux = luminous_flux;
}
/// Returns the luminous flux of the point light, in *lm*.
[[nodiscard]] inline const math::vector<float, 3>& get_luminous_flux() const noexcept
{
return m_luminous_flux;
}
/**
* Sets the attenuation factors of the light.
*
* @param attenuation Vector containing the constant, linear, and quadratic attenuation factors, as x, y, and z, respectively.
*/
void set_attenuation(const float3& attenuation);
/// Returns the attenuation factors of the light.
[[nodiscard]] inline const float3& get_attenuation() const noexcept
inline void set_attenuation(const float3& attenuation) noexcept
{
return attenuation[1];
m_attenuation = attenuation;
}
/// Returns the attenuation tween.
[[nodiscard]] inline const tween<float3>& get_attenuation_tween() const noexcept
/// Returns the attenuation factors of the light.
[[nodiscard]] inline const math::vector<float, 3>& get_attenuation() const noexcept
{
return attenuation;
return m_attenuation;
}
void update_tweens() override;
private:
tween<float3> attenuation;
math::vector<float, 3> m_luminous_flux{0.0f, 0.0f, 0.0f};
math::vector<float, 3> m_attenuation{1.0f, 0.0f, 0.0f};
};
} // namespace scene
#endif // ANTKEEPER_SCENE_POINT_LIGHT_HPP

+ 1
- 14
src/engine/scene/scene.hpp View File

@ -20,20 +20,7 @@
#ifndef ANTKEEPER_SCENE_HPP
#define ANTKEEPER_SCENE_HPP
/// 3D scene
/// 3D scene.
namespace scene {}
#include <engine/scene/ambient-light.hpp>
#include <engine/scene/billboard.hpp>
#include <engine/scene/camera.hpp>
#include <engine/scene/collection.hpp>
#include <engine/scene/directional-light.hpp>
#include <engine/scene/light.hpp>
#include <engine/scene/lod-group.hpp>
#include <engine/scene/static-mesh.hpp>
#include <engine/scene/object.hpp>
#include <engine/scene/point-light.hpp>
#include <engine/scene/spot-light.hpp>
#include <engine/scene/text.hpp>
#endif // ANTKEEPER_SCENE_HPP

+ 4
- 35
src/engine/scene/spot-light.cpp View File

@ -18,50 +18,19 @@
*/
#include <engine/scene/spot-light.hpp>
#include <engine/config.hpp>
#include <engine/math/quaternion.hpp>
#include <engine/math/interpolation.hpp>
#include <cmath>
namespace scene {
static float3 interpolate_direction(const float3& x, const float3& y, float a)
void spot_light::set_cutoff(const math::vector<float, 2>& cutoff)
{
math::quaternion<float> q0 = math::rotation(config::global_forward, x);
math::quaternion<float> q1 = math::rotation(config::global_forward, y);
return math::normalize(math::slerp(q0, q1, a) * config::global_forward);
}
spot_light::spot_light():
direction(config::global_forward, interpolate_direction),
attenuation(float3{1, 0, 0}, math::lerp<float3, float>),
cutoff(float2{math::pi<float>, math::pi<float>}, math::lerp<float2, float>),
cosine_cutoff(float2{std::cos(math::pi<float>), std::cos(math::pi<float>)}, math::lerp<float2, float>)
{}
void spot_light::set_attenuation(const float3& attenuation)
{
this->attenuation[1] = attenuation;
}
void spot_light::set_cutoff(const float2& cutoff)
{
this->cutoff[1] = cutoff;
this->cosine_cutoff[1] = {std::cos(cutoff.x()), std::cos(cutoff.y())};
}
void spot_light::update_tweens()
{
light::update_tweens();
direction.update();
attenuation.update();
cutoff.update();
cosine_cutoff.update();
m_cutoff = cutoff;
m_cosine_cutoff = {std::cos(m_cutoff.x()), std::cos(m_cutoff.y())};
}
void spot_light::transformed()
{
direction[1] = math::normalize(get_transform().rotation * config::global_forward);
m_direction = get_transform().rotation * math::vector<float, 3>{0.0f, 0.0f, -1.0f};
}
} // namespace scene

+ 38
- 46
src/engine/scene/spot-light.hpp View File

@ -21,7 +21,8 @@
#define ANTKEEPER_SCENE_SPOT_LIGHT_HPP
#include <engine/scene/light.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <engine/math/numbers.hpp>
#include <engine/math/vector.hpp>
namespace scene {
@ -31,86 +32,77 @@ namespace scene {
class spot_light: public light
{
public:
/// Creates a spot light.
spot_light();
/// Returns light_type::spot
/// Returns light_type::spot.
[[nodiscard]] inline light_type get_light_type() const noexcept override
{
return light_type::spot;
}
/**
* Sets the luminous flux of the spot light.
*
* @param luminous_flux Luminous flux, in *lm*.
*/
inline void set_luminous_flux(const math::vector<float, 3>& luminous_flux) noexcept
{
m_luminous_flux = luminous_flux;
}
/// Returns the luminous flux of the spot light, in *lm*.
[[nodiscard]] inline const math::vector<float, 3>& get_luminous_flux() const noexcept
{
return m_luminous_flux;
}
/**
* Sets the attenuation factors of the light.
*
* @param attenuation Vector containing the constant, linear, and quadratic attenuation factors, as x, y, and z, respectively.
*/
void set_attenuation(const float3& attenuation);
inline void set_attenuation(const math::vector<float, 3>& attenuation) noexcept
{
m_attenuation = attenuation;
}
/**
* Sets the spot light cutoff angles.
*
* @param cutoff Vector containing the inner and outer cutoff angles, as x and y, respectively.
*/
void set_cutoff(const float2& cutoff);
void set_cutoff(const math::vector<float, 2>& cutoff);
/// Returns the direction vector.
[[nodiscard]] inline const float3& get_direction() const noexcept
[[nodiscard]] inline const math::vector<float, 3>& get_direction() const noexcept
{
return direction[1];
return m_direction;
}
/// Returns the attenuation factors of the light.
[[nodiscard]] inline const float3& get_attenuation() const noexcept
[[nodiscard]] inline const math::vector<float, 3>& get_attenuation() const noexcept
{
return attenuation[1];
return m_attenuation;
}
/// Returns the spot light cutoff angles.
[[nodiscard]] inline const float2& get_cutoff() const noexcept
[[nodiscard]] inline const math::vector<float, 2>& get_cutoff() const noexcept
{
return cutoff[1];
return m_cutoff;
}
/// Returns the cosine of the spot light cutoff angles.
[[nodiscard]] inline const float2& get_cosine_cutoff() const noexcept
[[nodiscard]] inline const math::vector<float, 2>& get_cosine_cutoff() const noexcept
{
return cosine_cutoff[1];
}
/// Returns the direction tween.
[[nodiscard]] inline const tween<float3>& get_direction_tween() const noexcept
{
return direction;
}
/// Returns the attenuation tween.
[[nodiscard]] inline const tween<float3>& get_attenuation_tween() const noexcept
{
return attenuation;
}
/// Returns the cutoff tween.
[[nodiscard]] inline const tween<float2>& get_cutoff_tween() const noexcept
{
return cutoff;
}
/// Returns the cosine cutoff tween.
[[nodiscard]] inline const tween<float2>& get_cosine_cutoff_tween() const noexcept
{
return cosine_cutoff;
return m_cosine_cutoff;
}
void update_tweens() override;
private:
void transformed() override;
tween<float3> direction;
tween<float3> attenuation;
tween<float2> cutoff;
tween<float2> cosine_cutoff;
math::vector<float, 3> m_luminous_flux{0.0f, 0.0f, 0.0f};
math::vector<float, 3> m_direction{0.0f, 0.0f, -1.0f};
math::vector<float, 3> m_attenuation{1.0f, 0.0f, 0.0f};
math::vector<float, 2> m_cutoff{math::pi<float>, math::pi<float>};
math::vector<float, 2> m_cosine_cutoff{-1.0f, -1.0f};
};
} // namespace scene

+ 29
- 32
src/engine/scene/static-mesh.cpp View File

@ -20,6 +20,7 @@
#include <engine/scene/static-mesh.hpp>
#include <engine/render/model.hpp>
#include <engine/render/material.hpp>
#include <engine/scene/camera.hpp>
namespace scene {
@ -30,87 +31,83 @@ static_mesh::static_mesh(std::shared_ptr model)
void static_mesh::set_model(std::shared_ptr<render::model> model)
{
this->model = model;
m_model = model;
if (model)
if (m_model)
{
operations.resize(model->get_groups().size());
for (std::size_t i = 0; i < operations.size(); ++i)
m_operations.resize(m_model->get_groups().size());
for (std::size_t i = 0; i < m_operations.size(); ++i)
{
const auto& group = model->get_groups()[i];
const auto& group = m_model->get_groups()[i];
auto& operation = operations[i];
operation.vertex_array = model->get_vertex_array().get();
auto& operation = m_operations[i];
operation.vertex_array = m_model->get_vertex_array().get();
operation.drawing_mode = group.drawing_mode;
operation.start_index = group.start_index;
operation.index_count = group.index_count;
operation.material = group.material;
}
pose = model->get_skeleton().bind_pose;
::concatenate(pose, pose);
::concatenate(m_model->get_skeleton().bind_pose, m_pose);
}
else
{
operations.clear();
pose.clear();
m_operations.clear();
m_pose.clear();
}
update_bounds();
transformed();
}
void static_mesh::set_material(std::size_t index, std::shared_ptr<render::material> material)
{
if (material)
{
operations[index].material = material;
m_operations[index].material = material;
}
else
{
operations[index].material = model->get_groups()[index].material;
m_operations[index].material = m_model->get_groups()[index].material;
}
}
void static_mesh::reset_materials()
{
for (std::size_t i = 0; i < operations.size(); ++i)
for (std::size_t i = 0; i < m_operations.size(); ++i)
{
operations[i].material = model->get_groups()[i].material;
m_operations[i].material = m_model->get_groups()[i].material;
}
}
void static_mesh::update_bounds()
{
if (model)
if (m_model)
{
local_bounds = aabb_type::transform(model->get_bounds(), get_transform());
transformed();
m_bounds = aabb_type::transform(m_model->get_bounds(), get_transform());
}
else
{
local_bounds = {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}};
world_bounds = {get_translation(), get_translation()};
m_bounds = {get_translation(), get_translation()};
}
}
void static_mesh::transformed()
{
world_bounds = aabb_type::transform(local_bounds, get_transform());
}
void static_mesh::update_tweens()
{
object_base::update_tweens();
update_bounds();
const float4x4 transform_matrix = math::matrix_cast(get_transform());
for (auto& operation: m_operations)
{
operation.transform = transform_matrix;
}
}
void static_mesh::render(render::context& ctx) const
{
const float4x4 transform = math::matrix_cast(get_transform_tween().interpolate(ctx.alpha));
for (auto& operation: operations)
const float depth = ctx.camera->get_view_frustum().get_near().signed_distance(get_translation());
for (auto& operation: m_operations)
{
operation.transform = transform;
operation.depth = ctx.clip_near.signed_distance(float3(operation.transform[3]));
operation.depth = depth;
ctx.operations.push_back(&operation);
}
}

+ 10
- 26
src/engine/scene/static-mesh.hpp View File

@ -67,20 +67,9 @@ public:
*/
void reset_materials();
/**
* Returns the local bounds of the model instance.
*/
[[nodiscard]] inline virtual const bounding_volume_type& get_local_bounds() const noexcept
{
return local_bounds;
}
/**
* Returns the world bounds of the model instance.
*/
[[nodiscard]] inline virtual const bounding_volume_type& get_world_bounds() const noexcept
[[nodiscard]] inline const bounding_volume_type& get_bounds() const noexcept override
{
return world_bounds;
return m_bounds;
}
/**
@ -88,7 +77,7 @@ public:
*/
[[nodiscard]] inline const std::shared_ptr<render::model>& get_model() const noexcept
{
return model;
return m_model;
}
/**
@ -97,29 +86,24 @@ public:
/// @{
[[nodiscard]] inline const pose& get_pose() const noexcept
{
return pose;
return m_pose;
}
[[nodiscard]] inline pose& get_pose() noexcept
{
return pose;
return m_pose;
}
/// @}
void render(render::context& ctx) const override;
void update_tweens() override;
void update_bounds();
private:
void update_bounds();
void transformed() override;
std::shared_ptr<render::model> model;
mutable std::vector<render::operation> operations;
::pose pose;
aabb_type local_bounds{{0, 0, 0}, {0, 0, 0}};
aabb_type world_bounds{{0, 0, 0}, {0, 0, 0}};
std::shared_ptr<render::model> m_model;
mutable std::vector<render::operation> m_operations;
::pose m_pose;
aabb_type m_bounds{{0, 0, 0}, {0, 0, 0}};
};
} // namespace scene

+ 66
- 92
src/engine/scene/text.cpp View File

@ -20,77 +20,66 @@
#include <engine/scene/text.hpp>
#include <engine/render/vertex-attribute.hpp>
#include <engine/type/unicode/convert.hpp>
#include <engine/scene/camera.hpp>
#include <cstddef>
namespace scene {
text::text():
local_bounds{{0, 0, 0}, {0, 0, 0}},
world_bounds{{0, 0, 0}, {0, 0, 0}},
font(nullptr),
direction(type::text_direction::ltr),
content_u8(std::string()),
content_u32(std::u32string()),
color({0.0f, 0.0f, 0.0f, 1.0f}),
vertex_stride(0),
vertex_count(0),
vao(nullptr),
vbo(nullptr)
text::text()
{
// Allocate VBO and VAO
vbo = std::make_unique<gl::vertex_buffer>();
vao = std::make_unique<gl::vertex_array>();
m_vbo = std::make_unique<gl::vertex_buffer>();
m_vao = std::make_unique<gl::vertex_array>();
// Calculate vertex stride
vertex_stride = (3 + 2 + 4) * sizeof(float);
m_vertex_stride = (3 + 2 + 4) * sizeof(float);
// Init vertex attribute offset
std::size_t attribute_offset = 0;
// Define vertex position attribute
gl::vertex_attribute position_attribute;
position_attribute.buffer = vbo.get();
position_attribute.buffer = m_vbo.get();
position_attribute.offset = attribute_offset;
position_attribute.stride = vertex_stride;
position_attribute.stride = m_vertex_stride;
position_attribute.type = gl::vertex_attribute_type::float_32;
position_attribute.components = 3;
attribute_offset += position_attribute.components * sizeof(float);
// Define vertex UV attribute
gl::vertex_attribute uv_attribute;
uv_attribute.buffer = vbo.get();
uv_attribute.buffer = m_vbo.get();
uv_attribute.offset = attribute_offset;
uv_attribute.stride = vertex_stride;
uv_attribute.stride = m_vertex_stride;
uv_attribute.type = gl::vertex_attribute_type::float_32;
uv_attribute.components = 2;
attribute_offset += uv_attribute.components * sizeof(float);
// Define vertex color attribute
gl::vertex_attribute color_attribute;
color_attribute.buffer = vbo.get();
color_attribute.buffer = m_vbo.get();
color_attribute.offset = attribute_offset;
color_attribute.stride = vertex_stride;
color_attribute.stride = m_vertex_stride;
color_attribute.type = gl::vertex_attribute_type::float_32;
color_attribute.components = 4;
//attribute_offset += color_attribute.components * sizeof(float);
// Bind vertex attributes to VAO
vao->bind(render::vertex_attribute::position, position_attribute);
vao->bind(render::vertex_attribute::uv, uv_attribute);
vao->bind(render::vertex_attribute::color, color_attribute);
m_vao->bind(render::vertex_attribute::position, position_attribute);
m_vao->bind(render::vertex_attribute::uv, uv_attribute);
m_vao->bind(render::vertex_attribute::color, color_attribute);
// Init render operation
render_op.vertex_array = vao.get();
render_op.drawing_mode = gl::drawing_mode::triangles;
m_render_op.vertex_array = m_vao.get();
m_render_op.drawing_mode = gl::drawing_mode::triangles;
}
void text::render(render::context& ctx) const
{
if (vertex_count)
if (m_vertex_count)
{
render_op.transform = math::matrix_cast(get_transform_tween().interpolate(ctx.alpha));
render_op.depth = ctx.clip_near.signed_distance(math::vector<float, 3>(render_op.transform[3]));
ctx.operations.push_back(&render_op);
m_render_op.depth = ctx.camera->get_view_frustum().get_near().signed_distance(get_translation());
ctx.operations.push_back(&m_render_op);
}
}
@ -101,112 +90,96 @@ void text::refresh()
void text::set_material(std::shared_ptr<render::material> material)
{
render_op.material = material;
m_render_op.material = material;
}
void text::set_font(const type::bitmap_font* font)
{
if (this->font != font)
if (m_font != font)
{
this->font = font;
// Update text in VBO
m_font = font;
update_content();
}
}
void text::set_direction(type::text_direction direction)
{
if (this->direction != direction)
if (m_direction != direction)
{
this->direction = direction;
// Update text in VBO
m_direction = direction;
update_content();
}
}
void text::set_content(const std::string& content)
{
// If content has changed
if (content_u8 != content)
if (m_content_u8 != content)
{
// Update UTF-8 content
content_u8 = content;
// Convert UTF-8 content to UTF-32
content_u32 = type::unicode::u32(content_u8);
// Update text in VBO
m_content_u8 = content;
m_content_u32 = type::unicode::u32(m_content_u8);
update_content();
}
}
void text::set_color(const float4& color)
{
this->color = color;
// Update color in VBO
m_color = color;
update_color();
}
void text::transformed()
{
world_bounds = aabb_type::transform(local_bounds, get_transform());
}
void text::update_tweens()
{
object_base::update_tweens();
m_world_bounds = aabb_type::transform(m_local_bounds, get_transform());
m_render_op.transform = math::matrix_cast(get_transform());
}
void text::update_content()
{
// If no valid font or no text, clear vertex count
if (!font || content_u32.empty())
if (!m_font || m_content_u32.empty())
{
vertex_count = 0;
render_op.index_count = vertex_count;
local_bounds = {{0, 0, 0}, {0, 0, 0}};
m_vertex_count = 0;
m_render_op.index_count = 0;
m_local_bounds = {{0, 0, 0}, {0, 0, 0}};
transformed();
return;
}
// Calculate new vertex count and minimum vertex buffer size
std::size_t vertex_count = content_u32.length() * 6;
std::size_t min_vertex_buffer_size = vertex_count * vertex_stride;
std::size_t vertex_count = m_content_u32.length() * 6;
std::size_t min_vertex_buffer_size = vertex_count * m_vertex_stride;
// Expand vertex data buffer to accommodate vertices
if (vertex_data.size() < min_vertex_buffer_size)
if (m_vertex_data.size() < min_vertex_buffer_size)
{
vertex_data.resize(min_vertex_buffer_size);
m_vertex_data.resize(min_vertex_buffer_size);
}
// Get font metrics and bitmap
const type::font_metrics& font_metrics = font->get_font_metrics();
const image& font_bitmap = font->get_bitmap();
const type::font_metrics& font_metrics = m_font->get_font_metrics();
const image& font_bitmap = m_font->get_bitmap();
// Init pen position
float2 pen_position = {0.0f, 0.0f};
// Reset local-space bounds
local_bounds = {{0, 0, 0}, {0, 0, 0}};
m_local_bounds = {{0, 0, 0}, {0, 0, 0}};
// Generate vertex data
char32_t previous_code = 0;
float* v = reinterpret_cast<float*>(vertex_data.data());
for (char32_t code: content_u32)
float* v = reinterpret_cast<float*>(m_vertex_data.data());
for (char32_t code: m_content_u32)
{
// Apply kerning
if (previous_code)
{
pen_position.x() += font->get_kerning(previous_code, code).x();
pen_position.x() += m_font->get_kerning(previous_code, code).x();
}
if (font->contains(code))
if (m_font->contains(code))
{
// Get glyph
const type::bitmap_glyph& glyph = font->get_glyph(code);
const type::bitmap_glyph& glyph = m_font->get_glyph(code);
// Calculate vertex positions
float2 positions[6];
@ -245,10 +218,10 @@ void text::update_content()
*(v++) = 0.0f;
*(v++) = uvs[i].x();
*(v++) = uvs[i].y();
*(v++) = color[0];
*(v++) = color[1];
*(v++) = color[2];
*(v++) = color[3];
*(v++) = m_color[0];
*(v++) = m_color[1];
*(v++) = m_color[2];
*(v++) = m_color[3];
}
// Advance pen position
@ -260,8 +233,8 @@ void text::update_content()
const float2& position = positions[i];
for (int j = 0; j < 2; ++j)
{
local_bounds.min_point[j] = std::min<float>(local_bounds.min_point[j], position[j]);
local_bounds.max_point[j] = std::max<float>(local_bounds.max_point[j], position[j]);
m_local_bounds.min_point[j] = std::min<float>(m_local_bounds.min_point[j], position[j]);
m_local_bounds.max_point[j] = std::max<float>(m_local_bounds.max_point[j], position[j]);
}
}
}
@ -269,7 +242,9 @@ void text::update_content()
{
// Glyph not in font, zero vertex data
for (std::size_t i = 0; i < (6 * 9); ++i)
{
*(v++) = 0.0f;
}
}
// Handle newlines
@ -284,19 +259,18 @@ void text::update_content()
}
// Resize VBO, if necessary, and upload vertex data
if (vertex_count > this->vertex_count)
if (vertex_count > m_vertex_count)
{
this->vertex_count = vertex_count;
vbo->resize(min_vertex_buffer_size, vertex_data);
m_vbo->resize(min_vertex_buffer_size, m_vertex_data);
}
else
{
vbo->write({vertex_data.data(), min_vertex_buffer_size});
m_vbo->write({m_vertex_data.data(), min_vertex_buffer_size});
}
// Update vertex count
this->vertex_count = vertex_count;
render_op.index_count = vertex_count;
m_vertex_count = vertex_count;
m_render_op.index_count = vertex_count;
// Update world-space bounds
transformed();
@ -304,21 +278,21 @@ void text::update_content()
void text::update_color()
{
float* v = reinterpret_cast<float*>(vertex_data.data());
for (std::size_t i = 0; i < vertex_count; ++i)
float* v = reinterpret_cast<float*>(m_vertex_data.data());
for (std::size_t i = 0; i < m_vertex_count; ++i)
{
// Skip vertex position (vec3) and vertex UV (vec2)
v += (3 + 2);
// Update vertex color
*(v++) = color[0];
*(v++) = color[1];
*(v++) = color[2];
*(v++) = color[3];
*(v++) = m_color[0];
*(v++) = m_color[1];
*(v++) = m_color[2];
*(v++) = m_color[3];
}
// Update VBO
vbo->write({vertex_data.data(), vertex_count * vertex_stride});
m_vbo->write({m_vertex_data.data(), m_vertex_count * m_vertex_stride});
}
} // namespace scene

+ 39
- 63
src/engine/scene/text.hpp View File

@ -37,7 +37,7 @@ namespace scene {
class text: public object<text>
{
public:
typedef geom::aabb<float> aabb_type;
using aabb_type = geom::aabb<float>;
/// Constructs a text object.
text();
@ -87,28 +87,39 @@ public:
void set_color(const float4& color);
/// Returns the text material.
std::shared_ptr<render::material> get_material() const;
[[nodiscard]] inline std::shared_ptr<render::material> get_material() const noexcept
{
return m_render_op.material;
}
/// Returns the text font.
const type::bitmap_font* get_font() const;
[[nodiscard]] inline const type::bitmap_font* get_font() const noexcept
{
return m_font;
}
/// Returns the text direction.
const type::text_direction& get_direction() const;
[[nodiscard]] inline const type::text_direction& get_direction() const noexcept
{
return m_direction;
}
/// Returns the text content.
const std::string& get_content() const;
[[nodiscard]] inline const std::string& get_content() const noexcept
{
return m_content_u8;
}
/// Returns the text color.
const float4& get_color() const;
/// @copydoc scene::object::get_local_bounds() const
virtual const bounding_volume_type& get_local_bounds() const;
/// @copydoc scene::object::get_world_bounds() const
virtual const bounding_volume_type& get_world_bounds() const;
/// @copydoc scene::object::update_tweens()
virtual void update_tweens();
[[nodiscard]] inline const float4& get_color() const noexcept
{
return m_color;
}
[[nodiscard]] inline virtual const bounding_volume_type& get_bounds() const noexcept
{
return m_world_bounds;
}
private:
void update_content();
@ -116,56 +127,21 @@ private:
virtual void transformed();
mutable render::operation render_op;
aabb_type local_bounds;
aabb_type world_bounds;
const type::bitmap_font* font;
type::text_direction direction;
std::string content_u8;
std::u32string content_u32;
float4 color;
std::size_t vertex_stride;
std::size_t vertex_count;
std::vector<std::byte> vertex_data;
std::unique_ptr<gl::vertex_array> vao;
std::unique_ptr<gl::vertex_buffer> vbo;
mutable render::operation m_render_op;
aabb_type m_local_bounds{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}};
aabb_type m_world_bounds{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}};
const type::bitmap_font* m_font{nullptr};
type::text_direction m_direction{type::text_direction::ltr};
std::string m_content_u8;
std::u32string m_content_u32;
float4 m_color{1.0f, 0.0f, 1.0f, 1.0f};
std::size_t m_vertex_stride{0};
std::size_t m_vertex_count{0};
std::vector<std::byte> m_vertex_data;
std::unique_ptr<gl::vertex_array> m_vao;
std::unique_ptr<gl::vertex_buffer> m_vbo;
};
inline std::shared_ptr<render::material> text::get_material() const
{
return render_op.material;
}
inline const type::bitmap_font* text::get_font() const
{
return font;
}
inline const type::text_direction& text::get_direction() const
{
return direction;
}
inline const std::string& text::get_content() const
{
return content_u8;
}
inline const float4& text::get_color() const
{
return color;
}
inline const typename object_base::bounding_volume_type& text::get_local_bounds() const
{
return local_bounds;
}
inline const typename object_base::bounding_volume_type& text::get_world_bounds() const
{
return world_bounds;
}
} // namespace scene
#endif // ANTKEEPER_SCENE_TEXT_HPP

+ 1
- 2
src/game/ant/ant-swarm.cpp View File

@ -28,6 +28,7 @@
#include <engine/resources/resource-manager.hpp>
#include <engine/math/quaternion.hpp>
#include <engine/math/angles.hpp>
#include <engine/scene/static-mesh.hpp>
#include <engine/config.hpp>
#include <cmath>
#include <random>
@ -65,7 +66,6 @@ entity::id create_ant_swarm(::game& ctx)
::transform_component transform;
transform.local = math::transform<float>::identity;
transform.world = transform.local;
transform.warp = true;
// Init picking component
::picking_component picking;
@ -77,7 +77,6 @@ entity::id create_ant_swarm(::game& ctx)
entity::id swarm_eid = ctx.entity_registry->create();
transform.local.translation = swarm_center;
transform.world = transform.local;
transform.warp = true;
ctx.entity_registry->emplace<::transform_component>(swarm_eid, transform);
// Load male model

+ 2
- 4
src/game/commands/commands.cpp View File

@ -86,7 +86,6 @@ void warp_to(entity::registry& registry, entity::id eid, const float3& position)
[&position](auto& transform)
{
transform.local.translation = position;
transform.warp = true;
}
);
}
@ -108,7 +107,7 @@ void set_scale(entity::registry& registry, entity::id eid, const float3& scale)
}
}
void set_transform(entity::registry& registry, entity::id eid, const math::transform<float>& transform, bool warp)
void set_transform(entity::registry& registry, entity::id eid, const math::transform<float>& transform)
{
const ::transform_component* transform_component = registry.try_get<::transform_component>(eid);
if (transform_component)
@ -116,10 +115,9 @@ void set_transform(entity::registry& registry, entity::id eid, const math::trans
registry.patch<::transform_component>
(
eid,
[&other_transform = transform, warp](auto& transform)
[&other_transform = transform](auto& transform)
{
transform.local = other_transform;
transform.warp = warp;
}
);
}

+ 1
- 1
src/game/commands/commands.hpp View File

@ -34,7 +34,7 @@ void rotate(entity::registry& registry, entity::id eid, float angle, const float
void move_to(entity::registry& registry, entity::id eid, const float3& position);
void warp_to(entity::registry& registry, entity::id eid, const float3& position);
void set_scale(entity::registry& registry, entity::id eid, const float3& scale);
void set_transform(entity::registry& registry, entity::id eid, const math::transform<float>& transform, bool warp = false);
void set_transform(entity::registry& registry, entity::id eid, const math::transform<float>& transform);
void place(entity::registry& registry, entity::id eid, entity::id celestial_body_id, double altitude, double latitude, double longitude);
void assign_render_layers(entity::registry& registry, entity::id eid, unsigned int layers);
math::transform<float> get_local_transform(entity::registry& registry, entity::id eid);

+ 2
- 2
src/game/components/scene-component.hpp View File

@ -26,8 +26,8 @@
struct scene_component
{
std::unique_ptr<scene::object_base> object;
std::uint8_t layer_mask{0b11111111};
std::shared_ptr<scene::object_base> object;
std::uint8_t layer_mask{0b00000001};
};
#endif // ANTKEEPER_GAME_SCENE_COMPONENT_HPP

+ 0
- 2
src/game/components/transform-component.hpp View File

@ -27,9 +27,7 @@ struct transform_component
{
math::transform<float> local;
math::transform<float> world;
bool warp;
};
#endif // ANTKEEPER_GAME_TRANSFORM_COMPONENT_HPP

+ 2
- 2
src/game/controls.cpp View File

@ -416,7 +416,7 @@ void enable_menu_controls(::game& ctx)
{
auto [name, value] = ctx.menu_item_texts[i];
const auto& name_bounds = static_cast<const geom::aabb<float>&>(name->get_world_bounds());
const auto& name_bounds = static_cast<const geom::aabb<float>&>(name->get_bounds());
float min_x = name_bounds.min_point.x();
float min_y = name_bounds.min_point.y();
float max_x = name_bounds.max_point.x();
@ -424,7 +424,7 @@ void enable_menu_controls(::game& ctx)
if (value)
{
const auto& value_bounds = static_cast<const geom::aabb<float>&>(value->get_world_bounds());
const auto& value_bounds = static_cast<const geom::aabb<float>&>(value->get_bounds());
min_x = std::min<float>(min_x, value_bounds.min_point.x());
min_y = std::min<float>(min_y, value_bounds.min_point.y());
max_x = std::max<float>(max_x, value_bounds.max_point.x());

+ 13
- 27
src/game/game.cpp View File

@ -802,27 +802,19 @@ void game::setup_scenes()
surface_scene = std::make_unique<scene::collection>();
// Setup surface camera
surface_camera = std::make_unique<scene::camera>();
surface_camera = std::make_shared<scene::camera>();
surface_camera->set_perspective(math::radians<float>(45.0f), viewport_aspect_ratio, 0.1f, 5000.0f);
surface_camera->set_compositor(surface_compositor.get());
surface_camera->set_composite_index(0);
surface_camera->set_active(false);
// Add surface scene objects to surface scene
surface_scene->add_object(surface_camera.get());
// Setup underground scene
underground_scene = std::make_unique<scene::collection>();
// Setup underground camera
underground_camera = std::make_unique<scene::camera>();
underground_camera = std::make_shared<scene::camera>();
underground_camera->set_perspective(math::radians<float>(45.0f), viewport_aspect_ratio, 0.1f, 1000.0f);
underground_camera->set_compositor(underground_compositor.get());
underground_camera->set_composite_index(0);
underground_camera->set_active(false);
// Add underground scene objects to underground scene
underground_scene->add_object(underground_camera.get());
// Clear active scene
active_scene = nullptr;
@ -891,7 +883,6 @@ void game::setup_ui()
const float clip_far = 100.0f;
ui_camera->set_orthographic(clip_left, clip_right, clip_top, clip_bottom, clip_near, clip_far);
ui_camera->look_at({0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 0.0f});
ui_camera->update_tweens();
// Menu BG material
menu_bg_material = std::make_shared<render::material>();
@ -906,7 +897,6 @@ void game::setup_ui()
menu_bg_billboard->set_material(menu_bg_material);
menu_bg_billboard->set_scale({std::ceil(viewport_size.x() * 0.5f), std::ceil(viewport_size.y() * 0.5f), 1.0f});
menu_bg_billboard->set_translation({std::floor(viewport_size.x() * 0.5f), std::floor(viewport_size.y() * 0.5f), -100.0f});
menu_bg_billboard->update_tweens();
// Create fade transition
fade_transition = std::make_unique<screen_transition>();
@ -914,7 +904,6 @@ void game::setup_ui()
fade_transition_color = std::make_shared<render::material_float3>(1, float3{0, 0, 0});
fade_transition->get_material()->set_variable("color", fade_transition_color);
fade_transition->get_billboard()->set_translation({0, 0, 98});
fade_transition->get_billboard()->update_tweens();
// Create inner radial transition
radial_transition_inner = std::make_unique<screen_transition>();
@ -943,10 +932,9 @@ void game::setup_ui()
(
[&, menu_bg_tint]()
{
ui_scene->add_object(menu_bg_billboard.get());
ui_scene->add_object(*menu_bg_billboard);
menu_bg_tint->set(float4{0.0f, 0.0f, 0.0f, 0.0f});
//menu_bg_tint->update_tweens();
menu_bg_billboard->set_active(true);
}
);
@ -964,7 +952,7 @@ void game::setup_ui()
(
[&]()
{
ui_scene->remove_object(menu_bg_billboard.get());
ui_scene->remove_object(*menu_bg_billboard);
menu_bg_billboard->set_active(false);
}
);
@ -972,8 +960,8 @@ void game::setup_ui()
}
// Add UI scene objects to UI scene
ui_scene->add_object(ui_camera.get());
ui_scene->add_object(fade_transition->get_billboard());
ui_scene->add_object(*ui_camera);
ui_scene->add_object(*fade_transition->get_billboard());
// Add UI animations to animator
animator->add_animation(fade_transition->get_animation());
@ -1017,7 +1005,6 @@ void game::setup_ui()
// Re-align debug text
frame_time_text->set_translation({std::round(0.0f), std::round(viewport_size.y() - debug_font.get_font_metrics().size), 99.0f});
frame_time_text->update_tweens();
// Re-align menu text
::menu::align_text(*this);
@ -1186,9 +1173,8 @@ void game::setup_debugging()
frame_time_text->set_color({1.0f, 1.0f, 0.0f, 1.0f});
frame_time_text->set_font(&debug_font);
frame_time_text->set_translation({std::round(0.0f), std::round(viewport_size.y() - debug_font.get_font_metrics().size), 99.0f});
frame_time_text->update_tweens();
ui_scene->add_object(frame_time_text.get());
ui_scene->add_object(*frame_time_text);
}
void game::setup_timing()
@ -1241,9 +1227,6 @@ void game::fixed_update(::frame_scheduler::duration_type fixed_update_time, ::fr
// Update tweens
sky_pass->update_tweens();
surface_scene->update_tweens();
underground_scene->update_tweens();
ui_scene->update_tweens();
// Process window events
window_manager->update();
@ -1290,12 +1273,15 @@ void game::variable_update(::frame_scheduler::duration_type fixed_update_time, :
// Update frame rate display
frame_time_text->set_content(std::format("{:5.02f}ms / {:5.02f} FPS", average_frame_ms, average_frame_fps));
// Process input events
input_manager->update();
// Interpolate physics
physics_system->interpolate(alpha);
// Render
render_system->draw(alpha);
window->swap_buffers();
// Process input events
input_manager->update();
}
void game::execute()

+ 10
- 3
src/game/game.hpp View File

@ -42,13 +42,20 @@
#include <engine/render/anti-aliasing-method.hpp>
#include <engine/render/material-variable.hpp>
#include <engine/render/material.hpp>
#include <engine/scene/scene.hpp>
#include <engine/type/bitmap-font.hpp>
#include <engine/type/typeface.hpp>
#include <engine/utility/dict.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <engine/utility/state-machine.hpp>
#include <engine/utility/frame-scheduler.hpp>
#include <engine/scene/text.hpp>
#include <engine/scene/directional-light.hpp>
#include <engine/scene/spot-light.hpp>
#include <engine/scene/ambient-light.hpp>
#include <engine/scene/camera.hpp>
#include <engine/scene/billboard.hpp>
#include <engine/scene/collection.hpp>
#include <engine/scene/text.hpp>
#include <engine/math/angles.hpp>
#include <entt/entt.hpp>
#include <filesystem>
@ -312,9 +319,9 @@ public:
// Scene
std::unique_ptr<scene::collection> surface_scene;
std::unique_ptr<scene::camera> surface_camera;
std::shared_ptr<scene::camera> surface_camera;
std::unique_ptr<scene::collection> underground_scene;
std::unique_ptr<scene::camera> underground_camera;
std::shared_ptr<scene::camera> underground_camera;
std::unique_ptr<scene::ambient_light> underground_ambient_light;
std::unique_ptr<scene::spot_light> flashlight_spot_light;

+ 1
- 2
src/game/loaders/entity-archetype-loader.cpp View File

@ -204,7 +204,7 @@ static bool load_component_model(entity::archetype& archetype, resource_manager&
{
handle.emplace_or_replace<scene_component>
(
std::make_unique<scene::static_mesh>(model),
std::make_shared<scene::static_mesh>(model),
std::uint8_t{0b00000001}
);
}
@ -242,7 +242,6 @@ static bool load_component_transform(entity::archetype& archetype, const json& e
{
::transform_component component;
component.local = math::transform<float>::identity;
component.warp = true;
if (element.contains("translation"))
{

+ 8
- 20
src/game/menu.cpp View File

@ -72,16 +72,6 @@ void update_text_color(::game& ctx)
}
}
void update_text_tweens(::game& ctx)
{
for (auto [name, value]: ctx.menu_item_texts)
{
name->update_tweens();
if (value)
value->update_tweens();
}
}
void align_text(::game& ctx, bool center, bool has_back, float anchor_y)
{
@ -102,13 +92,13 @@ void align_text(::game& ctx, bool center, bool has_back, float anchor_y)
float row_width = 0.0f;
// Add name width to row width
const auto& name_bounds = static_cast<const geom::aabb<float>&>(name->get_local_bounds());
const auto& name_bounds = static_cast<const geom::aabb<float>&>(name->get_bounds());
row_width += name_bounds.max_point.x() - name_bounds.min_point.x();
if (value)
{
// Add value width to row width
const auto& value_bounds = static_cast<const geom::aabb<float>&>(value->get_local_bounds());
const auto& value_bounds = static_cast<const geom::aabb<float>&>(value->get_bounds());
row_width += value_bounds.max_point.x() - value_bounds.min_point.x();
// Add column spacing to row width
@ -143,7 +133,7 @@ void align_text(::game& ctx, bool center, bool has_back, float anchor_y)
if (center || i == ctx.menu_item_texts.size() - 1)
{
const auto& name_bounds = static_cast<const geom::aabb<float>&>(name->get_local_bounds());
const auto& name_bounds = static_cast<const geom::aabb<float>&>(name->get_bounds());
const float name_width = name_bounds.max_point.x() - name_bounds.min_point.x();
x = viewport_center.x() - name_width * 0.5f;
}
@ -152,7 +142,7 @@ void align_text(::game& ctx, bool center, bool has_back, float anchor_y)
if (value)
{
const auto& value_bounds = static_cast<const geom::aabb<float>&>(value->get_local_bounds());
const auto& value_bounds = static_cast<const geom::aabb<float>&>(value->get_bounds());
const float value_width = value_bounds.max_point.x() - value_bounds.min_point.x();
if (center || i == ctx.menu_item_texts.size() - 1)
@ -179,9 +169,9 @@ void add_text_to_ui(::game& ctx)
{
for (auto [name, value]: ctx.menu_item_texts)
{
ctx.ui_scene->add_object(name);
ctx.ui_scene->add_object(*name);
if (value)
ctx.ui_scene->add_object(value);
ctx.ui_scene->add_object(*value);
}
}
@ -189,9 +179,9 @@ void remove_text_from_ui(::game& ctx)
{
for (auto [name, value]: ctx.menu_item_texts)
{
ctx.ui_scene->remove_object(name);
ctx.ui_scene->remove_object(*name);
if (value)
ctx.ui_scene->remove_object(value);
ctx.ui_scene->remove_object(*value);
}
}
@ -261,12 +251,10 @@ void fade_in(::game& ctx, const std::function& end_callback)
if (name)
{
name->set_color(color);
name->update_tweens();
}
if (value)
{
value->set_color(color);
value->update_tweens();
}
}

+ 0
- 1
src/game/menu.hpp View File

@ -42,7 +42,6 @@ void fade_out_bg(::game& ctx);
void update_text_color(::game& ctx);
void update_text_font(::game& ctx);
void update_text_tweens(::game& ctx);
void align_text(::game& ctx, bool center = false, bool has_back = true, float anchor_y = 0.0f);
void refresh_text(::game& ctx);
void add_text_to_ui(::game& ctx);

+ 1
- 3
src/game/spawn.cpp View File

@ -20,7 +20,7 @@
#include "game/spawn.hpp"
#include "game/components/transform-component.hpp"
#include "game/components/scene-component.hpp"
#include <engine/scene/static-mesh.hpp>
entity::id spawn_ant_egg(::game& ctx, const ant_genome& genome, bool fertilized, const float3& position)
{
@ -32,7 +32,6 @@ entity::id spawn_ant_egg(::game& ctx, const ant_genome& genome, bool fertilized,
transform_component.local = math::transform<float>::identity;
transform_component.local.translation = position;
transform_component.world = transform_component.local;
transform_component.warp = true;
ctx.entity_registry->emplace<::transform_component>(egg_eid, transform_component);
// Construct scene component
@ -51,7 +50,6 @@ entity::id spawn_ant_larva(::game& ctx, const ant_genome& genome, const float3&
transform_component.local = math::transform<float>::identity;
transform_component.local.translation = position;
transform_component.world = transform_component.local;
transform_component.warp = true;
ctx.entity_registry->emplace<::transform_component>(larva_eid, transform_component);
// Construct scene component

+ 2
- 7
src/game/states/collection-menu-state.cpp View File

@ -45,7 +45,6 @@ collection_menu_state::collection_menu_state(::game& ctx):
box_material->set_blend_mode(render::material_blend_mode::translucent);
box_material->set_shader_template(ctx.resource_manager->load<gl::shader_template>("ui-element-untextured.glsl"));
box_material->set_variable("tint", std::make_shared<render::material_float4>(1, float4{0.5f, 0.5f, 0.5f, 1}));
//box_material.update_tweens();
// Construct box billboard
box_billboard.set_material(box_material);
@ -55,14 +54,13 @@ collection_menu_state::collection_menu_state(::game& ctx):
selection_material->set_blend_mode(render::material_blend_mode::translucent);
selection_material->set_shader_template(ctx.resource_manager->load<gl::shader_template>("ui-element-untextured.glsl"));
box_material->set_variable("tint", std::make_shared<render::material_float4>(1, float4{1, 1, 1, 1}));
//selection_material.update_tweens();
// Construct selection billboard
selection_billboard.set_material(selection_material);
// Add box and selection billboard to UI scene
ctx.ui_scene->add_object(&box_billboard);
ctx.ui_scene->add_object(&selection_billboard);
ctx.ui_scene->add_object(box_billboard);
ctx.ui_scene->add_object(selection_billboard);
row_count = 64;
column_count = 6;
@ -107,7 +105,6 @@ collection_menu_state::collection_menu_state(::game& ctx):
0.0f
}
);
selection_billboard.update_tweens();
debug::log::debug("selected colony: ({}, {})", selected_column, selected_row);
}
@ -161,7 +158,6 @@ void collection_menu_state::resize_box()
// Resize box
box_billboard.set_scale({box_size.x() * 0.5f, box_size.y() * 0.5f, 1.0f});
box_billboard.set_translation({box_center.x(), box_center.y(), -1.0f});
box_billboard.update_tweens();
// Resize selection
selection_billboard.set_scale({selection_size * 0.5f, selection_size * 0.5f, 1.0f});
@ -173,5 +169,4 @@ void collection_menu_state::resize_box()
0.0f
}
);
selection_billboard.update_tweens();
}

+ 0
- 1
src/game/states/controls-menu-state.cpp View File

@ -56,7 +56,6 @@ controls_menu_state::controls_menu_state(::game& ctx):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx, true);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);

+ 4
- 6
src/game/states/credits-state.cpp View File

@ -46,11 +46,10 @@ credits_state::credits_state(::game& ctx):
credits_text.set_content(get_string(ctx, "credits"));
// Align credits text
const auto& credits_aabb = static_cast<const geom::aabb<float>&>(credits_text.get_local_bounds());
const auto& credits_aabb = static_cast<const geom::aabb<float>&>(credits_text.get_bounds());
float credits_w = credits_aabb.max_point.x() - credits_aabb.min_point.x();
float credits_h = credits_aabb.max_point.y() - credits_aabb.min_point.y();
credits_text.set_translation({std::round(viewport_center.x() - credits_w * 0.5f), std::round(viewport_center.y() - credits_h * 0.5f), 0.0f});
credits_text.update_tweens();
// Set up animation timing configuration
const float credits_fade_in_duration = 0.5;
@ -81,11 +80,10 @@ credits_state::credits_state(::game& ctx):
{
const vec2 viewport_size = vec2(event.window->get_viewport_size());
const vec2 viewport_center = viewport_size * 0.5f;
const auto& credits_aabb = static_cast<const geom::aabb<float>&>(credits_text.get_local_bounds());
const auto& credits_aabb = static_cast<const geom::aabb<float>&>(credits_text.get_bounds());
float credits_w = credits_aabb.max_point.x() - credits_aabb.min_point.x();
float credits_h = credits_aabb.max_point.y() - credits_aabb.min_point.y();
credits_text.set_translation({std::round(viewport_center.x() - credits_w * 0.5f), std::round(viewport_center.y() - credits_h * 0.5f), 0.0f});
credits_text.update_tweens();
}
);
@ -135,7 +133,7 @@ credits_state::credits_state(::game& ctx):
}
);
ctx.ui_scene->add_object(&credits_text);
ctx.ui_scene->add_object(credits_text);
debug::log::trace("Entered credits state");
}
@ -149,7 +147,7 @@ credits_state::~credits_state()
input_mapped_subscriptions.clear();
// Destruct credits text
ctx.ui_scene->remove_object(&credits_text);
ctx.ui_scene->remove_object(credits_text);
// Destruct credits animations
ctx.animator->remove_animation(&credits_fade_in_animation);

+ 0
- 1
src/game/states/extras-menu-state.cpp View File

@ -53,7 +53,6 @@ extras_menu_state::extras_menu_state(::game& ctx):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);

+ 0
- 3
src/game/states/gamepad-config-menu-state.cpp View File

@ -62,7 +62,6 @@ gamepad_config_menu_state::gamepad_config_menu_state(::game& ctx):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);
@ -317,7 +316,6 @@ void gamepad_config_menu_state::add_control_item(input::action_map& action_map,
// Update control mapping text
value_text->set_content(this->get_mapping_string(*action_map, *control));
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
// Queue disabling of input mapper re-enabling of menu controls
ctx.function_queue.push
@ -336,7 +334,6 @@ void gamepad_config_menu_state::add_control_item(input::action_map& action_map,
// Set control mapping text to "..."
value_text->set_content(get_string(ctx, "control_mapping"));
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
// Setup input mapped callbacks
gamepad_axis_mapped_subscription = ctx.input_mapper.get_gamepad_axis_mapped_channel().subscribe

+ 0
- 10
src/game/states/graphics-menu-state.cpp View File

@ -77,7 +77,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);
@ -90,7 +89,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
// Update fullscreen settings
(*ctx.settings)["fullscreen"] = fullscreen;
@ -117,7 +115,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
// Update text
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto decrease_resolution_callback = [this, &ctx]()
@ -141,7 +138,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
// Update text
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto toggle_v_sync_callback = [this, &ctx]()
@ -155,7 +151,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto next_aa_method_callback = [this, &ctx]()
@ -182,7 +177,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
// Refresh and realign text
::menu::refresh_text(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto previous_aa_method_callback = [this, &ctx]()
@ -209,7 +203,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
// Refresh and realign text
::menu::refresh_text(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto increase_font_scale_callback = [this, &ctx]()
@ -238,7 +231,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
// Refresh and realign text
::menu::refresh_text(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto decrease_font_scale_callback = [this, &ctx]()
@ -267,7 +259,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
// Refresh and realign text
::menu::refresh_text(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto toggle_dyslexia_font_callback = [this, &ctx]()
@ -288,7 +279,6 @@ graphics_menu_state::graphics_menu_state(::game& ctx):
// Refresh and realign text
::menu::refresh_text(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto select_back_callback = [&ctx]()
{

+ 0
- 3
src/game/states/keyboard-config-menu-state.cpp View File

@ -62,7 +62,6 @@ keyboard_config_menu_state::keyboard_config_menu_state(::game& ctx):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);
@ -241,7 +240,6 @@ void keyboard_config_menu_state::add_control_item(input::action_map& action_map,
// Update control mapping text
value_text->set_content(this->get_mapping_string(*action_map, *control));
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
// Queue disabling of input mapper re-enabling of menu controls
ctx.function_queue.push
@ -260,7 +258,6 @@ void keyboard_config_menu_state::add_control_item(input::action_map& action_map,
// Set control mapping text to "..."
value_text->set_content(get_string(ctx, "control_mapping"));
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
// Setup input mapped callbacks
key_mapped_subscription = ctx.input_mapper.get_key_mapped_channel().subscribe

+ 0
- 2
src/game/states/language-menu-state.cpp View File

@ -73,7 +73,6 @@ language_menu_state::language_menu_state(::game& ctx):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);
@ -114,7 +113,6 @@ language_menu_state::language_menu_state(::game& ctx):
this->update_text_content();
::menu::refresh_text(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
// Construct menu item callbacks

+ 5
- 9
src/game/states/main-menu-state.cpp View File

@ -65,14 +65,13 @@ main_menu_state::main_menu_state(::game& ctx, bool fade_in):
title_text->set_color({1.0f, 1.0f, 1.0f, (fade_in) ? 1.0f : 0.0f});
title_text->set_font(&ctx.title_font);
title_text->set_content(get_string(ctx, "title_antkeeper"));
const auto& title_aabb = static_cast<const geom::aabb<float>&>(title_text->get_local_bounds());
const auto& title_aabb = static_cast<const geom::aabb<float>&>(title_text->get_bounds());
float title_w = title_aabb.max_point.x() - title_aabb.min_point.x();
float title_h = title_aabb.max_point.y() - title_aabb.min_point.y();
title_text->set_translation({std::round(viewport_center.x() - title_w * 0.5f), std::round(viewport_center.y() - title_h * 0.5f + (viewport_size.y() / 3.0f) / 2.0f), 0.0f});
title_text->update_tweens();
// Add text to UI
ctx.ui_scene->add_object(title_text.get());
ctx.ui_scene->add_object(*title_text);
// Construct title fade animation
title_fade_animation.set_interpolator(ease<float>::out_cubic);
@ -112,7 +111,6 @@ main_menu_state::main_menu_state(::game& ctx, bool fade_in):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx, true, false, (-viewport_size.y() / 3.0f) / 2.0f);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);
@ -266,14 +264,13 @@ main_menu_state::main_menu_state(::game& ctx, bool fade_in):
ctx.surface_camera->set_active(true);
const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f);
ctx.surface_camera->set_exposure(ev100_sunny16);
ctx.surface_camera->set_exposure_value(ev100_sunny16);
const float aspect_ratio = viewport_size.x() / viewport_size.y();
float fov = math::vertical_fov(math::radians(100.0f), aspect_ratio);
ctx.surface_camera->look_at({0, 2.0f, 0}, {0, 0, 0}, {0, 0, 1});
ctx.surface_camera->set_perspective(fov, ctx.surface_camera->get_aspect_ratio(), ctx.surface_camera->get_clip_near(), ctx.surface_camera->get_clip_far());
ctx.surface_camera->update_tweens();
// Setup and enable sky and ground passes
ctx.sky_pass->set_enabled(true);
@ -291,11 +288,10 @@ main_menu_state::main_menu_state(::game& ctx, bool fade_in):
const vec2 viewport_center = viewport_size * 0.5f;
// Re-align title text
const auto& title_aabb = static_cast<const geom::aabb<float>&>(title_text->get_local_bounds());
const auto& title_aabb = static_cast<const geom::aabb<float>&>(title_text->get_bounds());
float title_w = title_aabb.max_point.x() - title_aabb.min_point.x();
float title_h = title_aabb.max_point.y() - title_aabb.min_point.y();
title_text->set_translation({std::round(viewport_center.x() - title_w * 0.5f), std::round(viewport_center.y() - title_h * 0.5f + (viewport_size.y() / 3.0f) / 2.0f), 0.0f});
title_text->update_tweens();
::menu::align_text(ctx, true, false, (-viewport_size.y() / 3.0f) / 2.0f);
}
@ -325,7 +321,7 @@ main_menu_state::~main_menu_state()
ctx.animator->remove_animation(&title_fade_animation);
// Destruct text
ctx.ui_scene->remove_object(title_text.get());
ctx.ui_scene->remove_object(*title_text);
debug::log::trace("Exited main menu state");
}

+ 82
- 168
src/game/states/nest-selection-state.cpp View File

@ -23,7 +23,6 @@
#include "game/ant/ant-phenome.hpp"
#include "game/commands/commands.hpp"
#include "game/components/collision-component.hpp"
#include "game/components/camera-component.hpp"
#include "game/components/constraint-stack-component.hpp"
#include "game/components/scene-component.hpp"
#include "game/components/picking-component.hpp"
@ -72,6 +71,7 @@
#include <engine/render/passes/ground-pass.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/state-machine.hpp>
#include <engine/scene/static-mesh.hpp>
nest_selection_state::nest_selection_state(::game& ctx):
game_state(ctx)
@ -132,7 +132,6 @@ nest_selection_state::nest_selection_state(::game& ctx):
worker_transform_component.local = math::transform<float>::identity;
worker_transform_component.local.translation = {0, 0.5f, -4};
worker_transform_component.world = worker_transform_component.local;
worker_transform_component.warp = true;
ctx.entity_registry->emplace<transform_component>(worker_ant_eid, worker_transform_component);
ctx.entity_registry->emplace<scene_component>(worker_ant_eid, std::make_unique<scene::static_mesh>(worker_model), std::uint8_t{1});
@ -163,7 +162,7 @@ nest_selection_state::nest_selection_state(::game& ctx):
// Set camera exposure
const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f);
ctx.surface_camera->set_exposure(ev100_sunny16);
ctx.surface_camera->set_exposure_value(ev100_sunny16);
const auto& viewport_size = ctx.window->get_viewport_size();
const float aspect_ratio = static_cast<float>(viewport_size[0]) / static_cast<float>(viewport_size[1]);
@ -274,72 +273,18 @@ nest_selection_state::~nest_selection_state()
void nest_selection_state::create_first_person_camera_rig()
{
// Construct first person camera rig track to constraint
track_to_constraint first_person_camera_rig_track_to;
first_person_camera_rig_track_to.target = worker_ant_eid;
first_person_camera_rig_track_to.up = {0.0f, 1.0f, 0.0f};
constraint_stack_node_component first_person_camera_rig_track_to_node;
first_person_camera_rig_track_to_node.active = false;
first_person_camera_rig_track_to_node.weight = 1.0f;
first_person_camera_rig_track_to_node.next = entt::null;
first_person_camera_rig_track_to_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<track_to_constraint>(first_person_camera_rig_track_to_eid, first_person_camera_rig_track_to);
ctx.entity_registry->emplace<constraint_stack_node_component>(first_person_camera_rig_track_to_eid, first_person_camera_rig_track_to_node);
// Construct first person camera rig spring rotation constraint
spring_rotation_constraint first_person_camera_rig_spring_rotation;
first_person_camera_rig_spring_rotation.spring =
{
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
1.0f,
first_person_camera_rig_rotation_spring_angular_frequency
};
constraint_stack_node_component first_person_camera_rig_spring_rotation_node;
first_person_camera_rig_spring_rotation_node.active = false;
first_person_camera_rig_spring_rotation_node.weight = 1.0f;
first_person_camera_rig_spring_rotation_node.next = first_person_camera_rig_track_to_eid;
first_person_camera_rig_spring_rotation_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<spring_rotation_constraint>(first_person_camera_rig_spring_rotation_eid, first_person_camera_rig_spring_rotation);
ctx.entity_registry->emplace<constraint_stack_node_component>(first_person_camera_rig_spring_rotation_eid, first_person_camera_rig_spring_rotation_node);
// Construct first person camera rig spring translation constraint
spring_translation_constraint first_person_camera_rig_spring_translation;
first_person_camera_rig_spring_translation.spring =
{
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
1.0f,
first_person_camera_rig_translation_spring_angular_frequency
};
constraint_stack_node_component first_person_camera_rig_spring_translation_node;
first_person_camera_rig_spring_translation_node.active = false;
first_person_camera_rig_spring_translation_node.weight = 1.0f;
first_person_camera_rig_spring_translation_node.next = first_person_camera_rig_spring_rotation_eid;
first_person_camera_rig_spring_translation_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<spring_translation_constraint>(first_person_camera_rig_spring_translation_eid, first_person_camera_rig_spring_translation);
ctx.entity_registry->emplace<constraint_stack_node_component>(first_person_camera_rig_spring_translation_eid, first_person_camera_rig_spring_translation_node);
// Construct first person camera rig constraint stack
constraint_stack_component first_person_camera_rig_constraint_stack;
first_person_camera_rig_constraint_stack.priority = 2;
first_person_camera_rig_constraint_stack.head = first_person_camera_rig_spring_translation_eid;
// Construct first person camera rig transform component
transform_component first_person_camera_rig_transform;
first_person_camera_rig_transform.local = math::transform<float>::identity;
first_person_camera_rig_transform.local.translation = {0, 10, 0};
first_person_camera_rig_transform.world = first_person_camera_rig_transform.local;
first_person_camera_rig_transform.warp = true;
// Construct first person camera rig locomotion component
winged_locomotion_component first_person_camera_rig_locomotion;
// Construct first person camera rig physics component
auto first_person_camera_rig_body = std::make_unique<physics::rigid_body>();
first_person_camera_rig_body->set_position({0, 10, 0});
first_person_camera_rig_body->set_mass(1.0f);
first_person_camera_rig_body->set_linear_damping(10.0f);
first_person_camera_rig_body->set_angular_damping(0.5f);
@ -352,127 +297,102 @@ void nest_selection_state::create_first_person_camera_rig()
first_person_camera_rig_collider->set_material(std::move(camera_collider_material));
first_person_camera_rig_body->set_collider(std::move(first_person_camera_rig_collider));
// Construct first person camera rig camera component
camera_component first_person_camera_rig_camera;
first_person_camera_rig_camera.object = ctx.surface_camera.get();
// Construct first person camera rig scene component
scene_component first_person_camera_rig_camera;
first_person_camera_rig_camera.object = ctx.surface_camera;
// Construct first person camera rig entity
first_person_camera_rig_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<camera_component>(first_person_camera_rig_eid, first_person_camera_rig_camera);
ctx.entity_registry->emplace<scene_component>(first_person_camera_rig_eid, first_person_camera_rig_camera);
ctx.entity_registry->emplace<transform_component>(first_person_camera_rig_eid, first_person_camera_rig_transform);
ctx.entity_registry->emplace<rigid_body_component>(first_person_camera_rig_eid, std::move(first_person_camera_rig_body));
ctx.entity_registry->emplace<winged_locomotion_component>(first_person_camera_rig_eid, first_person_camera_rig_locomotion);
ctx.entity_registry->emplace<constraint_stack_component>(first_person_camera_rig_eid, first_person_camera_rig_constraint_stack);
// Construct first person camera rig fov spring
spring1_component first_person_camera_rig_fov_spring;
first_person_camera_rig_fov_spring.spring =
{
0.0f,
0.0f,
0.0f,
1.0f,
first_person_camera_rig_fov_spring_angular_frequency
};
first_person_camera_rig_fov_spring.callback = [&](float fov)
{
ctx.surface_camera->set_perspective(fov, ctx.surface_camera->get_aspect_ratio(), ctx.surface_camera->get_clip_near(), ctx.surface_camera->get_clip_far());
};
// Construct first person camera rig fov spring entity
first_person_camera_rig_fov_spring_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<spring1_component>(first_person_camera_rig_fov_spring_eid, first_person_camera_rig_fov_spring);
set_first_person_camera_rig_pedestal(first_person_camera_rig_pedestal);
}
void nest_selection_state::destroy_first_person_camera_rig()
{
ctx.entity_registry->destroy(first_person_camera_rig_eid);
ctx.entity_registry->destroy(first_person_camera_rig_spring_translation_eid);
ctx.entity_registry->destroy(first_person_camera_rig_spring_rotation_eid);
ctx.entity_registry->destroy(first_person_camera_rig_fov_spring_eid);
}
void nest_selection_state::set_first_person_camera_rig_pedestal(float pedestal)
{
first_person_camera_rig_pedestal = pedestal;
const float elevation = math::log_lerp(first_person_camera_rig_min_elevation, first_person_camera_rig_max_elevation, first_person_camera_rig_pedestal);
const float fov = math::log_lerp(first_person_camera_near_fov, first_person_camera_far_fov, first_person_camera_rig_pedestal);
ctx.entity_registry->patch<spring_translation_constraint>
(
first_person_camera_rig_spring_translation_eid,
[&](auto& component)
{
component.spring.x1[1] = elevation;
}
);
ctx.entity_registry->patch<spring1_component>
(
first_person_camera_rig_fov_spring_eid,
[&](auto& component)
{
component.spring.x1 = fov;
}
);
// first_person_camera_rig_pedestal = pedestal;
// const float elevation = math::log_lerp(first_person_camera_rig_min_elevation, first_person_camera_rig_max_elevation, first_person_camera_rig_pedestal);
// const float fov = math::log_lerp(first_person_camera_near_fov, first_person_camera_far_fov, first_person_camera_rig_pedestal);
// ctx.entity_registry->patch<spring_translation_constraint>
// (
// first_person_camera_rig_spring_translation_eid,
// [&](auto& component)
// {
// component.spring.x1[1] = elevation;
// }
// );
// ctx.entity_registry->patch<spring1_component>
// (
// first_person_camera_rig_fov_spring_eid,
// [&](auto& component)
// {
// component.spring.x1 = fov;
// }
// );
}
void nest_selection_state::move_first_person_camera_rig(const float2& direction, float factor)
{
const float speed = math::log_lerp(first_person_camera_near_speed, first_person_camera_far_speed, first_person_camera_rig_pedestal) * factor;
const spring_rotation_constraint& first_person_camera_rig_spring_rotation = ctx.entity_registry->get<spring_rotation_constraint>(first_person_camera_rig_spring_rotation_eid);
const math::quaternion<float> yaw_rotation = math::angle_axis(first_person_camera_rig_spring_rotation.spring.x0[0], float3{0.0f, 1.0f, 0.0f});
const float3 rotated_direction = math::normalize(yaw_rotation * float3{direction[0], 0.0f, direction[1]});
const float3 velocity = rotated_direction * speed;
ctx.entity_registry->patch<spring_translation_constraint>
(
first_person_camera_rig_spring_translation_eid,
[&](auto& component)
{
component.spring.x1 += velocity * static_cast<float>(1.0 / ctx.fixed_update_rate);
}
);
// const float speed = math::log_lerp(first_person_camera_near_speed, first_person_camera_far_speed, first_person_camera_rig_pedestal) * factor;
// const spring_rotation_constraint& first_person_camera_rig_spring_rotation = ctx.entity_registry->get<spring_rotation_constraint>(first_person_camera_rig_spring_rotation_eid);
// const math::quaternion<float> yaw_rotation = math::angle_axis(first_person_camera_rig_spring_rotation.spring.x0[0], float3{0.0f, 1.0f, 0.0f});
// const float3 rotated_direction = math::normalize(yaw_rotation * float3{direction[0], 0.0f, direction[1]});
// const float3 velocity = rotated_direction * speed;
// ctx.entity_registry->patch<spring_translation_constraint>
// (
// first_person_camera_rig_spring_translation_eid,
// [&](auto& component)
// {
// component.spring.x1 += velocity * static_cast<float>(1.0 / ctx.fixed_update_rate);
// }
// );
}
void nest_selection_state::satisfy_first_person_camera_rig_constraints()
{
// Satisfy first person camera rig spring translation constraint
ctx.entity_registry->patch<spring_translation_constraint>
(
first_person_camera_rig_spring_translation_eid,
[&](auto& component)
{
component.spring.x0 = component.spring.x1;
component.spring.v *= 0.0f;
}
);
// ctx.entity_registry->patch<spring_translation_constraint>
// (
// first_person_camera_rig_spring_translation_eid,
// [&](auto& component)
// {
// component.spring.x0 = component.spring.x1;
// component.spring.v *= 0.0f;
// }
// );
// Satisfy first person camera rig spring rotation constraint
ctx.entity_registry->patch<spring_rotation_constraint>
(
first_person_camera_rig_spring_rotation_eid,
[&](auto& component)
{
component.spring.x0 = component.spring.x1;
component.spring.v *= 0.0f;
}
);
// ctx.entity_registry->patch<spring_rotation_constraint>
// (
// first_person_camera_rig_spring_rotation_eid,
// [&](auto& component)
// {
// component.spring.x0 = component.spring.x1;
// component.spring.v *= 0.0f;
// }
// );
// Satisfy first person camera rig fov spring
ctx.entity_registry->patch<spring1_component>
(
first_person_camera_rig_fov_spring_eid,
[&](auto& component)
{
component.spring.x0 = component.spring.x1;
component.spring.v *= 0.0f;
}
);
// ctx.entity_registry->patch<spring1_component>
// (
// first_person_camera_rig_fov_spring_eid,
// [&](auto& component)
// {
// component.spring.x0 = component.spring.x1;
// component.spring.v *= 0.0f;
// }
// );
}
void nest_selection_state::setup_controls()
@ -522,12 +442,14 @@ void nest_selection_state::setup_controls()
{
const transform_component& first_person_camera_rig_transform = ctx.entity_registry->get<transform_component>(first_person_camera_rig_eid);
const spring_rotation_constraint& first_person_camera_rig_spring_rotation = ctx.entity_registry->get<spring_rotation_constraint>(first_person_camera_rig_spring_rotation_eid);
//const spring_rotation_constraint& first_person_camera_rig_spring_rotation = ctx.entity_registry->get<spring_rotation_constraint>(first_person_camera_rig_spring_rotation_eid);
const math::quaternion<float> yaw_rotation = math::angle_axis(first_person_camera_rig_spring_rotation.spring.x0[0], float3{0.0f, 1.0f, 0.0f});
//const math::quaternion<float> yaw_rotation = math::angle_axis(first_person_camera_rig_spring_rotation.spring.x0[0], float3{0.0f, 1.0f, 0.0f});
//const float3 rotated_direction = yaw_rotation * float3{direction[0], 0.0f, direction[1]};
const float3 rotated_direction = first_person_camera_rig_transform.world.rotation * float3{direction[0], 0.0f, direction[1]};
const math::quaternion<float> yaw_rotation = math::angle_axis(static_cast<float>(first_person_camera_yaw), float3{0.0f, 1.0f, 0.0f});
const float3 rotated_direction = yaw_rotation * float3{direction[0], 0.0f, direction[1]};
const float3 force = rotated_direction * speed;
@ -578,13 +500,12 @@ void nest_selection_state::setup_controls()
const math::quaternion<double> pitch_rotation = math::angle_axis(first_person_camera_pitch, {-1.0, 0.0, 0.0});
const math::quaternion<float> first_person_camera_orientation = math::quaternion<float>(math::normalize(yaw_rotation * pitch_rotation));
ctx.entity_registry->patch<camera_component>
ctx.entity_registry->patch<scene_component>
(
first_person_camera_rig_eid,
[&](auto& component)
{
component.object->set_rotation(first_person_camera_orientation);
component.object->update_tweens();
}
);
@ -593,6 +514,7 @@ void nest_selection_state::setup_controls()
first_person_camera_rig_eid,
[&](auto& component)
{
component.body->set_previous_orientation(first_person_camera_orientation);
component.body->set_orientation(first_person_camera_orientation);
}
);
@ -752,16 +674,15 @@ void nest_selection_state::setup_controls()
const auto& camera_transform = ctx.entity_registry->get<transform_component>(first_person_camera_rig_eid);
scene_component projectile_scene;
projectile_scene.object = std::make_unique<scene::static_mesh>(ctx.resource_manager->load<render::model>("sphere.mdl"));
//projectile_scene.object = std::make_unique<scene::static_mesh>(ctx.resource_manager->load<render::model>("cube.mdl"));
projectile_scene.object = std::make_shared<scene::static_mesh>(ctx.resource_manager->load<render::model>("sphere.mdl"));
//projectile_scene.object = std::make_shared<scene::static_mesh>(ctx.resource_manager->load<render::model>("cube.mdl"));
transform_component projectile_transform;
projectile_transform.local = camera_transform.world;
projectile_transform.world = projectile_transform.local;
projectile_transform.warp = true;
auto projectile_body = std::make_unique<physics::rigid_body>();
projectile_body->set_center_of_mass(camera_transform.world.translation);
projectile_body->set_position(camera_transform.world.translation);
projectile_body->set_mass(0.1f);
projectile_body->set_inertia(0.05f);
projectile_body->set_angular_damping(0.5f);
@ -814,14 +735,7 @@ void nest_selection_state::setup_controls()
(
[&](const auto& event)
{
ctx.entity_registry->patch<constraint_stack_node_component>
(
first_person_camera_rig_track_to_eid,
[&](auto& component)
{
component.active = false;
}
);
}
)
);

+ 0
- 4
src/game/states/nest-selection-state.hpp View File

@ -54,10 +54,6 @@ private:
entity::id worker_ant_eid;
entity::id first_person_camera_rig_eid;
entity::id first_person_camera_rig_spring_translation_eid;
entity::id first_person_camera_rig_spring_rotation_eid;
entity::id first_person_camera_rig_track_to_eid;
entity::id first_person_camera_rig_fov_spring_eid;
float first_person_camera_rig_translation_spring_angular_frequency;
float first_person_camera_rig_rotation_spring_angular_frequency;
float first_person_camera_rig_fov_spring_angular_frequency;

+ 9
- 13
src/game/states/nuptial-flight-state.cpp View File

@ -29,12 +29,12 @@
#include "game/components/ant-caste-component.hpp"
#include "game/components/transform-component.hpp"
#include "game/components/terrain-component.hpp"
#include "game/components/camera-component.hpp"
#include "game/components/name-component.hpp"
#include "game/components/constraint-stack-component.hpp"
#include "game/components/steering-component.hpp"
#include "game/components/picking-component.hpp"
#include "game/components/spring-component.hpp"
#include "game/components/scene-component.hpp"
#include "game/constraints/child-of-constraint.hpp"
#include "game/constraints/copy-rotation-constraint.hpp"
#include "game/constraints/copy-scale-constraint.hpp"
@ -140,7 +140,7 @@ nuptial_flight_state::nuptial_flight_state(::game& ctx):
// Set camera exposure
const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f);
ctx.surface_camera->set_exposure(ev100_sunny16);
ctx.surface_camera->set_exposure_value(ev100_sunny16);
const auto& viewport_size = ctx.window->get_viewport_size();
const float aspect_ratio = static_cast<float>(viewport_size[0]) / static_cast<float>(viewport_size[1]);
@ -163,14 +163,13 @@ nuptial_flight_state::nuptial_flight_state(::game& ctx):
selection_text.set_material(ctx.menu_font_material);
selection_text.set_color({1.0f, 1.0f, 1.0f, 1.0f});
selection_text.set_font(&ctx.menu_font);
const auto& text_aabb = static_cast<const geom::aabb<float>&>(selection_text.get_local_bounds());
const auto& text_aabb = static_cast<const geom::aabb<float>&>(selection_text.get_bounds());
float text_w = text_aabb.max_point.x() - text_aabb.min_point.x();
float text_h = text_aabb.max_point.y() - text_aabb.min_point.y();
selection_text.set_translation({std::round(viewport_size.x() * 0.5f - text_w * 0.5f), std::round(ctx.menu_font.get_font_metrics().size), 0.0f});
selection_text.update_tweens();
// Add text to UI
ctx.ui_scene->add_object(&selection_text);
ctx.ui_scene->add_object(selection_text);
// Select random alate
entity::id random_alate_eid;
@ -219,7 +218,7 @@ nuptial_flight_state::~nuptial_flight_state()
::disable_game_controls(ctx);
// Remove text from UI
ctx.ui_scene->remove_object(&selection_text);
ctx.ui_scene->remove_object(selection_text);
// Deselect selected entity
select_entity(entt::null);
@ -257,7 +256,6 @@ void nuptial_flight_state::create_camera_rig()
transform_component camera_rig_focus_transform;
camera_rig_focus_transform.local = math::transform<float>::identity;
camera_rig_focus_transform.world = camera_rig_focus_transform.local;
camera_rig_focus_transform.warp = true;
// Construct camera rig focus entity
camera_rig_focus_eid = ctx.entity_registry->create();
@ -339,15 +337,14 @@ void nuptial_flight_state::create_camera_rig()
transform_component camera_rig_transform;
camera_rig_transform.local = math::transform<float>::identity;
camera_rig_transform.world = camera_rig_transform.local;
camera_rig_transform.warp = true;
// Construct camera rig camera component
camera_component camera_rig_camera;
camera_rig_camera.object = ctx.surface_camera.get();
scene_component camera_rig_camera;
camera_rig_camera.object = ctx.surface_camera;
// Construct camera rig entity
camera_rig_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<camera_component>(camera_rig_eid, camera_rig_camera);
ctx.entity_registry->emplace<scene_component>(camera_rig_eid, camera_rig_camera);
ctx.entity_registry->emplace<transform_component>(camera_rig_eid, camera_rig_transform);
ctx.entity_registry->emplace<constraint_stack_component>(camera_rig_eid, camera_rig_constraint_stack);
@ -1104,11 +1101,10 @@ void nuptial_flight_state::select_entity(entity::id entity_id)
}
const auto& viewport_size = ctx.window->get_viewport_size();
const auto& text_aabb = static_cast<const geom::aabb<float>&>(selection_text.get_local_bounds());
const auto& text_aabb = static_cast<const geom::aabb<float>&>(selection_text.get_bounds());
float text_w = text_aabb.max_point.x() - text_aabb.min_point.x();
float text_h = text_aabb.max_point.y() - text_aabb.min_point.y();
selection_text.set_translation({std::round(viewport_size.x() * 0.5f - text_w * 0.5f), std::round(ctx.menu_font.get_font_metrics().size), 0.0f});
selection_text.update_tweens();
}
}
}

+ 0
- 1
src/game/states/options-menu-state.cpp View File

@ -68,7 +68,6 @@ options_menu_state::options_menu_state(::game& ctx):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx, true);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);

+ 0
- 1
src/game/states/pause-menu-state.cpp View File

@ -64,7 +64,6 @@ pause_menu_state::pause_menu_state(::game& ctx):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx, true, false);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);

+ 0
- 7
src/game/states/sound-menu-state.cpp View File

@ -74,7 +74,6 @@ sound_menu_state::sound_menu_state(::game& ctx):
::menu::update_text_color(ctx);
::menu::update_text_font(ctx);
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
::menu::add_text_to_ui(ctx);
::menu::setup_animations(ctx);
@ -93,7 +92,6 @@ sound_menu_state::sound_menu_state(::game& ctx):
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto decrease_volume_callback = [this, &ctx](float* volume)
{
@ -109,7 +107,6 @@ sound_menu_state::sound_menu_state(::game& ctx):
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto toggle_mono_audio_callback = [this, &ctx]()
@ -118,7 +115,6 @@ sound_menu_state::sound_menu_state(::game& ctx):
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto toggle_captions_callback = [this, &ctx]()
@ -127,7 +123,6 @@ sound_menu_state::sound_menu_state(::game& ctx):
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto increase_captions_size_callback = [this, &ctx]()
@ -144,7 +139,6 @@ sound_menu_state::sound_menu_state(::game& ctx):
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto decrease_captions_size_callback = [this, &ctx]()
@ -161,7 +155,6 @@ sound_menu_state::sound_menu_state(::game& ctx):
this->update_value_text_content();
::menu::align_text(ctx);
::menu::update_text_tweens(ctx);
};
auto select_back_callback = [&ctx]()
{

+ 2
- 5
src/game/states/splash-state.cpp View File

@ -58,16 +58,14 @@ splash_state::splash_state(::game& ctx):
auto splash_tint = std::make_shared<render::material_float4>(1, float4{1, 1, 1, 0});
splash_billboard_material->set_variable("tint", splash_tint);
//splash_billboard_material.update_tweens();
// Construct splash billboard
splash_billboard.set_material(splash_billboard_material);
splash_billboard.set_scale({static_cast<float>(std::get<0>(splash_dimensions)) * 0.5f, static_cast<float>(std::get<1>(splash_dimensions)) * 0.5f, 1.0f});
splash_billboard.set_translation({std::round(viewport_center.x()), std::round(viewport_center.y()), 0.0f});
splash_billboard.update_tweens();
// Add splash billboard to UI scene
ctx.ui_scene->add_object(&splash_billboard);
ctx.ui_scene->add_object(splash_billboard);
// Load animation timing configuration
const float splash_fade_in_duration = 0.5;
@ -136,7 +134,6 @@ splash_state::splash_state(::game& ctx):
const vec2 viewport_size = vec2(event.window->get_viewport_size());
const vec2 viewport_center = viewport_size * 0.5f;
splash_billboard.set_translation({std::round(viewport_center.x()), std::round(viewport_center.y()), 0.0f});
splash_billboard.update_tweens();
}
);
@ -207,7 +204,7 @@ splash_state::~splash_state()
ctx.animator->remove_animation(&splash_fade_out_animation);
// Remove splash billboard from UI scene
ctx.ui_scene->remove_object(&splash_billboard);
ctx.ui_scene->remove_object(splash_billboard);
// Disable color buffer clearing in UI pass
ctx.ui_clear_pass->set_cleared_buffers(false, true, false);

+ 4
- 4
src/game/systems/astronomy-system.cpp View File

@ -206,7 +206,7 @@ void astronomy_system::update(float t, float dt)
)
);
sun_light->set_color(float3(observer_blackbody_transmitted_illuminance));
sun_light->set_illuminance(float3(observer_blackbody_transmitted_illuminance));
// Bounce sun light
bounce_illuminance += std::max(0.0, math::dot(bounce_normal, -observer_blackbody_direction_eus)) * observer_blackbody_transmitted_illuminance * bounce_albedo;
@ -226,7 +226,7 @@ void astronomy_system::update(float t, float dt)
sky_light_illuminance += starlight_illuminance;
// Update sky light
sky_light->set_color(float3(sky_light_illuminance));
sky_light->set_illuminance(float3(sky_light_illuminance));
// Bounce sky light
bounce_illuminance += sky_light_illuminance * bounce_albedo;
@ -314,7 +314,7 @@ void astronomy_system::update(float t, float dt)
{
const float3 reflector_up_eus = float3(icrf_to_eus.r * double3{0, 0, 1});
this->moon_light->set_color(float3(observer_reflector_illuminance));
this->moon_light->set_illuminance(float3(observer_reflector_illuminance));
this->moon_light->set_rotation
(
math::look_rotation
@ -332,7 +332,7 @@ void astronomy_system::update(float t, float dt)
if (bounce_light)
{
bounce_light->set_color(float3(bounce_illuminance));
bounce_light->set_illuminance(float3(bounce_illuminance));
}
}

+ 36
- 52
src/game/systems/physics-system.cpp View File

@ -22,6 +22,7 @@
#include "game/components/rigid-body-component.hpp"
#include "game/components/rigid-body-constraint-component.hpp"
#include "game/components/transform-component.hpp"
#include "game/components/scene-component.hpp"
#include <algorithm>
#include <engine/debug/log.hpp>
#include <engine/entity/id.hpp>
@ -77,33 +78,15 @@ physics_system::physics_system(entity::registry& registry):
void physics_system::update(float t, float dt)
{
/// Update rigid body transforms
auto transform_view = registry.view<rigid_body_component, transform_component>();
std::for_each
(
std::execution::par_unseq,
transform_view.begin(),
transform_view.end(),
[&](auto entity_id)
{
auto& body = *(transform_view.get<rigid_body_component>(entity_id).body);
auto& transform = transform_view.get<transform_component>(entity_id);
// Update body center of mass and orientation
body.set_center_of_mass(transform.local.translation);
body.set_orientation(transform.local.rotation);
}
);
detect_collisions_broad();
detect_collisions_narrow();
solve_constraints(dt);
resolve_collisions();
integrate_forces(dt);
integrate_velocities(dt);
integrate(dt);
correct_positions();
// Update transform component transforms
auto transform_view = registry.view<rigid_body_component, transform_component>();
for (const auto entity_id: transform_view)
{
const auto& body = *(transform_view.get<rigid_body_component>(entity_id).body);
@ -115,14 +98,32 @@ void physics_system::update(float t, float dt)
[&, dt](auto& transform)
{
// Integrate position
transform.local.translation = body.get_center_of_mass();
transform.local.rotation = body.get_orientation();
transform.local = body.get_transform();
}
);
}
}
void physics_system::integrate_forces(float dt)
void physics_system::interpolate(float alpha)
{
// Interpolate rigid body states
auto view = registry.view<rigid_body_component, scene_component>();
std::for_each
(
std::execution::par_unseq,
view.begin(),
view.end(),
[&, alpha](auto entity_id)
{
const auto& rigid_body = *(view.get<rigid_body_component>(entity_id).body);
auto& scene_object = *(view.get<scene_component>(entity_id).object);
scene_object.set_transform(rigid_body.interpolate(alpha));
}
);
}
void physics_system::integrate(float dt)
{
// Drag
/*
@ -152,24 +153,7 @@ void physics_system::integrate_forces(float dt)
// Apply gravity
body.apply_central_force(gravity / 10.0f * body.get_mass());
body.integrate_forces(dt);
}
);
}
void physics_system::integrate_velocities(float dt)
{
auto view = registry.view<rigid_body_component>();
std::for_each
(
std::execution::par_unseq,
view.begin(),
view.end(),
[&](auto entity_id)
{
auto& body = *(view.get<rigid_body_component>(entity_id).body);
body.integrate_velocities(dt);
body.integrate(dt);
}
);
}
@ -312,8 +296,8 @@ void physics_system::resolve_collisions()
{
const physics::collision_contact& contact = manifold.contacts[i];
const math::vector<float, 3> radius_a = contact.point - body_a.get_center_of_mass();
const math::vector<float, 3> radius_b = contact.point - body_b.get_center_of_mass();
const math::vector<float, 3> radius_a = contact.point - body_a.get_position();
const math::vector<float, 3> radius_b = contact.point - body_b.get_position();
math::vector<float, 3> relative_velocity = body_b.get_point_velocity(radius_b) - body_a.get_point_velocity(radius_a);
@ -391,8 +375,8 @@ void physics_system::correct_positions()
math::vector<float, 3> correction = contact.normal * (std::max<float>(0.0f, contact.depth - depth_threshold) / sum_inverse_mass) * correction_factor;
body_a.set_center_of_mass(body_a.get_center_of_mass() - correction * body_a.get_inverse_mass());
body_b.set_center_of_mass(body_b.get_center_of_mass() + correction * body_b.get_inverse_mass());
body_a.set_position(body_a.get_position() - correction * body_a.get_inverse_mass());
body_b.set_position(body_b.get_position() + correction * body_b.get_inverse_mass());
}
}
}
@ -409,9 +393,9 @@ void physics_system::narrow_phase_plane_sphere(physics::rigid_body& body_a, phys
// Transform plane into world-space
const math::vector<float, 3> plane_normal = body_a.get_orientation() * plane_a.get_normal();
const float plane_constant = plane_a.get_constant() - math::dot(plane_normal, body_a.get_center_of_mass());
const float plane_constant = plane_a.get_constant() - math::dot(plane_normal, body_a.get_position());
const float signed_distance = math::dot(plane_normal, body_b.get_center_of_mass()) + plane_constant;
const float signed_distance = math::dot(plane_normal, body_b.get_position()) + plane_constant;
if (signed_distance > sphere_b.get_radius())
{
return;
@ -425,7 +409,7 @@ void physics_system::narrow_phase_plane_sphere(physics::rigid_body& body_a, phys
// Generate collision contact
auto& contact = manifold.contacts[0];
contact.point = body_b.get_center_of_mass() - plane_normal * sphere_b.get_radius();
contact.point = body_b.get_position() - plane_normal * sphere_b.get_radius();
contact.normal = plane_normal * -normal_sign;
contact.depth = std::abs(signed_distance - sphere_b.get_radius());
@ -439,7 +423,7 @@ void physics_system::narrow_phase_plane_box(physics::rigid_body& body_a, physics
// Transform plane into world-space
const math::vector<float, 3> plane_normal = body_a.get_orientation() * plane_a.get_normal();
const float plane_constant = plane_a.get_constant() - math::dot(plane_normal, body_a.get_center_of_mass());
const float plane_constant = plane_a.get_constant() - math::dot(plane_normal, body_a.get_position());
const auto& box_min = box_b.get_min();
const auto& box_max = box_b.get_max();
@ -463,7 +447,7 @@ void physics_system::narrow_phase_plane_box(physics::rigid_body& body_a, physics
for (std::size_t i = 0; i < 8; ++i)
{
// Transform corner into world-space
const math::vector<float, 3> point = body_b.get_center_of_mass() + body_b.get_orientation() * corners[i];
const math::vector<float, 3> point = body_b.get_transform() * corners[i];
const float signed_distance = math::dot(plane_normal, point) + plane_constant;
@ -504,7 +488,7 @@ void physics_system::narrow_phase_sphere_sphere(physics::rigid_body& body_a, phy
const float sum_radii = sphere_a.get_radius() + sphere_b.get_radius();
const float sqr_sum_radii = sum_radii * sum_radii;
const math::vector<float, 3> difference = body_b.get_center_of_mass() - body_a.get_center_of_mass();
const math::vector<float, 3> difference = body_b.get_position() - body_a.get_position();
const float sqr_distance = math::dot(difference, difference);
if (sqr_distance > sqr_sum_radii)
@ -531,7 +515,7 @@ void physics_system::narrow_phase_sphere_sphere(physics::rigid_body& body_a, phy
contact.normal = {1.0f, 0.0f, 0.0f};
contact.depth = sum_radii;
}
contact.point = body_a.get_center_of_mass() + contact.normal * sphere_a.get_radius();
contact.point = body_a.get_position() + contact.normal * sphere_a.get_radius();
narrow_phase_manifolds.emplace_back(std::move(manifold));
}

+ 3
- 2
src/game/systems/physics-system.hpp View File

@ -38,6 +38,8 @@ public:
explicit physics_system(entity::registry& registry);
void update(float t, float dt) override;
void interpolate(float alpha);
/**
* Sets the gravity vector.
*
@ -51,8 +53,7 @@ public:
private:
using collision_manifold_type = physics::collision_manifold<4>;
void integrate_forces(float dt);
void integrate_velocities(float dt);
void integrate(float dt);
void solve_constraints(float dt);

+ 4
- 28
src/game/systems/render-system.cpp View File

@ -19,7 +19,6 @@
#include "game/systems/render-system.hpp"
#include "game/components/transform-component.hpp"
#include "game/components/camera-component.hpp"
#include <algorithm>
#include <execution>
@ -63,30 +62,9 @@ void render_system::update(float t, float dt)
// WARNING: could potentially lead to multithreading issues with scene::object_base::transformed()
scene.object->set_transform(transform.world);
if (transform.warp)
{
scene.object->get_transform_tween().update();
transform.warp = false;
}
}
);
updated_scene_transforms.clear();
// Update camera transforms
registry.view<transform_component, camera_component>().each
(
[this](entity::id entity_id, auto& transform, auto& camera)
{
camera.object->set_transform(transform.world);
if (transform.warp)
{
camera.object->get_transform_tween().update();
camera.object->update_tweens();
transform.warp = false;
}
}
);
}
void render_system::draw(float alpha)
@ -123,14 +101,13 @@ void render_system::on_scene_construct(entity::registry& registry, entity::id en
if (const auto transform = registry.try_get<transform_component>(entity_id))
{
component.object->set_transform(transform->world);
component.object->get_transform_tween().update();
}
for (std::size_t i = 0; i < layers.size(); ++i)
{
if (component.layer_mask & static_cast<std::uint8_t>(1 << i))
{
layers[i]->add_object(component.object.get());
layers[i]->add_object(*component.object);
}
}
}
@ -143,12 +120,12 @@ void render_system::on_scene_update(entity::registry& registry, entity::id entit
{
// Remove from layer
scene::collection* layer = layers[i];
layer->remove_object(component.object.get());
layer->remove_object(*component.object);
if (component.layer_mask & static_cast<std::uint8_t>(1 << i))
{
// Add to layer
layer->add_object(component.object.get());
layer->add_object(*component.object);
}
}
}
@ -161,7 +138,7 @@ void render_system::on_scene_destroy(entity::registry& registry, entity::id enti
{
if (component.layer_mask & static_cast<std::uint8_t>(1 << i))
{
layers[i]->remove_object(component.object.get());
layers[i]->remove_object(*component.object);
}
}
}
@ -174,6 +151,5 @@ void render_system::on_transform_construct(entity::registry& registry, entity::i
const auto& transform = registry.get<transform_component>(entity_id);
scene->object->set_transform(transform.world);
scene->object->get_transform_tween().update();
}
}

+ 0
- 1
src/game/systems/terrain-system.cpp View File

@ -19,7 +19,6 @@
#include "game/systems/terrain-system.hpp"
#include "game/components/terrain-component.hpp"
#include "game/components/camera-component.hpp"
#include <engine/geom/meshes/grid.hpp>
#include <engine/geom/mesh-functions.hpp>
#include <engine/geom/morton.hpp>

+ 7
- 11
src/game/world.cpp View File

@ -361,29 +361,26 @@ void create_sun(::game& ctx)
// Create sun directional light scene object
ctx.sun_light = std::make_unique<scene::directional_light>();
ctx.sun_light->set_color({0, 0, 0});
ctx.sun_light->set_illuminance({0, 0, 0});
ctx.sun_light->set_shadow_caster(true);
ctx.sun_light->set_shadow_framebuffer(ctx.shadow_map_framebuffer.get());
ctx.sun_light->set_shadow_bias(0.005f);
ctx.sun_light->set_shadow_cascade_count(4);
ctx.sun_light->set_shadow_cascade_coverage(0.15f);
ctx.sun_light->set_shadow_cascade_distribution(0.8f);
ctx.sun_light->update_tweens();
// Create sky ambient light scene object
ctx.sky_light = std::make_unique<scene::ambient_light>();
ctx.sky_light->set_color({0, 0, 0});
ctx.sky_light->update_tweens();
ctx.sky_light->set_illuminance({0, 0, 0});
// Create bounce directional light scene object
ctx.bounce_light = std::make_unique<scene::directional_light>();
ctx.bounce_light->set_color({0, 0, 0});
ctx.bounce_light->set_illuminance({0, 0, 0});
ctx.bounce_light->look_at({0, 0, 0}, {0, 1, 0}, {1, 0, 0});
ctx.bounce_light->update_tweens();
// Add sun light scene objects to surface scene
ctx.surface_scene->add_object(ctx.sun_light.get());
ctx.surface_scene->add_object(ctx.sky_light.get());
ctx.surface_scene->add_object(*ctx.sun_light);
ctx.surface_scene->add_object(*ctx.sky_light);
//ctx.surface_scene->add_object(ctx.bounce_light);
// Pass direct sun light scene object to shadow map pass and astronomy system
@ -450,11 +447,10 @@ void create_moon(::game& ctx)
// Create moon directional light scene object
ctx.moon_light = std::make_unique<scene::directional_light>();
ctx.moon_light->set_color({0, 0, 0});
ctx.moon_light->update_tweens();
ctx.moon_light->set_illuminance({0, 0, 0});
// Add moon light scene objects to surface scene
ctx.surface_scene->add_object(ctx.moon_light.get());
ctx.surface_scene->add_object(*ctx.moon_light);
// Pass moon light scene object to astronomy system
ctx.astronomy_system->set_moon_light(ctx.moon_light.get());

Loading…
Cancel
Save