]> git.localhorst.tv Git - blank.git/blobdiff - src/ui/ui.cpp
use "forces" for entity control and RK4 integrator
[blank.git] / src / ui / ui.cpp
index 75129c1b3837ebd5460328507cded17ff3f73473..96386195e57803c4aa8fcd498072caa229df768f 100644 (file)
 #include "../app/FrameCounter.hpp"
 #include "../app/init.hpp"
 #include "../audio/Audio.hpp"
+#include "../audio/SoundBank.hpp"
 #include "../graphics/Font.hpp"
 #include "../graphics/Viewport.hpp"
 #include "../io/TokenStreamReader.hpp"
-#include "../model/shapes.hpp"
+#include "../model/bounds.hpp"
 #include "../world/BlockLookup.hpp"
 #include "../world/World.hpp"
 #include "../world/WorldManipulator.hpp"
 
 namespace blank {
 
-DirectInput::DirectInput(World &world, Player &player, WorldManipulator &manip)
+PlayerController::PlayerController(World &world, Player &player)
 : world(world)
 , player(player)
-, manip(manip)
-, aim_world()
-, aim_entity()
 , move_dir(0.0f)
 , pitch(0.0f)
 , yaw(0.0f)
 , dirty(true)
-, place_timer(256)
-, remove_timer(256) {
-
-}
-
-void DirectInput::Update(int dt) {
-       dirty = true; // world has changed in the meantime
-       UpdatePlayer();
-
-       remove_timer.Update(dt);
-       if (remove_timer.Hit()) {
-               RemoveBlock();
-       }
+, aim_world()
+, aim_entity() {
 
-       place_timer.Update(dt);
-       if (place_timer.Hit()) {
-               PlaceBlock();
-       }
 }
 
-void DirectInput::SetMovement(const glm::vec3 &m) {
+void PlayerController::SetMovement(const glm::vec3 &m) noexcept {
        if (dot(m, m) > 1.0f) {
                move_dir = normalize(m);
        } else {
                move_dir = m;
        }
-       dirty = true;
+       Invalidate();
 }
 
-void DirectInput::TurnHead(float dp, float dy) {
+void PlayerController::TurnHead(float dp, float dy) noexcept {
        pitch += dp;
        if (pitch > PI / 2) {
                pitch = PI / 2;
@@ -84,9 +67,70 @@ void DirectInput::TurnHead(float dp, float dy) {
        } else if (yaw < -PI) {
                yaw += PI * 2;
        }
+       Invalidate();
+}
+
+void PlayerController::SelectInventory(int i) noexcept {
+       player.SetInventorySlot(i);
+}
+
+int PlayerController::InventorySlot() const noexcept {
+       return player.GetInventorySlot();
+}
+
+void PlayerController::Invalidate() noexcept {
        dirty = true;
 }
 
+void PlayerController::UpdatePlayer() noexcept {
+       constexpr float max_vel = 0.005f;
+       if (dirty) {
+               player.GetEntity().Orientation(glm::quat(glm::vec3(pitch, yaw, 0.0f)));
+               player.GetEntity().TargetVelocity(glm::rotateY(move_dir * max_vel, yaw));
+
+               Ray aim = player.Aim();
+               if (!world.Intersection(aim, glm::mat4(1.0f), player.GetEntity().ChunkCoords(), aim_world)) {
+                       aim_world = WorldCollision();
+               }
+               if (!world.Intersection(aim, glm::mat4(1.0f), player.GetEntity(), aim_entity)) {
+                       aim_entity = EntityCollision();
+               }
+               if (aim_world && aim_entity) {
+                       // got both, pick the closest one
+                       if (aim_world.depth < aim_entity.depth) {
+                               aim_entity = EntityCollision();
+                       } else {
+                               aim_world = WorldCollision();
+                       }
+               }
+               dirty = false;
+       }
+}
+
+
+DirectInput::DirectInput(World &world, Player &player, WorldManipulator &manip)
+: PlayerController(world, player)
+, manip(manip)
+, place_timer(256)
+, remove_timer(256) {
+
+}
+
+void DirectInput::Update(int dt) {
+       Invalidate(); // world has changed in the meantime
+       UpdatePlayer();
+
+       remove_timer.Update(dt);
+       if (remove_timer.Hit()) {
+               RemoveBlock();
+       }
+
+       place_timer.Update(dt);
+       if (place_timer.Hit()) {
+               PlaceBlock();
+       }
+}
+
 void DirectInput::StartPrimaryAction() {
        if (!remove_timer.Running()) {
                RemoveBlock();
@@ -117,59 +161,29 @@ void DirectInput::StopTertiaryAction() {
        // nothing
 }
 
-void DirectInput::SelectInventory(int i) {
-       player.SetInventorySlot(i);
-}
-
-void DirectInput::UpdatePlayer() {
-       constexpr float max_vel = 0.005f;
-       if (dirty) {
-               player.GetEntity().Orientation(glm::quat(glm::vec3(pitch, yaw, 0.0f)));
-               player.GetEntity().Velocity(glm::rotateY(move_dir * max_vel, yaw));
-
-               Ray aim = player.Aim();
-               if (!world.Intersection(aim, glm::mat4(1.0f), player.GetEntity().ChunkCoords(), aim_world)) {
-                       aim_world = WorldCollision();
-               }
-               if (!world.Intersection(aim, glm::mat4(1.0f), player.GetEntity(), aim_entity)) {
-                       aim_entity = EntityCollision();
-               }
-               if (aim_world && aim_entity) {
-                       // got both, pick the closest one
-                       if (aim_world.depth < aim_entity.depth) {
-                               aim_entity = EntityCollision();
-                       } else {
-                               aim_world = WorldCollision();
-                       }
-               }
-               // TODO: update outline if applicable
-               dirty = false;
-       }
-}
-
 void DirectInput::PickBlock() {
        UpdatePlayer();
-       if (!aim_world) return;
-       player.SetInventorySlot(aim_world.GetBlock().type - 1);
+       if (!BlockFocus()) return;
+       SelectInventory(BlockFocus().GetBlock().type - 1);
 }
 
 void DirectInput::PlaceBlock() {
        UpdatePlayer();
-       if (!aim_world) return;
+       if (!BlockFocus()) return;
 
-       BlockLookup next_block(aim_world.chunk, aim_world.BlockPos(), Block::NormalFace(aim_world.normal));
+       BlockLookup next_block(BlockFocus().chunk, BlockFocus().BlockPos(), Block::NormalFace(BlockFocus().normal));
        if (!next_block) {
                return;
        }
-       manip.SetBlock(next_block.GetChunk(), next_block.GetBlockIndex(), Block(player.GetInventorySlot() + 1));
-       dirty = true;
+       manip.SetBlock(next_block.GetChunk(), next_block.GetBlockIndex(), Block(InventorySlot() + 1));
+       Invalidate();
 }
 
 void DirectInput::RemoveBlock() {
        UpdatePlayer();
-       if (!aim_world) return;
-       manip.SetBlock(aim_world.GetChunk(), aim_world.block, Block(0));
-       dirty = true;
+       if (!BlockFocus()) return;
+       manip.SetBlock(BlockFocus().GetChunk(), BlockFocus().block, Block(0));
+       Invalidate();
 }
 
 
@@ -237,12 +251,12 @@ HUD::HUD(Environment &env, Config &config, const Player &player)
        messages.Background(glm::vec4(0.5f));
 
        // crosshair
-       OutlineModel::Buffer buf;
+       OutlineMesh::Buffer buf;
        buf.vertices = std::vector<glm::vec3>({
                { -10.0f,   0.0f, 0.0f }, { 10.0f,  0.0f, 0.0f },
                {   0.0f, -10.0f, 0.0f }, {  0.0f, 10.0f, 0.0f },
        });
-       buf.indices = std::vector<OutlineModel::Index>({
+       buf.indices = std::vector<OutlineMesh::Index>({
                0, 1, 2, 3
        });
        buf.colors.resize(4, { 10.0f, 10.0f, 10.0f });
@@ -251,7 +265,7 @@ HUD::HUD(Environment &env, Config &config, const Player &player)
 
 namespace {
 
-OutlineModel::Buffer outl_buf;
+OutlineMesh::Buffer outl_buf;
 
 }
 
@@ -259,7 +273,7 @@ void HUD::FocusBlock(const Chunk &chunk, int index) {
        const Block &block = chunk.BlockAt(index);
        const BlockType &type = chunk.Type(index);
        outl_buf.Clear();
-       type.FillOutlineModel(outl_buf);
+       type.FillOutlineMesh(outl_buf);
        outline.Update(outl_buf);
        outline_transform = chunk.Transform(player.GetEntity().ChunkCoords());
        outline_transform *= chunk.ToTransform(Chunk::ToPos(index), index);
@@ -299,7 +313,7 @@ void HUD::DisplayNone() {
 
 void HUD::Display(const BlockType &type) {
        block_buf.Clear();
-       type.FillEntityModel(block_buf);
+       type.FillEntityMesh(block_buf);
        block.Update(block_buf);
 
        block_label.Set(env.assets.small_ui_font, type.label);
@@ -411,22 +425,26 @@ void HUD::Render(Viewport &viewport) noexcept {
 }
 
 
-InteractiveManipulator::InteractiveManipulator(Environment &env, Entity &player)
+InteractiveManipulator::InteractiveManipulator(Audio &audio, const SoundBank &sounds, Entity &player)
 : player(player)
-, audio(env.audio)
-, place_sound(env.loader.LoadSound("thump"))
-, remove_sound(env.loader.LoadSound("plop")) {
+, audio(audio)
+, sounds(sounds) {
 
 }
 
 void InteractiveManipulator::SetBlock(Chunk &chunk, int index, const Block &block) {
+       const BlockType &old_type = chunk.Type(index);
        chunk.SetBlock(index, block);
+       const BlockType &new_type = chunk.Type(index);
        glm::vec3 coords = chunk.ToSceneCoords(player.ChunkCoords(), Chunk::ToCoords(index));
-       // TODO: get sound effect from block type
-       if (block.type == 0) {
-               audio.Play(remove_sound, coords);
+       if (new_type.id == 0) {
+               if (old_type.remove_sound >= 0) {
+                       audio.Play(sounds[old_type.remove_sound], coords);
+               }
        } else {
-               audio.Play(place_sound, coords);
+               if (new_type.place_sound >= 0) {
+                       audio.Play(sounds[new_type.place_sound], coords);
+               }
        }
 }