Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drag Selection #1603

Merged
merged 28 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7b74280
renderer: HUD renderer.
heinezen Nov 19, 2023
a64c2c9
refactor: Solve weird tab/space mixup.
heinezen Nov 20, 2023
449df59
input: Change entity creation to 'CTRL+LMB'.
heinezen Nov 20, 2023
542ff6b
input: Rename engine controller to game controller.
heinezen Nov 20, 2023
ad992b4
input: Event bindings for drag selection box.
heinezen Nov 20, 2023
3e16e5d
gamestate: Drag selection as event.
heinezen Nov 22, 2023
20f8709
input: HUD controller.
heinezen Nov 22, 2023
c8657df
assets: Shader for drag select rectangle.
heinezen Nov 23, 2023
d2f8538
input: Select with viewport transformation.
heinezen Nov 25, 2023
05b1fba
gamestate: Add 'Selectable' component.
heinezen Nov 25, 2023
a532255
gamestate: Assign 'Selectable' component when configured in nyan.
heinezen Nov 25, 2023
16ef5e7
gamestate: Check if an entity is selectable when drag selecting.
heinezen Nov 25, 2023
4247e3c
gamestate: Remove auto-selection on spawning.
heinezen Nov 25, 2023
522bd56
input: Separate method for resetting drag select.
heinezen Nov 25, 2023
b6d33a5
renderer: Add drag select in HUD renderer.
heinezen Nov 25, 2023
f834b05
presenter: Add HUD renderer.
heinezen Nov 25, 2023
6acc008
input: Default actions for HUD controller.
heinezen Nov 25, 2023
248dba6
input: Allow multiple input actions per event.
heinezen Nov 25, 2023
664475f
input: Forward actions to HuD controller.
heinezen Nov 26, 2023
386eb8c
renderer: Fix drag selection rectable vertices.
heinezen Nov 26, 2023
016d874
renderer: Add missing docstrings.
heinezen Nov 26, 2023
f7ce033
renderer: Rename high-level renderers to 'render stage'.
heinezen Nov 26, 2023
7b027b0
renderer: Refactor filenames for render stages.
heinezen Nov 26, 2023
4ad0fb9
input: Reactivate camera actions.
heinezen Nov 26, 2023
b408178
doc: Add HudRenderer description to renderer docs.
heinezen Nov 26, 2023
136471d
renderer: Make sure that alpha is 1 for blend results.
heinezen Nov 26, 2023
4ff5e6d
gamestate: Suppress less useful drag select log messages.
heinezen Dec 25, 2023
a51d2c3
input: Fix missing std::move.
heinezen Dec 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions assets/shaders/hud_drag_select.frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#version 330

// Color of the drag rectangle
uniform vec4 in_col;

layout(location=0) out vec4 out_col;

void main() {
out_col = in_col;
heinezen marked this conversation as resolved.
Show resolved Hide resolved
}
7 changes: 7 additions & 0 deletions assets/shaders/hud_drag_select.vert.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#version 330

layout(location=0) in vec2 position;

void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
12 changes: 6 additions & 6 deletions doc/code/renderer/level2.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ High-level renderer for transforming data from the gamestate to render objects f

## Overview

1. [Level 2](#level-2)
1. [Overview](#overview)
2. [Stages](#stages)
1. [Updating Render Stages from the Gamestate](#updating-render-stages-from-the-gamestate)
3. [Camera](#camera)
1. [Overview](#overview)
2. [Stages](#stages)
1. [Updating Render Stages from the Gamestate](#updating-render-stages-from-the-gamestate)
3. [Camera](#camera)

## Stages

Every stage has its own subrenderer that manages a `RenderPass` from the level 1 renderer and updates it with `Renderable`s created using update information from the gamestate. Stages also store the vertex and fragment shaders used for drawing the renderable objects.

There are currently 5 stages in the level 2 rendering pipeline:
There are currently 6 stages in the level 2 rendering pipeline:

1. `SkyboxRenderer`: Draws the background behind the terrain (as a single color).
1. `TerrainRenderer`: Draws the terrain. Terrains are handled as textured 3D meshes.
1. `WorldRenderer`: Draws animations and sprites for units/buildings and other 2D ingame objects.
1. `HudRenderer`: Draws "Head-Up Display" elements like health bars, selection boxes, and others.
heinezen marked this conversation as resolved.
Show resolved Hide resolved
1. `GuiRenderer`: Draws the GUI overlay. The drawing part in this stage is actually done by Qt, while the level 1 renderer only provides the framebuffer.
1. `ScreenRenderer`: Alpha composites the framebuffer data of previous stages and draws them onto the screen (i.e. it overlays the outputs from the other stages).

Expand Down
1 change: 1 addition & 0 deletions libopenage/gamestate/component/api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ add_sources(libopenage
idle.cpp
live.cpp
move.cpp
selectable.cpp
turn.cpp
)
12 changes: 12 additions & 0 deletions libopenage/gamestate/component/api/selectable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright 2023-2023 the openage authors. See copying.md for legal info.

#include "selectable.h"


namespace openage::gamestate::component {

component_t Selectable::get_type() const {
return component_t::SELECTABLE;
}

} // namespace openage::gamestate::component
20 changes: 20 additions & 0 deletions libopenage/gamestate/component/api/selectable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2023-2023 the openage authors. See copying.md for legal info.

#pragma once

#include <nyan/nyan.h>

#include "gamestate/component/api_component.h"
#include "gamestate/component/types.h"


namespace openage::gamestate::component {

class Selectable : public APIComponent {
public:
using APIComponent::APIComponent;

component_t get_type() const override;
};

} // namespace openage::gamestate::component
1 change: 1 addition & 0 deletions libopenage/gamestate/component/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum class component_t {
IDLE,
TURN,
MOVE,
SELECTABLE,
LIVE
};

Expand Down
5 changes: 5 additions & 0 deletions libopenage/gamestate/entity_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "gamestate/component/api/idle.h"
#include "gamestate/component/api/live.h"
#include "gamestate/component/api/move.h"
#include "gamestate/component/api/selectable.h"
#include "gamestate/component/api/turn.h"
#include "gamestate/component/internal/activity.h"
#include "gamestate/component/internal/command_queue.h"
Expand Down Expand Up @@ -203,6 +204,10 @@ void EntityFactory::init_components(const std::shared_ptr<openage::event::EventL
else if (ability_parent == "engine.ability.type.Activity") {
activity_ability = ability_obj;
}
else if (ability_parent == "engine.ability.type.Selectable") {
auto selectable = std::make_shared<component::Selectable>(loop, ability_obj);
entity->add_component(selectable);
}
}

if (activity_ability) {
Expand Down
1 change: 1 addition & 0 deletions libopenage/gamestate/event/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_sources(libopenage
drag_select.cpp
process_command.cpp
send_command.cpp
spawn_entity.cpp
Expand Down
100 changes: 100 additions & 0 deletions libopenage/gamestate/event/drag_select.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2023-2023 the openage authors. See copying.md for legal info.

#include "drag_select.h"

#include <eigen3/Eigen/Dense>

#include "coord/phys.h"
#include "coord/pixel.h"
#include "coord/scene.h"
#include "curve/discrete.h"
#include "gamestate/component/internal/ownership.h"
#include "gamestate/component/internal/position.h"
#include "gamestate/game_entity.h"
#include "gamestate/game_state.h"
#include "gamestate/types.h"


namespace openage::gamestate::event {

DragSelectHandler::DragSelectHandler() :
OnceEventHandler{"game.drag_select"} {}

void DragSelectHandler::setup_event(const std::shared_ptr<openage::event::Event> & /* event */,
const std::shared_ptr<openage::event::State> & /* state */) {
// TODO
}

void DragSelectHandler::invoke(openage::event::EventLoop & /* loop */,
const std::shared_ptr<openage::event::EventEntity> & /* target */,
const std::shared_ptr<openage::event::State> &state,
const time::time_t &time,
const param_map &params) {
auto gstate = std::dynamic_pointer_cast<openage::gamestate::GameState>(state);

size_t controlled_id = params.get("controlled", 0);

Eigen::Matrix4f id_matrix = Eigen::Matrix4f::Identity();
Eigen::Matrix4f cam_matrix = params.get("camera_matrix", id_matrix);
Eigen::Vector2f drag_start = params.get("drag_start", Eigen::Vector2f{0, 0});
Eigen::Vector2f drag_end = params.get("drag_end", Eigen::Vector2f{0, 0});

// Boundaries of the rectangle
float top = std::max(drag_start.y(), drag_end.y());
float bottom = std::min(drag_start.y(), drag_end.y());
float left = std::min(drag_start.x(), drag_end.x());
float right = std::max(drag_start.x(), drag_end.x());

log::log(SPAM << "Drag select rectangle (NDC):");
log::log(SPAM << "\tTop: " << top);
log::log(SPAM << "\tBottom: " << bottom);
log::log(SPAM << "\tLeft: " << left);
log::log(SPAM << "\tRight: " << right);

std::vector<entity_id_t> selected;
for (auto &entity : gstate->get_game_entities()) {
heinezen marked this conversation as resolved.
Show resolved Hide resolved
if (not entity.second->has_component(component::component_t::SELECTABLE)) {
// skip entities that are not selectable
continue;
}

// Check if the entity is owned by the controlled player
// TODO: Check this using Selectable diplomatic property
auto owner = std::dynamic_pointer_cast<component::Ownership>(
entity.second->get_component(component::component_t::OWNERSHIP));
if (owner->get_owners().get(time) != controlled_id) {
// only select entities of the controlled player
continue;
}

// Get the position of the entity in the viewport
auto pos = std::dynamic_pointer_cast<component::Position>(
entity.second->get_component(component::component_t::POSITION));
auto current_pos = pos->get_positions().get(time);
auto world_pos = current_pos.to_scene3().to_world_space();
Eigen::Vector4f clip_pos = cam_matrix * Eigen::Vector4f{world_pos.x(), world_pos.y(), world_pos.z(), 1};
TheJJ marked this conversation as resolved.
Show resolved Hide resolved

// Check if the entity is in the rectangle
if (clip_pos.x() > left
and clip_pos.x() < right
and clip_pos.y() > bottom
and clip_pos.y() < top) {
selected.push_back(entity.first);
}
}

// Select the units
auto select_cb = params.get("select_cb",
std::function<void(const std::vector<entity_id_t> ids)>{
[](const std::vector<entity_id_t> /* ids */) {}});
select_cb(selected);
}

time::time_t DragSelectHandler::predict_invoke_time(const std::shared_ptr<openage::event::EventEntity> & /* target */,
const std::shared_ptr<openage::event::State> & /* state */,
const time::time_t &at) {
return at;
}


} // namespace openage::gamestate::event
46 changes: 46 additions & 0 deletions libopenage/gamestate/event/drag_select.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2023-2023 the openage authors. See copying.md for legal info.

#pragma once

#include <cstddef>
#include <memory>
#include <string>

#include "event/evententity.h"
#include "event/eventhandler.h"


namespace openage {

namespace event {
class EventLoop;
class Event;
class State;
} // namespace event

namespace gamestate::event {

/**
* Drag select game entities.
*/
class DragSelectHandler : public openage::event::OnceEventHandler {
heinezen marked this conversation as resolved.
Show resolved Hide resolved
public:
DragSelectHandler();
~DragSelectHandler() = default;

void setup_event(const std::shared_ptr<openage::event::Event> &event,
const std::shared_ptr<openage::event::State> &state) override;

void invoke(openage::event::EventLoop &loop,
const std::shared_ptr<openage::event::EventEntity> &target,
const std::shared_ptr<openage::event::State> &state,
const time::time_t &time,
const param_map &params) override;

time::time_t predict_invoke_time(const std::shared_ptr<openage::event::EventEntity> &target,
const std::shared_ptr<openage::event::State> &state,
const time::time_t &at) override;
};

} // namespace gamestate::event
} // namespace openage
5 changes: 0 additions & 5 deletions libopenage/gamestate/event/spawn_entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,6 @@ void SpawnEntityHandler::invoke(openage::event::EventLoop & /* loop */,
activity->init(time);
entity->get_manager()->run_activity_system(time);

// TODO: Select the unit when it's created
// very dumb but it gets the job done
auto select_cb = params.get("select_cb", std::function<void(entity_id_t id)>{[](entity_id_t /* id */) {}});
select_cb(entity->get_id());

gstate->add_game_entity(entity);
}

Expand Down
2 changes: 1 addition & 1 deletion libopenage/gamestate/game_entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "gamestate/component/api/move.h"
#include "gamestate/component/base_component.h"
#include "gamestate/component/internal/position.h"
#include "renderer/stages/world/world_render_entity.h"
#include "renderer/stages/world/render_entity.h"

namespace openage::gamestate {

Expand Down
2 changes: 2 additions & 0 deletions libopenage/gamestate/game_entity.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ class GameEntity {

/**
* Data components.
*
* TODO: Multiple components of the same type.
*/
std::unordered_map<component::component_t, std::shared_ptr<component::Component>> components;

Expand Down
3 changes: 3 additions & 0 deletions libopenage/gamestate/simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "assets/mod_manager.h"
#include "event/event_loop.h"
#include "gamestate/entity_factory.h"
#include "gamestate/event/drag_select.h"
#include "gamestate/event/process_command.h"
#include "gamestate/event/send_command.h"
#include "gamestate/event/spawn_entity.h"
Expand Down Expand Up @@ -133,11 +134,13 @@ void GameSimulation::set_modpacks(const std::vector<std::string> &modpacks) {
}

void GameSimulation::init_event_handlers() {
auto drag_select_handler = std::make_shared<gamestate::event::DragSelectHandler>();
auto spawn_handler = std::make_shared<gamestate::event::SpawnEntityHandler>(this->event_loop,
this->entity_factory);
auto command_handler = std::make_shared<gamestate::event::SendCommandHandler>();
auto manager_handler = std::make_shared<gamestate::event::ProcessCommandHandler>();
auto wait_handler = std::make_shared<gamestate::event::WaitHandler>();
this->event_loop->add_event_handler(drag_select_handler);
this->event_loop->add_event_handler(spawn_handler);
this->event_loop->add_event_handler(command_handler);
this->event_loop->add_event_handler(manager_handler);
Expand Down
2 changes: 1 addition & 1 deletion libopenage/gamestate/terrain_chunk.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#include "coord/tile.h"
#include "gamestate/terrain_tile.h"
#include "renderer/stages/terrain/terrain_render_entity.h"
#include "renderer/stages/terrain/render_entity.h"
#include "time/time.h"
#include "util/vector.h"

Expand Down
2 changes: 1 addition & 1 deletion libopenage/gamestate/terrain_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "gamestate/terrain_chunk.h"
#include "gamestate/terrain_tile.h"
#include "renderer/render_factory.h"
#include "renderer/stages/terrain/terrain_render_entity.h"
#include "renderer/stages/terrain/render_entity.h"
#include "time/time.h"

#include "assets/mod_manager.h"
Expand Down
3 changes: 2 additions & 1 deletion libopenage/input/action.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ enum class input_action_t {
PUSH_CONTEXT,
POP_CONTEXT,
REMOVE_CONTEXT,
ENGINE,
GAME,
CAMERA,
HUD,
GUI,
CUSTOM,
};
Expand Down
1 change: 1 addition & 0 deletions libopenage/input/controller/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory("camera")
add_subdirectory("game")
add_subdirectory("hud")
14 changes: 8 additions & 6 deletions libopenage/input/controller/camera/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "input/event.h"


namespace openage {

namespace renderer::camera {
Expand All @@ -27,12 +28,13 @@ class Controller {
~Controller() = default;

/**
* Process an input event from the input manager.
*
* @param ev Input event and arguments.
*
* @return true if the event is accepted, else false.
*/
* Process an input event from the input manager.
*
* @param ev Input event and arguments.
* @param ctx Binding context that maps input events to camera actions.
*
* @return true if the event is accepted, else false.
*/
bool process(const event_arguments &ev_args, const std::shared_ptr<BindingContext> &ctx);
};

Expand Down
2 changes: 1 addition & 1 deletion libopenage/input/controller/game/binding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

namespace openage::input::game {

} // namespace openage::input::engine
} // namespace openage::input::game
2 changes: 1 addition & 1 deletion libopenage/input/controller/game/binding_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ const binding_action &BindingContext::lookup(const Event &ev) const {
throw Error{MSG(err) << "Event is not bound in binding_action context."};
}

} // namespace openage::input::engine
} // namespace openage::input::game
2 changes: 1 addition & 1 deletion libopenage/input/controller/game/binding_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ class BindingContext {
std::unordered_map<event_class, binding_action, event_class_hash> by_class;
};

} // namespace openage::input::engine
} // namespace openage::input::game