Skip to content

Commit

Permalink
rework hud alignment system
Browse files Browse the repository at this point in the history
  • Loading branch information
hero622 committed Dec 15, 2023
1 parent 77fa8bd commit d017206
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 59 deletions.
147 changes: 100 additions & 47 deletions src/core/huds/huds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "photon-sdk/photon.h"

#include <algorithm>
#include <cmath>

static sdk::vec2_t get_abs_pos( photon_api::hud_t *hud ) {
Expand All @@ -12,9 +13,16 @@ static sdk::vec2_t get_abs_pos( photon_api::hud_t *hud ) {
}

static void set_abs_pos( photon_api::hud_t *hud, sdk::vec2_t pos ) {
const auto screen_size = photon->render->get_screen_size( );

const auto anchor = hud->anchor * hud->bounds;

hud->pos = photon->render->normalize( pos + anchor );
auto new_pos = pos + anchor;

new_pos.x = std::clamp( new_pos.x, ( float ) huds::safezone_x, screen_size.x - huds::safezone_x );
new_pos.y = std::clamp( new_pos.y, ( float ) huds::safezone_y, screen_size.y - huds::safezone_y );

hud->pos = photon->render->normalize( new_pos );
}

static void set_hud_anchor( photon_api::hud_t *hud ) {
Expand All @@ -37,46 +45,103 @@ static void set_hud_anchor( photon_api::hud_t *hud ) {
hud->anchor.y = 0.5f;
}

static void align_hud_element( photon_api::hud_t *hud, photon_api::hud_t *other_hud ) {
const auto screen_size = photon->render->get_screen_size( );
struct hud_bounds_t {
sdk::vec2_t mins;
sdk::vec2_t maxs;
sdk::vec2_t center;
};

static hud_bounds_t get_hud_bounds( photon_api::hud_t *hud ) {
const auto hud_pos = get_abs_pos( hud );

hud_bounds_t bounds;
bounds.mins = sdk::vec2_t( hud_pos.x, hud_pos.y );
bounds.maxs = sdk::vec2_t( hud_pos.x + hud->bounds.x, hud_pos.y + hud->bounds.y );
bounds.center = sdk::vec2_t( hud_pos.x + hud->bounds.x / 2, hud_pos.y + hud->bounds.y / 2 );

return bounds;
};

/*
* get all distances to all hud element's edges, sort them, align to closest
* this whole thing might be overcomplicated, but this was my best idea
*/
static void align_hud_element( photon_api::hud_t *hud ) {
const auto clr = sdk::color_t( 255, 0, 255, 255 );

const auto hud_pos = get_abs_pos( hud );
const auto other_hud_pos = get_abs_pos( other_hud );

int hud_rect[ 6 ] = {
hud_pos.x,
hud_pos.y,
hud_pos.x + hud->bounds.x,
hud_pos.y + hud->bounds.y,
hud_pos.x + hud->bounds.x / 2,
hud_pos.y + hud->bounds.y / 2 };
int other_hud_rect[ 6 ] = {
other_hud_pos.x,
other_hud_pos.y,
other_hud_pos.x + other_hud->bounds.x,
other_hud_pos.y + other_hud->bounds.y,
other_hud_pos.x + other_hud->bounds.x / 2,
other_hud_pos.y + other_hud->bounds.y / 2 };

// TODO: sort everything by the distance and then use the closest one
for ( int i = 0; i < 6; ++i ) {
for ( int j = 0; j < 6; ++j ) {
if ( i % 2 != j % 2 )
continue;

if ( abs( hud_rect[ i ] - other_hud_rect[ j ] ) < 8 ) {
if ( j % 2 == 0 ) {
hud->pos.x = ( other_hud_rect[ j ] - ( hud_rect[ i ] - hud_rect[ 0 ] ) + hud->anchor.x * hud->bounds.x ) / screen_size.x;
photon->render->draw_line( other_hud_rect[ j ], 0, 0, screen_size.y, clr );
} else {
hud->pos.y = ( other_hud_rect[ j ] - ( hud_rect[ i ] - hud_rect[ 1 ] ) + hud->anchor.y * hud->bounds.y ) / screen_size.y;
photon->render->draw_line( 0, other_hud_rect[ j ], screen_size.x, 0, clr );
const auto screen_size = photon->render->get_screen_size( );
const auto hud_rect = get_hud_bounds( hud );

struct point_distance_t {
sdk::vec2_t pt1; // one of the current hud's points
sdk::vec2_t pt2; // one of the other hud's points
float dist; // squared distance
};
std::vector<point_distance_t> distances;

for ( const auto &other_hud : huds::huds ) {
if ( hud == other_hud )
continue;

const auto other_hud_rect = get_hud_bounds( other_hud );

// loop over all edges
for ( int i = 0; i < 3; ++i ) {
for ( int j = 0; j < 3; ++j ) {
for ( int axis = 0; axis < 2; ++axis ) {
/*
* NOTE: this whole section is using pointer indexing to access struct members
*/

auto pt1 = ( ( sdk::vec2_t * ) &hud_rect )[ i ];
auto pt2 = ( ( sdk::vec2_t * ) &other_hud_rect )[ j ];

// since we align huds on axis, not actually by points, set -1 on the axis we dont use
( ( float * ) &pt1 )[ 1 - axis /* other axis */ ] = -1;
( ( float * ) &pt2 )[ 1 - axis /* other axis */ ] = -1;

// delta pos, again only on one axis
float delta_pos = ( ( float * ) &pt1 )[ axis ] - ( ( float * ) &pt2 )[ axis ];

point_distance_t dist;
dist.pt1 = pt1;
dist.pt2 = pt2;
dist.dist = delta_pos * delta_pos; // squared distance

distances.push_back( dist );
}
}
}
}

// sort points by distance
std::sort( distances.begin( ), distances.end( ), []( const point_distance_t &lhs, const point_distance_t &rhs ) {
return lhs.dist < rhs.dist;
} );

// align hud element x, y but only once per axis
bool was_vertical = false;
for ( int i = 0; i < 2; ++i ) {
const auto &pt_dist = distances[ i ];
const auto vertical = pt_dist.pt2.x == -1; // axis check
const auto hud_pos = get_abs_pos( hud );

// only align once per axis
if ( i == 1 && vertical == was_vertical )
return;

was_vertical = vertical;

if ( pt_dist.dist < 100 ) {
if ( !vertical ) {
hud->pos.x = ( pt_dist.pt2.x - ( pt_dist.pt1.x - hud_pos.x ) ) / screen_size.x;
photon->render->draw_line( pt_dist.pt2.x, 0, 0, screen_size.y, clr );
} else {
hud->pos.y = ( pt_dist.pt2.y - ( pt_dist.pt1.y - hud_pos.y ) ) / screen_size.y;
photon->render->draw_line( 0, pt_dist.pt2.y, screen_size.x, 0, clr );
}
}
}
}

void huds::paint( ) {
Expand Down Expand Up @@ -135,19 +200,7 @@ void huds::paint_ui( ) {

set_abs_pos( hud, photon->input->get_cursor_position( ) - grab_pos );

// dummy hud element for safezone
auto safezone = photon_api::hud_t( );
const auto safezone_vec = sdk::vec2_t( safezone_x, safezone_y );
safezone.pos = photon->render->normalize( safezone_vec );
safezone.bounds = screen_size - sdk::vec2_t( safezone_vec ) * 2;
align_hud_element( hud, &safezone );

for ( const auto &other_hud : huds ) {
if ( hud == other_hud )
continue;

align_hud_element( hud, other_hud );
}
align_hud_element( hud );
}

if ( photon->input->get_key_release( sdk::mouse_left ) ) {
Expand Down
2 changes: 1 addition & 1 deletion src/core/menu/framework.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ bool gui::framework::tab( int &selected, sdk::vec2_t pos, sdk::vec2_t size, std:
photon->portal2->surface->set_clip_rect( 0, 0, photon->render->get_screen_size( ).x, photon->render->get_screen_size( ).y );

photon->render->draw_outlined_rect( pos.x, pos.y, size.x, size.y, active ? colors::white : hover ? colors::dark
: colors::darker );
: colors::darker );
photon->render->draw_filled_rect( pos.x + 1, pos.y + 1, size.x - 2, size.y - 2, colors::bg );

const auto text_size = photon->render->get_text_size( fonts::title, title.c_str( ) );
Expand Down
22 changes: 11 additions & 11 deletions src/core/photon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,25 +109,25 @@ void c_photon::un_pause( ) {}
const char *c_photon::get_plugin_description( ) {
return photon_plugin_sig;
}
void c_photon::level_init( char const *p_map_name ) {}
void c_photon::server_activate( void *p_edict_list, int edict_count, int client_max ) {}
void c_photon::level_init( char const *map_name ) {}
void c_photon::server_activate( void *edict_list, int edict_count, int client_max ) {}
void c_photon::game_frame( bool simulating ) {}
void c_photon::level_shutdown( ) {}
void c_photon::client_fully_connect( void *p_edict ) {}
void c_photon::client_active( void *p_entity ) {}
void c_photon::client_disconnect( void *p_entity ) {}
void c_photon::client_put_in_server( void *p_entity, char const *playername ) {}
void c_photon::client_fully_connect( void *edict ) {}
void c_photon::client_active( void *entity ) {}
void c_photon::client_disconnect( void *entity ) {}
void c_photon::client_put_in_server( void *entity, char const *playername ) {}
void c_photon::set_command_client( int index ) {}
void c_photon::client_settings_changed( void *p_edict ) {}
int c_photon::client_connect( bool *b_allow_connect, void *p_entity, const char *psz_name, const char *psz_address, char *reject, int maxrejectlen ) {
void c_photon::client_settings_changed( void *edict ) {}
int c_photon::client_connect( bool *allow_connect, void *entity, const char *name, const char *address, char *reject, int maxrejectlen ) {
return 0;
}
int c_photon::client_command( void *p_entity, const void *&args ) {
int c_photon::client_command( void *entity, const void *&args ) {
return 0;
}
int c_photon::network_id_validated( const char *psz_user_name, const char *psz_network_id ) {
int c_photon::network_id_validated( const char *user_name, const char *network_id ) {
return 0;
}
void c_photon::on_query_cvar_value_finished( int i_cookie, void *p_player_entity, int e_status, const char *p_cvar_name, const char *p_cvar_value ) {}
void c_photon::on_query_cvar_value_finished( int cookie, void *player_entity, int status, const char *cvar_name, const char *cvar_value ) {}
void c_photon::on_edict_allocated( void *edict ) {}
void c_photon::on_edict_freed( const void *edict ) {}

0 comments on commit d017206

Please sign in to comment.