Skip to content

Commit

Permalink
Merge pull request #50 from tgfrerer/feature-gamepad
Browse files Browse the repository at this point in the history
merge Feature gamepad
  • Loading branch information
tgfrerer authored Mar 27, 2023
2 parents 6d49abf + 34d0c56 commit b7f6022
Show file tree
Hide file tree
Showing 9 changed files with 431 additions and 59 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ can build a single, statically linked and optimised binary.
reverse-ssh or similar to forward localhost::3535 and you can
remotely connect to a running app from all over the world.

* **Gamepad** support: the default camera can be steered with
a gamepad-just connect your gamepad and you are set; application
windows can decide whether they want to subscribe to gamepad events
- and to which gamepads to subscribe to.

* **Multi-Window** Island allows you to hook up multiple swapchains to
a single application. You can dynamically add and remove swapchains
while your Island application is running. This is particularly useful
Expand Down
2 changes: 1 addition & 1 deletion modules/le_backend_vk/le_backend_vk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2000,7 +2000,7 @@ static bool backend_poll_frame_fence( le_backend_o* self, size_t frameIndex ) {
logger.error( "Poll Frame Fence returned: %s", to_str_vk_result( result ) );
exit( 1 );
} else if ( result != VK_SUCCESS ) {
logger.error( "Poll Frame Fence returned: %s", to_str_vk_result( result ) );
logger.warn( "Poll Frame Fence returned: %s", to_str_vk_result( result ) );
return false;
} else {
return true;
Expand Down
83 changes: 75 additions & 8 deletions modules/le_camera/le_camera.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "le_camera.h"
#include "le_core.h"

#include "modules/le_log/le_log.h"
#include "private/le_renderer/le_renderer_types.h" // for le::Viewport
#include "le_ui_event.h"

Expand Down Expand Up @@ -92,7 +93,7 @@ static void update_frustum_planes( le_camera_o* self ) {
float fPL[ 6 ]{};
for ( size_t i = 0; i != 6; i++ ) {
// get the length (= magnitude of the .xyz part of the row), so that we can normalize later
fPL[ i ] = glm::vec3( fP[ i ].x, fP[ i ].y, fP[ i ].z ).length();
fPL[ i ] = glm::distance(glm::vec3( fP[ i ].x, fP[ i ].y, fP[ i ].z ), glm::vec3(0));
}

for ( size_t i = 0; i < 6; i++ ) {
Expand Down Expand Up @@ -289,6 +290,19 @@ void camera_translate_xy( le_camera_o* camera, glm::mat4 const& world_to_cam_sta
camera->view_matrix = glm::inverse( world_to_cam );
}

// ----------------------------------------------------------------------
void camera_translate_xyz( le_camera_o* camera, glm::mat4 const& world_to_cam_start, glm::vec3 const& signedNorm, float movement_speed, float pivotDistance ) {

float distance_to_origin = glm::distance( glm::vec4{ 0, 0, 0, 1 }, world_to_cam_start * glm::vec4( 0, 0, 0, 1 ) );
movement_speed *= distance_to_origin;

auto pivot = glm::translate( world_to_cam_start, glm::vec3{ 0, 0, -pivotDistance } );
pivot = glm::translate( pivot, movement_speed * glm::vec3{ signedNorm.x, signedNorm.y, signedNorm.z } );
auto world_to_cam = glm::translate( pivot, glm::vec3{ 0, 0, pivotDistance } );

camera->view_matrix = glm::inverse( world_to_cam );
}

// ----------------------------------------------------------------------

void camera_translate_z( le_camera_o* camera, glm::mat4 const& world_to_cam_start, glm::vec3 const& signedNorm, float movement_speed, float pivotDistance ) {
Expand Down Expand Up @@ -326,6 +340,8 @@ static void camera_controller_update_camera( le_camera_controller_o* controller,
}

for ( auto const& event : events ) {
glm::vec3 translationDelta{};
glm::vec3 rotationDelta{};

// -- accumulate mouse state

Expand Down Expand Up @@ -355,21 +371,56 @@ static void camera_controller_update_camera( le_camera_controller_o* controller,
if ( e.action == LeUiEvent::ButtonAction::ePress ) {
// set appropriate button flag
mouse_state.buttonState |= ( 1 << e.button );

} else if ( e.action == LeUiEvent::ButtonAction::eRelease ) {
// null appropriate button flag
mouse_state.buttonState &= ~( 1 << e.button );
// set camera controller into neutral state if any button was released.
controller->mode = le_camera_controller_o::eNeutral;
}
} break;
case ( LeUiEvent::Type::eGamepad ): {
auto& e = event->gamepad;

// We must make sure that axes are not drifting ... if any of the values are below axes_epsilon, they shall be zero.
// Therefore, we ignore any values that are within the +- drift range; we then remap the range so that we still cover -1..1
auto remove_drift = []( glm::vec3 const& vec_input, glm::vec3 const& drift_tolerance = glm::vec3( 0.1f ) ) -> glm::vec3 {
glm::vec3 abs_val = glm::abs( vec_input );
glm::vec3 sign_val = glm::sign( vec_input );

glm::vec3 test_val = abs_val - drift_tolerance;
test_val = max( glm::vec3( 0.f ), test_val );
test_val = test_val * sign_val;
// todo: map back to original range.
return test_val / ( glm::vec3( 1.f ) - drift_tolerance );
};

glm::vec3 gamepad_x_y_z = {
e.axes[ uint32_t( le::UiEvent::NamedGamepadAxis::eLeftX ) ],
e.axes[ uint32_t( le::UiEvent::NamedGamepadAxis::eLeftY ) ],
( ( e.axes[ uint32_t( le::UiEvent::NamedGamepadAxis::eLeftTrigger ) ] + 1 ) -
( e.axes[ uint32_t( le::UiEvent::NamedGamepadAxis::eRightTrigger ) ] + 1 ) ),
};

translationDelta += 0.01f * remove_drift( gamepad_x_y_z, glm::vec3( 0.1 ) );
;

glm::vec3 gamepad_rot = {
e.axes[ uint32_t( le::UiEvent::NamedGamepadAxis::eRightX ) ],
e.axes[ uint32_t( le::UiEvent::NamedGamepadAxis::eRightY ) ],
0.f };

gamepad_rot = remove_drift( gamepad_rot, glm::vec3( 0.1 ) );

rotationDelta.x = glm::two_pi<float>() * -0.0025f * gamepad_rot.x;
rotationDelta.y = glm::two_pi<float>() * 0.0025f * gamepad_rot.y;

break;
}
default:
break;
}

glm::vec3 rotationDelta;
glm::vec3 translationDelta;
{
if ( mouse_state.buttonState ) {
auto mouseInitial = controller->mouse_pos_initial - controlRectCentre;
float mouseInitialAngle = glm::two_pi<float>() - fmodf( glm::two_pi<float>() + atan2f( mouseInitial.y, mouseInitial.x ), glm::two_pi<float>() ); // Range is expected to be 0..2pi, ccw

Expand All @@ -389,6 +440,18 @@ static void camera_controller_update_camera( le_camera_controller_o* controller,
switch ( controller->mode ) {
case le_camera_controller_o::eNeutral: {

if ( event->event == le::UiEvent::Type::eGamepad ) {

float movement_speed = 0.5;
static auto logger = le::Log( "le_camera" );
controller->world_to_cam = glm::inverse( camera->view_matrix );
camera_translate_xyz( camera, controller->world_to_cam, translationDelta, movement_speed, controller->pivotDistance );
controller->world_to_cam = glm::inverse( camera->view_matrix );
camera_orbit_xy( camera, controller->world_to_cam, rotationDelta, controller->pivotDistance );
controller->world_to_cam = glm::inverse( camera->view_matrix );
continue;
}

if ( false == is_inside_rect( mouse_state.cursor_pos, controller->controlRect ) ) {
// if camera is outside the control rect, we don't care.
continue;
Expand Down Expand Up @@ -458,7 +521,10 @@ static void camera_controller_process_events( le_camera_controller_o* controller
filtered_events.reserve( numEvents );

for ( auto event = events; event != events_end; event++ ) {
if ( event->event == LeUiEvent::Type::eCursorPosition || event->event == LeUiEvent::Type::eMouseButton || event->event == LeUiEvent::Type::eKey ) {
if ( event->event == LeUiEvent::Type::eCursorPosition ||
event->event == LeUiEvent::Type::eMouseButton ||
event->event == LeUiEvent::Type::eKey ||
event->event == LeUiEvent::Type::eGamepad ) {
filtered_events.emplace_back( event );
}
}
Expand Down Expand Up @@ -510,7 +576,8 @@ static void camera_controller_set_pivot_distance( le_camera_controller_o* self,
// ----------------------------------------------------------------------

LE_MODULE_REGISTER_IMPL( le_camera, api ) {
auto& le_camera_i = static_cast<le_camera_api*>( api )->le_camera_i;
auto api_i = static_cast<le_camera_api*>( api );
auto& le_camera_i = api_i->le_camera_i;

le_camera_i.create = le_camera_create;
le_camera_i.destroy = le_camera_destroy;
Expand All @@ -529,7 +596,7 @@ LE_MODULE_REGISTER_IMPL( le_camera, api ) {
le_camera_i.get_sphere_in_frustum = camera_get_sphere_in_frustum;
le_camera_i.set_is_orthographic = camera_set_is_orthographic;

auto& le_camera_controller_i = static_cast<le_camera_api*>( api )->le_camera_controller_i;
auto& le_camera_controller_i = api_i->le_camera_controller_i;

le_camera_controller_i.create = camera_controller_create;
le_camera_controller_i.destroy = camera_controller_destroy;
Expand Down
2 changes: 1 addition & 1 deletion modules/le_file_watcher/le_tweakable.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
# include "le_core.h"

# include "le_file_watcher.h"
# include "le_log.h"
# include "le_log.h" ///< if you get an error message saying that this header can't be found, make sure that the module that uses le_tweakable has a line saying `depends_on_island_module(le_log)` in its CMake file.

# include <fstream>
# include <iostream>
Expand Down
12 changes: 6 additions & 6 deletions modules/le_mesh/le_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ struct le_mesh_api {

void (*clear)(le_mesh_o* self);

void (*get_vertices )( le_mesh_o *self, size_t& count, float const ** vertices);
void (*get_normals )( le_mesh_o *self, size_t& count, float const ** normals );
void (*get_colours )( le_mesh_o *self, size_t& count, float const ** colours );
void (*get_uvs )( le_mesh_o *self, size_t& count, float const ** uvs );
void (*get_tangents )( le_mesh_o *self, size_t& count, float const ** tangents);
void (*get_indices )( le_mesh_o *self, size_t& count, uint16_t const ** indices );
void (*get_vertices )( le_mesh_o *self, size_t& count, float const ** vertices); // 3 floats per vertex
void (*get_normals )( le_mesh_o *self, size_t& count, float const ** normals ); // 3 floats per vertex
void (*get_colours )( le_mesh_o *self, size_t& count, float const ** colours ); // 4 floats per vertex
void (*get_uvs )( le_mesh_o *self, size_t& count, float const ** uvs ); // 3 floats per vertex
void (*get_tangents )( le_mesh_o *self, size_t& count, float const ** tangents); // 3 floats per vertex
void (*get_indices )( le_mesh_o *self, size_t& count, uint16_t const ** indices ); // 1 uint16_t per index

void (*get_data )( le_mesh_o *self, size_t& numVertices, size_t& numIndices, float const** vertices, float const **normals, float const **uvs, float const ** colours, uint16_t const **indices);

Expand Down
79 changes: 69 additions & 10 deletions modules/le_ui_event/le_ui_event.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,41 @@
#pragma once
#include <stdint.h>

// Todo: move this to a frame-work wide internal header file.

struct LeUiEvent {
enum class NamedGamepadButton : uint32_t {
eA = 0,
eB = 1,
eX = 2,
eY = 3,
eLeftBumper = 4,
eRightBumper = 5,
eBack = 6,
eStart = 7,
eGuide = 8,
eLeftThumb = 9,
eRightThumb = 10,
eDpadUp = 11,
eDpadRight = 12,
eDpadDown = 13,
eDpadLeft = 14,
//
eLast = eDpadLeft,
//
eCross = eA,
eCircle = eB,
eSquare = eX,
eTriangle = eY,
};

enum class NamedGamepadAxis : uint32_t {
eLeftX = 0,
eLeftY = 1,
eRightX = 2,
eRightY = 3,
eLeftTrigger = 4,
eRightTrigger = 5,
eLast = eRightTrigger,
};

enum class NamedKey : int32_t {
eUnknown = -1,
Expand Down Expand Up @@ -138,13 +170,15 @@ struct LeUiEvent {
};

enum class Type : uint32_t {
eKey = 1 << 0,
eCharacter = 1 << 1,
eCursorPosition = 1 << 2,
eCursorEnter = 1 << 3,
eMouseButton = 1 << 4,
eScroll = 1 << 5,
eDrop = 1 << 6,
eUnknown = 0,
eKey,
eCharacter,
eCursorPosition,
eCursorEnter,
eMouseButton,
eScroll,
eDrop,
eGamepad,
};

struct KeyEvent {
Expand Down Expand Up @@ -183,7 +217,29 @@ struct LeUiEvent {
uint64_t paths_count;
};

Type event;
struct GamepadEvent {
float axes[ 6 ]; // -1 to 1 (inclusive for each axis)
uint16_t buttons; // [0] : 0..14 bitset, 0 is least significant bit
uint16_t gamepad_id; // 0..15

bool get_button_at( uint8_t index ) const noexcept {
return index < 15 ? ( buttons & ( uint16_t( 1 ) << index ) ) : false;
}

bool operator==( GamepadEvent const& rhs ) {
return axes[ 0 ] == rhs.axes[ 0 ] &&
axes[ 1 ] == rhs.axes[ 1 ] &&
axes[ 2 ] == rhs.axes[ 2 ] &&
axes[ 3 ] == rhs.axes[ 3 ] &&
axes[ 4 ] == rhs.axes[ 4 ] &&
axes[ 5 ] == rhs.axes[ 5 ] &&
buttons == rhs.buttons;
}

bool operator!=( GamepadEvent const& rhs ) {
return !( *this == rhs );
}
};

union {
KeyEvent key;
Expand All @@ -193,7 +249,10 @@ struct LeUiEvent {
MouseButtonEvent mouseButton;
ScrollEvent scroll;
DropEvent drop;
GamepadEvent gamepad;
};

Type event;
};

namespace le {
Expand Down
2 changes: 1 addition & 1 deletion modules/le_window/3rdparty/glfw
Loading

0 comments on commit b7f6022

Please sign in to comment.