player focus dir relative to player. raw mouse input. crosshair.
This commit is contained in:
parent
aa8dd7a4fa
commit
bdd8db60c3
BIN
res/graphics/crosshair.ase
(Stored with Git LFS)
Normal file
BIN
res/graphics/crosshair.ase
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -32,7 +32,6 @@ INTERNAL u32 peek_bits(struct bitbuf *bb, u32 nbits)
|
|||||||
val32 &= U32_MAX >> (32 - nbits);
|
val32 &= U32_MAX >> (32 - nbits);
|
||||||
|
|
||||||
return val32;
|
return val32;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL u32 consume_bits(struct bitbuf *bb, u32 nbits)
|
INTERNAL u32 consume_bits(struct bitbuf *bb, u32 nbits)
|
||||||
|
|||||||
19
src/config.h
19
src/config.h
@ -7,10 +7,7 @@
|
|||||||
|
|
||||||
#define PIXELS_PER_UNIT 256
|
#define PIXELS_PER_UNIT 256
|
||||||
|
|
||||||
#define AUDIO_ENABLED 0
|
#define GAME_FPS 50
|
||||||
#define VSYNC_ENABLED 0
|
|
||||||
|
|
||||||
#define GAME_FPS 30
|
|
||||||
|
|
||||||
#define USER_FRAME_LIMIT 300
|
#define USER_FRAME_LIMIT 300
|
||||||
|
|
||||||
@ -18,4 +15,16 @@
|
|||||||
* Delay ms = USER_INTERP_OFFSET_TICK_RATIO * Game tick rate
|
* Delay ms = USER_INTERP_OFFSET_TICK_RATIO * Game tick rate
|
||||||
* E.g: At 1.5, the user thread will render 49.5ms back in time (if game thread runs at 30FPS)
|
* E.g: At 1.5, the user thread will render 49.5ms back in time (if game thread runs at 30FPS)
|
||||||
*/
|
*/
|
||||||
#define USER_INTERP_OFFSET_TICK_RATIO 1.5
|
#define USER_INTERP_OFFSET_TICK_RATIO 1.2
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Settings
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
/* TODO: Move these to user-configurable settings */
|
||||||
|
|
||||||
|
#define AUDIO_ENABLED 0
|
||||||
|
#define VSYNC_ENABLED 0
|
||||||
|
|
||||||
|
#define MOUSE_SENSITIVITY 1.5
|
||||||
|
|||||||
@ -295,13 +295,13 @@ void draw_text_ex(struct renderer_canvas *canvas, struct font *font, struct v2 p
|
|||||||
|
|
||||||
struct clip_rect clip = {
|
struct clip_rect clip = {
|
||||||
{
|
{
|
||||||
glyph->atlas_rect.x / font->texture.width,
|
glyph->atlas_rect.x / font->texture.size.x,
|
||||||
glyph->atlas_rect.y / font->texture.height
|
glyph->atlas_rect.y / font->texture.size.y
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
(glyph->atlas_rect.x + glyph->atlas_rect.width) / font->texture.width,
|
(glyph->atlas_rect.x + glyph->atlas_rect.width) / font->texture.size.x,
|
||||||
(glyph->atlas_rect.y + glyph->atlas_rect.height) / font->texture.height
|
(glyph->atlas_rect.y + glyph->atlas_rect.height) / font->texture.size.y
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
27
src/entity.c
27
src/entity.c
@ -63,11 +63,18 @@ void entity_release(struct entity_store *store, struct entity *entity)
|
|||||||
store->first_free = handle;
|
store->first_free = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Lookup
|
* Query
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
struct entity_array entity_store_as_array(struct entity_store *store)
|
||||||
|
{
|
||||||
|
return (struct entity_array) {
|
||||||
|
.entities = (struct entity *)store->arena.base,
|
||||||
|
.count = store->count
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns a valid entity or nil entity. Always safe to read result, need to check to write. */
|
/* Returns a valid entity or nil entity. Always safe to read result, need to check to write. */
|
||||||
struct entity *entity_from_handle(struct entity_store *store, struct entity_handle handle)
|
struct entity *entity_from_handle(struct entity_store *store, struct entity_handle handle)
|
||||||
{
|
{
|
||||||
@ -81,6 +88,22 @@ struct entity *entity_from_handle(struct entity_store *store, struct entity_hand
|
|||||||
return entity_nil();
|
return entity_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct entity *entity_find_first_with_prop(struct entity_store *store, enum entity_prop prop)
|
||||||
|
{
|
||||||
|
struct entity_array entities_array = entity_store_as_array(store);
|
||||||
|
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||||
|
struct entity *ent = &entities_array.entities[entity_index];
|
||||||
|
if (ent->valid && entity_has_prop(ent, prop)) {
|
||||||
|
return ent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entity_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Tree
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
void entity_link(struct entity_store *store, struct entity *parent, struct entity *child)
|
void entity_link(struct entity_store *store, struct entity *parent, struct entity *child)
|
||||||
{
|
{
|
||||||
struct entity *first_child = entity_from_handle(store, parent->first);
|
struct entity *first_child = entity_from_handle(store, parent->first);
|
||||||
|
|||||||
@ -14,7 +14,6 @@ enum entity_prop {
|
|||||||
/* Test props */
|
/* Test props */
|
||||||
|
|
||||||
ENTITY_PROP_TEST,
|
ENTITY_PROP_TEST,
|
||||||
ENTITY_PROP_TEST_FOLLOW_MOUSE,
|
|
||||||
ENTITY_PROP_TEST_SOUND_EMITTER,
|
ENTITY_PROP_TEST_SOUND_EMITTER,
|
||||||
|
|
||||||
ENTITY_PROP_COUNT
|
ENTITY_PROP_COUNT
|
||||||
@ -60,6 +59,7 @@ struct entity {
|
|||||||
/* ENTITY_PROP_PLAYER_CONTROLLED */
|
/* ENTITY_PROP_PLAYER_CONTROLLED */
|
||||||
f32 player_max_speed;
|
f32 player_max_speed;
|
||||||
f32 player_acceleration;
|
f32 player_acceleration;
|
||||||
|
struct v2 player_focus_dir;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Sprite */
|
/* Sprite */
|
||||||
@ -146,7 +146,11 @@ void entity_store_copy_replace(struct entity_store *dest, struct entity_store *s
|
|||||||
/* Entity */
|
/* Entity */
|
||||||
struct entity *entity_alloc(struct entity_store *store);
|
struct entity *entity_alloc(struct entity_store *store);
|
||||||
void entity_release(struct entity_store *store, struct entity *entity);
|
void entity_release(struct entity_store *store, struct entity *entity);
|
||||||
|
|
||||||
|
struct entity_array entity_store_as_array(struct entity_store *store);
|
||||||
struct entity *entity_from_handle(struct entity_store *store, struct entity_handle handle);
|
struct entity *entity_from_handle(struct entity_store *store, struct entity_handle handle);
|
||||||
|
struct entity *entity_find_first_with_prop(struct entity_store *store, enum entity_prop prop);
|
||||||
|
|
||||||
void entity_link(struct entity_store *store, struct entity *parent, struct entity *child);
|
void entity_link(struct entity_store *store, struct entity *parent, struct entity *child);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -119,8 +119,7 @@ INTERNAL void font_load_asset_task(void *vparams)
|
|||||||
/* Set font data */
|
/* Set font data */
|
||||||
font->texture = (struct texture) {
|
font->texture = (struct texture) {
|
||||||
.renderer_handle = texture_renderer_handle,
|
.renderer_handle = texture_renderer_handle,
|
||||||
.width = result.image_data.width,
|
.size = V2(result.image_data.width, result.image_data.height),
|
||||||
.height = result.image_data.height
|
|
||||||
};
|
};
|
||||||
font->glyphs_count = result.glyphs_count;
|
font->glyphs_count = result.glyphs_count;
|
||||||
font->point_size = point_size;
|
font->point_size = point_size;
|
||||||
|
|||||||
34
src/game.c
34
src/game.c
@ -121,6 +121,7 @@ INTERNAL void game_update(void)
|
|||||||
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
|
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
|
||||||
e->player_max_speed = 5.f;
|
e->player_max_speed = 5.f;
|
||||||
e->player_acceleration = 15.0f;
|
e->player_acceleration = 15.0f;
|
||||||
|
e->player_focus_dir = V2(0, -1);
|
||||||
|
|
||||||
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
|
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
|
||||||
|
|
||||||
@ -180,7 +181,7 @@ INTERNAL void game_update(void)
|
|||||||
entity_link(&L.world.entity_store, parent, e);
|
entity_link(&L.world.entity_store, parent, e);
|
||||||
|
|
||||||
if (sys_rand_u32() % 2 == 0) {
|
if (sys_rand_u32() % 2 == 0) {
|
||||||
u64 parent_idx = sys_rand_u32() % world_get_entities(&L.world).count;
|
u64 parent_idx = sys_rand_u32() % entity_store_as_array(&L.world.entity_store).count;
|
||||||
struct entity *rand_ent = entity_from_handle(&L.world.entity_store, (struct entity_handle) { .idx = parent_idx, .gen = 1 });
|
struct entity *rand_ent = entity_from_handle(&L.world.entity_store, (struct entity_handle) { .idx = parent_idx, .gen = 1 });
|
||||||
if (rand_ent->valid) {
|
if (rand_ent->valid) {
|
||||||
parent = rand_ent;
|
parent = rand_ent;
|
||||||
@ -208,13 +209,13 @@ INTERNAL void game_update(void)
|
|||||||
L.world.tick_ts = sys_timestamp();
|
L.world.tick_ts = sys_timestamp();
|
||||||
L.world.dt = max_f64(0.0, (1.0 / GAME_FPS) * L.world.timescale);
|
L.world.dt = max_f64(0.0, (1.0 / GAME_FPS) * L.world.timescale);
|
||||||
L.world.time += L.world.dt;
|
L.world.time += L.world.dt;
|
||||||
struct entity_array entities_array = world_get_entities(&L.world);
|
struct entity_array entities_array = entity_store_as_array(&L.world.entity_store);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Process game cmds
|
* Process game cmds
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
L.world.player_move_dir = V2(0, 0);
|
L.world.player_focus_move_dir = V2(0, 0);
|
||||||
|
|
||||||
struct game_cmd_array game_cmds = pop_cmds(scratch.arena);
|
struct game_cmd_array game_cmds = pop_cmds(scratch.arena);
|
||||||
for (u64 cmd_index = 0; cmd_index < game_cmds.count; ++cmd_index) {
|
for (u64 cmd_index = 0; cmd_index < game_cmds.count; ++cmd_index) {
|
||||||
@ -223,13 +224,8 @@ INTERNAL void game_update(void)
|
|||||||
switch (cmd.kind) {
|
switch (cmd.kind) {
|
||||||
/* Movement */
|
/* Movement */
|
||||||
case GAME_CMD_KIND_PLAYER_MOVE: {
|
case GAME_CMD_KIND_PLAYER_MOVE: {
|
||||||
struct v2 dir = cmd.dir;
|
L.world.player_move_dir = cmd.move_dir;
|
||||||
L.world.player_move_dir = v2_add(L.world.player_move_dir, dir);
|
L.world.player_focus_move_dir = v2_add(L.world.player_focus_move_dir, cmd.focus_move_dir);
|
||||||
} break;
|
|
||||||
|
|
||||||
/* Focus */
|
|
||||||
case GAME_CMD_KIND_PLAYER_FOCUS: {
|
|
||||||
L.world.player_focus = cmd.pos;
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
/* Clear level */
|
/* Clear level */
|
||||||
@ -361,26 +357,20 @@ INTERNAL void game_update(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Player look direction
|
* Player focus
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
||||||
|
/* Update focus */
|
||||||
|
ent->player_focus_dir = v2_add(ent->player_focus_dir, L.world.player_focus_move_dir);
|
||||||
|
|
||||||
|
/* Update view angle */
|
||||||
struct v2 ent_pos = ent->rel_xform.og;
|
struct v2 ent_pos = ent->rel_xform.og;
|
||||||
struct v2 look_pos = L.world.player_focus;
|
struct v2 look_pos = v2_add(ent_pos, ent->player_focus_dir);
|
||||||
f32 r = v2_angle_to_point(ent_pos, look_pos) + PI / 2;
|
f32 r = v2_angle_to_point(ent_pos, look_pos) + PI / 2;
|
||||||
ent->rel_xform = xform_with_rotation(ent->rel_xform, r);
|
ent->rel_xform = xform_with_rotation(ent->rel_xform, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Update position from mouse
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
/* ENTITY_PROP_TEST_FOLLOW_MOUSE */
|
|
||||||
if (entity_has_prop(ent, ENTITY_PROP_TEST_FOLLOW_MOUSE)) {
|
|
||||||
ent->rel_xform.og = L.world.player_focus;
|
|
||||||
ent->test_start_rel_xform.og = L.world.player_focus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Calculate xforms
|
* Calculate xforms
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
@ -7,7 +7,6 @@ enum game_cmd_kind {
|
|||||||
GAME_CMD_KIND_NONE,
|
GAME_CMD_KIND_NONE,
|
||||||
|
|
||||||
GAME_CMD_KIND_PLAYER_MOVE,
|
GAME_CMD_KIND_PLAYER_MOVE,
|
||||||
GAME_CMD_KIND_PLAYER_FOCUS,
|
|
||||||
|
|
||||||
/* Testing */
|
/* Testing */
|
||||||
GAME_CMD_KIND_CLEAR_ALL,
|
GAME_CMD_KIND_CLEAR_ALL,
|
||||||
@ -19,10 +18,8 @@ struct game_cmd {
|
|||||||
enum game_cmd_kind kind;
|
enum game_cmd_kind kind;
|
||||||
|
|
||||||
/* GAME_CMD_KIND_PLAYER_MOVE */
|
/* GAME_CMD_KIND_PLAYER_MOVE */
|
||||||
struct v2 dir;
|
struct v2 move_dir;
|
||||||
|
struct v2 focus_move_dir;
|
||||||
/* GAME_CMD_KIND_PLAYER_FOCUS */
|
|
||||||
struct v2 pos;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct game_cmd_array {
|
struct game_cmd_array {
|
||||||
|
|||||||
36
src/math.h
36
src/math.h
@ -323,6 +323,22 @@ INLINE struct v2 v2_round(struct v2 a)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INLINE struct v2 v2_floor(struct v2 a)
|
||||||
|
{
|
||||||
|
return V2(
|
||||||
|
(f32)math_floor(a.x),
|
||||||
|
(f32)math_floor(a.y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE struct v2 v2_ceil(struct v2 a)
|
||||||
|
{
|
||||||
|
return V2(
|
||||||
|
(f32)math_ceil(a.x),
|
||||||
|
(f32)math_ceil(a.y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
INLINE f32 v2_dot(struct v2 a, struct v2 b)
|
INLINE f32 v2_dot(struct v2 a, struct v2 b)
|
||||||
{
|
{
|
||||||
return a.x * b.x + a.y * b.y;
|
return a.x * b.x + a.y * b.y;
|
||||||
@ -751,4 +767,24 @@ INLINE struct quad quad_mul_xform(struct quad quad, struct xform m)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INLINE struct quad quad_round(struct quad quad)
|
||||||
|
{
|
||||||
|
return (struct quad) {
|
||||||
|
v2_round(quad.p1),
|
||||||
|
v2_round(quad.p2),
|
||||||
|
v2_round(quad.p3),
|
||||||
|
v2_round(quad.p4)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE struct quad quad_floor(struct quad quad)
|
||||||
|
{
|
||||||
|
return (struct quad) {
|
||||||
|
v2_floor(quad.p1),
|
||||||
|
v2_round(quad.p2),
|
||||||
|
v2_round(quad.p3),
|
||||||
|
v2_round(quad.p4)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
18
src/sys.h
18
src/sys.h
@ -13,10 +13,9 @@ enum sys_event_kind {
|
|||||||
|
|
||||||
SYS_EVENT_KIND_BUTTON_DOWN,
|
SYS_EVENT_KIND_BUTTON_DOWN,
|
||||||
SYS_EVENT_KIND_BUTTON_UP,
|
SYS_EVENT_KIND_BUTTON_UP,
|
||||||
//SYS_EVENT_KIND_MOUSE_MOVE,
|
SYS_EVENT_KIND_MOUSE_MOVE,
|
||||||
|
SYS_EVENT_KIND_RAW_MOUSE_MOVE,
|
||||||
SYS_EVENT_KIND_TEXT,
|
SYS_EVENT_KIND_TEXT,
|
||||||
|
|
||||||
SYS_EVENT_KIND_QUIT,
|
SYS_EVENT_KIND_QUIT,
|
||||||
|
|
||||||
SYS_EVENT_KIND_COUNT
|
SYS_EVENT_KIND_COUNT
|
||||||
@ -134,7 +133,10 @@ struct sys_event {
|
|||||||
|
|
||||||
u32 text_character;
|
u32 text_character;
|
||||||
|
|
||||||
struct v2 position;
|
struct v2 mouse_position;
|
||||||
|
struct v2 mouse_delta;
|
||||||
|
|
||||||
|
struct v2 raw_mouse_delta;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sys_event_array {
|
struct sys_event_array {
|
||||||
@ -276,14 +278,18 @@ struct sys_window_settings sys_window_get_settings(struct sys_window *sys_window
|
|||||||
|
|
||||||
void sys_window_show(struct sys_window *sys_window);
|
void sys_window_show(struct sys_window *sys_window);
|
||||||
|
|
||||||
|
void sys_window_set_cursor_pos(struct sys_window *sys_window, struct v2 pos);
|
||||||
|
|
||||||
struct v2 sys_window_get_size(struct sys_window *sys_window);
|
struct v2 sys_window_get_size(struct sys_window *sys_window);
|
||||||
struct v2 sys_window_get_monitor_size(struct sys_window *sys_window);
|
struct v2 sys_window_get_monitor_size(struct sys_window *sys_window);
|
||||||
|
|
||||||
struct v2 sys_window_get_mouse_pos(struct sys_window *sys_window);
|
|
||||||
|
|
||||||
/* Returns a platform specific representation of the window. E.g. `hwnd` on win32. */
|
/* Returns a platform specific representation of the window. E.g. `hwnd` on win32. */
|
||||||
u64 sys_window_get_internal_handle(struct sys_window *sys_window);
|
u64 sys_window_get_internal_handle(struct sys_window *sys_window);
|
||||||
|
|
||||||
|
void sys_window_cursor_set_pos(struct sys_window *sys_window, struct v2 pos);
|
||||||
|
void sys_window_cursor_show(struct sys_window *sys_window);
|
||||||
|
void sys_window_cursor_hide(struct sys_window *sys_window);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Mutex
|
* Mutex
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
164
src/sys_win32.c
164
src/sys_win32.c
@ -11,6 +11,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
#include <ShlObj_core.h>
|
#include <ShlObj_core.h>
|
||||||
#include <fileapi.h>
|
#include <fileapi.h>
|
||||||
#include <dwmapi.h>
|
#include <dwmapi.h>
|
||||||
@ -31,13 +32,21 @@ struct win32_condition_variable {
|
|||||||
struct win32_condition_variable *next_free;
|
struct win32_condition_variable *next_free;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum win32_window_cursor_set_flag {
|
||||||
|
WIN32_WINDOW_CURSOR_SET_FLAG_NONE = 0x0,
|
||||||
|
WIN32_WINDOW_CURSOR_SET_FLAG_POSITION = 0x1,
|
||||||
|
WIN32_WINDOW_CURSOR_SET_FLAG_HIDE = 0x2,
|
||||||
|
WIN32_WINDOW_CURSOR_SET_FLAG_SHOW = 0x4
|
||||||
|
};
|
||||||
|
|
||||||
struct win32_window {
|
struct win32_window {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
|
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
|
u32 tid;
|
||||||
struct sync_flag ready_sf;
|
struct sync_flag ready_sf;
|
||||||
|
|
||||||
struct sys_mutex settings_mutex;
|
struct sys_rw_mutex settings_rw_mutex;
|
||||||
struct sys_window_settings settings;
|
struct sys_window_settings settings;
|
||||||
|
|
||||||
i32 monitor_width;
|
i32 monitor_width;
|
||||||
@ -48,6 +57,10 @@ struct win32_window {
|
|||||||
* their pre-minimized values) */
|
* their pre-minimized values) */
|
||||||
i32 x, y, width, height;
|
i32 x, y, width, height;
|
||||||
|
|
||||||
|
struct v2 cursor_pos;
|
||||||
|
u32 cursor_set_flags;
|
||||||
|
struct v2 cursor_set_position;
|
||||||
|
|
||||||
b32 event_thread_shutdown;
|
b32 event_thread_shutdown;
|
||||||
struct sys_thread event_thread;
|
struct sys_thread event_thread;
|
||||||
|
|
||||||
@ -488,14 +501,14 @@ void sys_dir_iter_end(struct sys_dir_iter *iter)
|
|||||||
INTERNAL void win32_update_window_from_system(struct win32_window *window);
|
INTERNAL void win32_update_window_from_system(struct win32_window *window);
|
||||||
|
|
||||||
INTERNAL void win32_window_process_event(struct win32_window *window, struct sys_event event)
|
INTERNAL void win32_window_process_event(struct win32_window *window, struct sys_event event)
|
||||||
{
|
|
||||||
{
|
{
|
||||||
sys_mutex_lock(&window->event_callbacks_mutex);
|
sys_mutex_lock(&window->event_callbacks_mutex);
|
||||||
|
{
|
||||||
for (u64 i = 0; i < window->event_callbacks_count; ++i) {
|
for (u64 i = 0; i < window->event_callbacks_count; ++i) {
|
||||||
window->event_callbacks[i](event);
|
window->event_callbacks[i](event);
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&window->event_callbacks_mutex);
|
|
||||||
}
|
}
|
||||||
|
sys_mutex_unlock(&window->event_callbacks_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL HWND win32_create_window(struct win32_window *window)
|
INTERNAL HWND win32_create_window(struct win32_window *window)
|
||||||
@ -541,6 +554,7 @@ INTERNAL void window_thread_entry_point(void *arg)
|
|||||||
|
|
||||||
/* Win32 limitation: Window must be initialized on same thread that processes events */
|
/* Win32 limitation: Window must be initialized on same thread that processes events */
|
||||||
window->hwnd = win32_create_window(window);
|
window->hwnd = win32_create_window(window);
|
||||||
|
window->tid = sys_thread_id();
|
||||||
win32_update_window_from_system(window);
|
win32_update_window_from_system(window);
|
||||||
BringWindowToTop(window->hwnd);
|
BringWindowToTop(window->hwnd);
|
||||||
|
|
||||||
@ -561,9 +575,33 @@ INTERNAL void window_thread_entry_point(void *arg)
|
|||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: update mouse pos w/ GetCursorPos */
|
/* Update cursor */
|
||||||
|
if (GetFocus() == window->hwnd) {
|
||||||
|
u32 cursor_flags = window->cursor_set_flags;
|
||||||
|
|
||||||
|
/* Hide cursor */
|
||||||
|
if (cursor_flags & WIN32_WINDOW_CURSOR_SET_FLAG_HIDE) {
|
||||||
|
while(ShowCursor(false) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Show cursor */
|
||||||
|
if (cursor_flags & WIN32_WINDOW_CURSOR_SET_FLAG_SHOW) {
|
||||||
|
while(ShowCursor(true) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update position */
|
||||||
|
if (cursor_flags & WIN32_WINDOW_CURSOR_SET_FLAG_POSITION) {
|
||||||
|
struct v2 window_space_pos = window->cursor_set_position;
|
||||||
|
POINT p = { window_space_pos.x, window_space_pos.y };
|
||||||
|
ClientToScreen(window->hwnd, &p);
|
||||||
|
SetCursorPos(p.x, p.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
window->cursor_set_flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Destroy window hwnd */
|
/* Destroy window hwnd */
|
||||||
DestroyWindow(window->hwnd);
|
DestroyWindow(window->hwnd);
|
||||||
}
|
}
|
||||||
@ -588,7 +626,7 @@ INTERNAL struct win32_window *win32_window_alloc(void)
|
|||||||
window->ready_sf = sync_flag_alloc();
|
window->ready_sf = sync_flag_alloc();
|
||||||
|
|
||||||
/* Allocate mutexes */
|
/* Allocate mutexes */
|
||||||
window->settings_mutex = sys_mutex_alloc();
|
window->settings_rw_mutex = sys_rw_mutex_alloc();
|
||||||
window->event_callbacks_mutex = sys_mutex_alloc();
|
window->event_callbacks_mutex = sys_mutex_alloc();
|
||||||
|
|
||||||
/* Start window thread for processing events */
|
/* Start window thread for processing events */
|
||||||
@ -613,7 +651,7 @@ INTERNAL void win32_window_release(struct win32_window *window)
|
|||||||
|
|
||||||
/* Release mutexes */
|
/* Release mutexes */
|
||||||
sys_mutex_release(&window->event_callbacks_mutex);
|
sys_mutex_release(&window->event_callbacks_mutex);
|
||||||
sys_mutex_release(&window->settings_mutex);
|
sys_rw_mutex_release(&window->settings_rw_mutex);
|
||||||
|
|
||||||
/* Release sync flag */
|
/* Release sync flag */
|
||||||
sync_flag_release(&window->ready_sf);
|
sync_flag_release(&window->ready_sf);
|
||||||
@ -729,17 +767,10 @@ INTERNAL void win32_update_window_from_settings(struct win32_window *window, str
|
|||||||
SetWindowTextA(hwnd, settings->title);
|
SetWindowTextA(hwnd, settings->title);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL struct v2 win32_window_get_mouse_pos(struct win32_window *window)
|
INTERNAL void win32_window_wake(struct win32_window *window)
|
||||||
{
|
{
|
||||||
HWND hwnd = window->hwnd;
|
/* Post a blank message to the window's thread message queue to wake it. */
|
||||||
|
PostThreadMessageA(window->tid, 0, 0, 0);
|
||||||
struct v2 res = V2(0, 0);
|
|
||||||
POINT p;
|
|
||||||
if (GetCursorPos(&p) && ScreenToClient(hwnd, &p)) {
|
|
||||||
res = V2(p.x, p.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||||
@ -867,7 +898,7 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
|
|||||||
(struct sys_event) {
|
(struct sys_event) {
|
||||||
.kind = event_kind,
|
.kind = event_kind,
|
||||||
.button = button,
|
.button = button,
|
||||||
.position = win32_window_get_mouse_pos(window)
|
.mouse_position = window->cursor_pos
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -885,6 +916,53 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
/* Mouse move */
|
||||||
|
case WM_MOUSEMOVE: {
|
||||||
|
i32 x = GET_X_LPARAM(lparam);
|
||||||
|
i32 y = GET_Y_LPARAM(lparam);
|
||||||
|
struct v2 old = window->cursor_pos;
|
||||||
|
window->cursor_pos = V2(x, y);
|
||||||
|
struct v2 delta = v2_sub(window->cursor_pos, old);
|
||||||
|
win32_window_process_event(
|
||||||
|
window,
|
||||||
|
(struct sys_event) {
|
||||||
|
.kind = SYS_EVENT_KIND_MOUSE_MOVE,
|
||||||
|
.mouse_position = window->cursor_pos,
|
||||||
|
.mouse_delta = delta
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
/* Raw mouse move */
|
||||||
|
case WM_INPUT: {
|
||||||
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
|
|
||||||
|
/* Read raw input buffer */
|
||||||
|
UINT buff_size;
|
||||||
|
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &buff_size, sizeof(RAWINPUTHEADER));
|
||||||
|
u8 *buff = arena_push_array_zero(scratch.arena, u8, buff_size);
|
||||||
|
if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, buff, &buff_size, sizeof(RAWINPUTHEADER)) != buff_size) {
|
||||||
|
logf_error("GetRawInputData did not return correct size");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RAWINPUT *raw = (RAWINPUT *)buff;
|
||||||
|
|
||||||
|
if (raw->header.dwType == RIM_TYPEMOUSE) {
|
||||||
|
i32 x = raw->data.mouse.lLastX;
|
||||||
|
i32 y = raw->data.mouse.lLastY;
|
||||||
|
struct v2 delta = V2(x, y);
|
||||||
|
win32_window_process_event(
|
||||||
|
window,
|
||||||
|
(struct sys_event) {
|
||||||
|
.kind = SYS_EVENT_KIND_RAW_MOUSE_MOVE,
|
||||||
|
.raw_mouse_delta = delta
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
result = DefWindowProcA(hwnd, msg, wparam, lparam);
|
result = DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||||
@ -930,7 +1008,6 @@ void sys_window_unregister_event_callback(struct sys_window *sys_window, sys_win
|
|||||||
|
|
||||||
sys_mutex_lock(&window->event_callbacks_mutex);
|
sys_mutex_lock(&window->event_callbacks_mutex);
|
||||||
{
|
{
|
||||||
|
|
||||||
u64 count = window->event_callbacks_count;
|
u64 count = window->event_callbacks_count;
|
||||||
sys_window_event_callback_func *last = count > 0 ? window->event_callbacks[count - 1] : NULL;
|
sys_window_event_callback_func *last = count > 0 ? window->event_callbacks[count - 1] : NULL;
|
||||||
|
|
||||||
@ -951,11 +1028,11 @@ void sys_window_update_settings(struct sys_window *sys_window, struct sys_window
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
||||||
sys_mutex_lock(&window->settings_mutex);
|
sys_rw_mutex_lock_exclusive(&window->settings_rw_mutex);
|
||||||
{
|
{
|
||||||
win32_update_window_from_settings(window, settings);
|
win32_update_window_from_settings(window, settings);
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&window->settings_mutex);
|
sys_rw_mutex_unlock_exclusive(&window->settings_rw_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Lock settings mutex for these functions */
|
/* TODO: Lock settings mutex for these functions */
|
||||||
@ -970,7 +1047,7 @@ void sys_window_show(struct sys_window *sys_window)
|
|||||||
{
|
{
|
||||||
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
||||||
HWND hwnd = window->hwnd;
|
HWND hwnd = window->hwnd;
|
||||||
sys_mutex_lock(&window->settings_mutex);
|
sys_rw_mutex_lock_exclusive(&window->settings_rw_mutex);
|
||||||
{
|
{
|
||||||
i32 show_cmd = SW_NORMAL;
|
i32 show_cmd = SW_NORMAL;
|
||||||
struct sys_window_settings *settings = &window->settings;
|
struct sys_window_settings *settings = &window->settings;
|
||||||
@ -983,7 +1060,7 @@ void sys_window_show(struct sys_window *sys_window)
|
|||||||
ShowWindow(hwnd, show_cmd);
|
ShowWindow(hwnd, show_cmd);
|
||||||
BringWindowToTop(hwnd);
|
BringWindowToTop(hwnd);
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&window->settings_mutex);
|
sys_rw_mutex_unlock_exclusive(&window->settings_rw_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct v2 sys_window_get_size(struct sys_window *sys_window)
|
struct v2 sys_window_get_size(struct sys_window *sys_window)
|
||||||
@ -998,18 +1075,34 @@ struct v2 sys_window_get_monitor_size(struct sys_window *sys_window)
|
|||||||
return V2((f32)window->monitor_width, (f32)window->monitor_height);
|
return V2((f32)window->monitor_width, (f32)window->monitor_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct v2 sys_window_get_mouse_pos(struct sys_window *sys_window)
|
|
||||||
{
|
|
||||||
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
|
||||||
return win32_window_get_mouse_pos(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 sys_window_get_internal_handle(struct sys_window *sys_window)
|
u64 sys_window_get_internal_handle(struct sys_window *sys_window)
|
||||||
{
|
{
|
||||||
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
||||||
return (u64)window->hwnd;
|
return (u64)window->hwnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sys_window_cursor_set_pos(struct sys_window *sys_window, struct v2 pos)
|
||||||
|
{
|
||||||
|
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
||||||
|
window->cursor_set_position = pos;
|
||||||
|
window->cursor_set_flags |= WIN32_WINDOW_CURSOR_SET_FLAG_POSITION;
|
||||||
|
win32_window_wake(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_window_cursor_show(struct sys_window *sys_window)
|
||||||
|
{
|
||||||
|
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
||||||
|
window->cursor_set_flags |= WIN32_WINDOW_CURSOR_SET_FLAG_SHOW;
|
||||||
|
win32_window_wake(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_window_cursor_hide(struct sys_window *sys_window)
|
||||||
|
{
|
||||||
|
struct win32_window *window = (struct win32_window *)sys_window->handle;
|
||||||
|
window->cursor_set_flags |= WIN32_WINDOW_CURSOR_SET_FLAG_HIDE;
|
||||||
|
win32_window_wake(window);
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Mutex
|
* Mutex
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -1719,6 +1812,21 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Register raw input */
|
||||||
|
{
|
||||||
|
RAWINPUTDEVICE rid = (RAWINPUTDEVICE) {
|
||||||
|
.usUsagePage = 0x01, /* HID_USAGE_PAGE_GENERIC */
|
||||||
|
.usUsage = 0x02, /* HID_USAGE_GENERIC_MOUSE */
|
||||||
|
//.dwFlags = RIDEV_NOLEGACY /* Adds mouse and also ignores legacy mouse messages */
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
|
||||||
|
/* TODO: GetLastError */
|
||||||
|
error_msg = "Failed to register raw input device";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (error_msg) {
|
if (error_msg) {
|
||||||
MessageBoxExA(NULL, error_msg, "Fatal initialization error", MB_ICONSTOP, 0);
|
MessageBoxExA(NULL, error_msg, "Fatal initialization error", MB_ICONSTOP, 0);
|
||||||
|
|||||||
@ -167,8 +167,7 @@ INTERNAL void texture_load_asset_task(void *vparams)
|
|||||||
struct asset_cache_store store = asset_cache_store_open();
|
struct asset_cache_store store = asset_cache_store_open();
|
||||||
texture = arena_push(store.arena, struct texture);
|
texture = arena_push(store.arena, struct texture);
|
||||||
*texture = (struct texture) {
|
*texture = (struct texture) {
|
||||||
.width = image_data.width,
|
.size = V2(image_data.width, image_data.height),
|
||||||
.height = image_data.height,
|
|
||||||
.renderer_handle = handle
|
.renderer_handle = handle
|
||||||
};
|
};
|
||||||
asset_cache_store_close(&store);
|
asset_cache_store_close(&store);
|
||||||
@ -200,9 +199,8 @@ abort:
|
|||||||
struct asset_cache_store store = asset_cache_store_open();
|
struct asset_cache_store store = asset_cache_store_open();
|
||||||
texture = arena_push(store.arena, struct texture);
|
texture = arena_push(store.arena, struct texture);
|
||||||
*texture = (struct texture) {
|
*texture = (struct texture) {
|
||||||
.width = default_image_data.width,
|
.renderer_handle = handle,
|
||||||
.height = default_image_data.height,
|
.size = V2(default_image_data.width, default_image_data.height)
|
||||||
.renderer_handle = handle
|
|
||||||
};
|
};
|
||||||
asset_cache_store_close(&store);
|
asset_cache_store_close(&store);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,8 +23,7 @@ struct texture_anim {
|
|||||||
|
|
||||||
struct texture {
|
struct texture {
|
||||||
struct renderer_handle renderer_handle;
|
struct renderer_handle renderer_handle;
|
||||||
u32 width;
|
struct v2 size;
|
||||||
u32 height;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void texture_startup(void);
|
void texture_startup(void);
|
||||||
|
|||||||
216
src/user.c
216
src/user.c
@ -30,6 +30,7 @@ struct view {
|
|||||||
struct bind_state {
|
struct bind_state {
|
||||||
b32 is_held; /* Is this bind held down this frame */
|
b32 is_held; /* Is this bind held down this frame */
|
||||||
u32 num_presses; /* How many times was this bind pressed since last frame */
|
u32 num_presses; /* How many times was this bind pressed since last frame */
|
||||||
|
u32 num_releases; /* How many times was this bind released since last frame */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct blend_tick {
|
struct blend_tick {
|
||||||
@ -57,7 +58,7 @@ GLOBAL struct {
|
|||||||
|
|
||||||
b32 debug_camera;
|
b32 debug_camera;
|
||||||
b32 debug_camera_panning;
|
b32 debug_camera_panning;
|
||||||
struct v2 debug_camera_panning_from;
|
struct v2 debug_camera_pan_start;
|
||||||
|
|
||||||
b32 debug_draw;
|
b32 debug_draw;
|
||||||
|
|
||||||
@ -71,6 +72,9 @@ GLOBAL struct {
|
|||||||
struct v2 screen_size;
|
struct v2 screen_size;
|
||||||
struct v2 screen_center;
|
struct v2 screen_center;
|
||||||
struct v2 screen_mouse;
|
struct v2 screen_mouse;
|
||||||
|
struct v2 screen_mouse_delta;
|
||||||
|
struct v2 world_mouse;
|
||||||
|
struct v2 last_focus_screen_pos;
|
||||||
} L = { 0 }, DEBUG_LVAR(L_user);
|
} L = { 0 }, DEBUG_LVAR(L_user);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -91,7 +95,8 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = {
|
|||||||
[SYS_BTN_F6] = USER_BIND_KIND_DEBUG_DRAW,
|
[SYS_BTN_F6] = USER_BIND_KIND_DEBUG_DRAW,
|
||||||
[SYS_BTN_F7] = USER_BIND_KIND_DEBUG_CAMERA,
|
[SYS_BTN_F7] = USER_BIND_KIND_DEBUG_CAMERA,
|
||||||
[SYS_BTN_MWHEELUP] = USER_BIND_KIND_ZOOM_IN,
|
[SYS_BTN_MWHEELUP] = USER_BIND_KIND_ZOOM_IN,
|
||||||
[SYS_BTN_MWHEELDOWN] = USER_BIND_KIND_ZOOM_OUT
|
[SYS_BTN_MWHEELDOWN] = USER_BIND_KIND_ZOOM_OUT,
|
||||||
|
[SYS_BTN_M3] = USER_BIND_KIND_PAN
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -314,22 +319,17 @@ INTERNAL struct xform view_get_xform(struct view view)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL struct v2 view_xform_point(struct view view, struct v2 p)
|
INTERNAL struct v2 view_xform_v2(struct view view, struct v2 p)
|
||||||
{
|
{
|
||||||
struct xform mtx = view_get_xform(view);
|
struct xform mtx = view_get_xform(view);
|
||||||
return xform_mul_v2(mtx, p);
|
return xform_mul_v2(mtx, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL struct v2 view_inverse_xform_point(struct view view, struct v2 p)
|
INTERNAL struct v2 view_inverse_xform_v2(struct view view, struct v2 p)
|
||||||
{
|
{
|
||||||
return xform_invert_mul_v2(view_get_xform(view), p);
|
return xform_invert_mul_v2(view_get_xform(view), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL struct v2 view_mouse_pos(struct view view)
|
|
||||||
{
|
|
||||||
return view_inverse_xform_point(view, L.screen_mouse);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Update
|
* Update
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -395,7 +395,6 @@ INTERNAL void user_update(void)
|
|||||||
L.screen_center = v2_mul(L.screen_size, 0.5);
|
L.screen_center = v2_mul(L.screen_size, 0.5);
|
||||||
|
|
||||||
/* Read input */
|
/* Read input */
|
||||||
L.screen_mouse = sys_window_get_mouse_pos(L.window);
|
|
||||||
struct sys_event_array events = pop_sys_events(scratch.arena);
|
struct sys_event_array events = pop_sys_events(scratch.arena);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -409,6 +408,8 @@ INTERNAL void user_update(void)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
L.screen_mouse_delta = V2(0, 0);
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < events.count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < events.count; ++entity_index) {
|
||||||
struct sys_event *event = &events.events[entity_index];
|
struct sys_event *event = &events.events[entity_index];
|
||||||
|
|
||||||
@ -421,16 +422,6 @@ INTERNAL void user_update(void)
|
|||||||
app_quit();
|
app_quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move camera/view */
|
|
||||||
if (event->button == SYS_BTN_M3) {
|
|
||||||
if (event->kind == SYS_EVENT_KIND_BUTTON_DOWN) {
|
|
||||||
L.debug_camera_panning = true;
|
|
||||||
L.debug_camera_panning_from = view_mouse_pos(L.world_view);
|
|
||||||
} else if (event->kind == SYS_EVENT_KIND_BUTTON_UP) {
|
|
||||||
L.debug_camera_panning = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->kind == SYS_EVENT_KIND_BUTTON_UP) {
|
if (event->kind == SYS_EVENT_KIND_BUTTON_UP) {
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
/* Escape quit */
|
/* Escape quit */
|
||||||
@ -453,6 +444,16 @@ INTERNAL void user_update(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update mouse pos */
|
||||||
|
if (event->kind == SYS_EVENT_KIND_MOUSE_MOVE) {
|
||||||
|
L.screen_mouse = event->mouse_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update mouse delta */
|
||||||
|
if (event->kind == SYS_EVENT_KIND_RAW_MOUSE_MOVE) {
|
||||||
|
L.screen_mouse_delta = v2_add(L.screen_mouse_delta, event->raw_mouse_delta);
|
||||||
|
}
|
||||||
|
|
||||||
/* Update bind states */
|
/* Update bind states */
|
||||||
if ((event->kind == SYS_EVENT_KIND_BUTTON_DOWN || event->kind == SYS_EVENT_KIND_BUTTON_UP) && !event->is_repeat) {
|
if ((event->kind == SYS_EVENT_KIND_BUTTON_DOWN || event->kind == SYS_EVENT_KIND_BUTTON_UP) && !event->is_repeat) {
|
||||||
enum sys_btn button = event->button;
|
enum sys_btn button = event->button;
|
||||||
@ -463,52 +464,13 @@ INTERNAL void user_update(void)
|
|||||||
L.bind_states[bind].is_held = pressed;
|
L.bind_states[bind].is_held = pressed;
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
++L.bind_states[bind].num_presses;
|
++L.bind_states[bind].num_presses;
|
||||||
|
} else {
|
||||||
|
++L.bind_states[bind].num_releases;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Process movement input
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
/* Movement */
|
|
||||||
{
|
|
||||||
struct v2 input_move_dir = { 0 };
|
|
||||||
for (enum user_bind_kind bind = 0; bind < (i32)ARRAY_COUNT(L.bind_states); ++bind) {
|
|
||||||
struct bind_state state = L.bind_states[bind];
|
|
||||||
|
|
||||||
if (!state.is_held && state.num_presses <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (bind) {
|
|
||||||
/* Movement */
|
|
||||||
case USER_BIND_KIND_MOVE_UP: {
|
|
||||||
input_move_dir.y -= 1;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case USER_BIND_KIND_MOVE_DOWN: {
|
|
||||||
input_move_dir.y += 1;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case USER_BIND_KIND_MOVE_LEFT: {
|
|
||||||
input_move_dir.x -= 1;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case USER_BIND_KIND_MOVE_RIGHT: {
|
|
||||||
input_move_dir.x += 1;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queue_game_cmd(&cmd_list, (struct game_cmd) {
|
|
||||||
.kind = GAME_CMD_KIND_PLAYER_MOVE,
|
|
||||||
.dir = v2_norm(input_move_dir)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Debug commands
|
* Debug commands
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -532,18 +494,27 @@ INTERNAL void user_update(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (L.bind_states[USER_BIND_KIND_DEBUG_CAMERA].num_presses > 0) {
|
if (L.bind_states[USER_BIND_KIND_DEBUG_CAMERA].num_presses > 0) {
|
||||||
|
if (!L.debug_camera) {
|
||||||
|
/* Move cursor to last crosshair pos */
|
||||||
|
sys_window_cursor_set_pos(L.window, L.last_focus_screen_pos);
|
||||||
|
}
|
||||||
L.debug_camera = !L.debug_camera;
|
L.debug_camera = !L.debug_camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (L.debug_camera) {
|
if (L.debug_camera) {
|
||||||
|
sys_window_cursor_show(L.window);
|
||||||
//L.world_view.rot += 1 * (f32)L.dt;
|
|
||||||
|
|
||||||
/* Pan view */
|
/* Pan view */
|
||||||
if (L.debug_camera_panning) {
|
if (L.bind_states[USER_BIND_KIND_PAN].is_held) {
|
||||||
struct v2 offset = v2_sub(L.debug_camera_panning_from, view_mouse_pos(L.world_view));
|
if (!L.debug_camera_panning) {
|
||||||
|
L.debug_camera_pan_start = view_inverse_xform_v2(L.world_view, L.screen_mouse);
|
||||||
|
}
|
||||||
|
L.debug_camera_panning = true;
|
||||||
|
struct v2 offset = v2_sub(L.debug_camera_pan_start, view_inverse_xform_v2(L.world_view, L.screen_mouse));
|
||||||
L.world_view.center = v2_add(L.world_view.center, offset);
|
L.world_view.center = v2_add(L.world_view.center, offset);
|
||||||
L.debug_camera_panning_from = view_mouse_pos(L.world_view);
|
L.debug_camera_pan_start = view_inverse_xform_v2(L.world_view, L.screen_mouse);
|
||||||
|
} else {
|
||||||
|
L.debug_camera_panning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zoom view */
|
/* Zoom view */
|
||||||
@ -566,14 +537,65 @@ INTERNAL void user_update(void)
|
|||||||
new_zoom = clamp_f32(new_zoom, zoom_min, zoom_max);
|
new_zoom = clamp_f32(new_zoom, zoom_min, zoom_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct v2 old_mouse = view_mouse_pos(L.world_view);
|
struct v2 old_mouse = view_inverse_xform_v2(L.world_view, L.screen_mouse);
|
||||||
L.world_view.zoom = new_zoom;
|
L.world_view.zoom = new_zoom;
|
||||||
struct v2 new_mouse = view_mouse_pos(L.world_view);
|
struct v2 new_mouse = view_inverse_xform_v2(L.world_view, L.screen_mouse);
|
||||||
|
|
||||||
/* Offset view to zoom in on mouse */
|
/* Offset view to zoom in on mouse */
|
||||||
struct v2 offset = v2_sub(old_mouse, new_mouse);
|
struct v2 offset = v2_sub(old_mouse, new_mouse);
|
||||||
L.world_view.center = v2_add(L.world_view.center, offset);
|
L.world_view.center = v2_add(L.world_view.center, offset);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
/* Keep cursor invisible at center of screen */
|
||||||
|
sys_window_cursor_hide(L.window);
|
||||||
|
sys_window_cursor_set_pos(L.window, L.screen_center);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Process movement input
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
/* Movement */
|
||||||
|
{
|
||||||
|
struct v2 player_move_dir = { 0 };
|
||||||
|
for (enum user_bind_kind bind = 0; bind < (i32)ARRAY_COUNT(L.bind_states); ++bind) {
|
||||||
|
struct bind_state state = L.bind_states[bind];
|
||||||
|
|
||||||
|
if (!state.is_held && state.num_presses <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bind) {
|
||||||
|
/* Movement */
|
||||||
|
case USER_BIND_KIND_MOVE_UP: {
|
||||||
|
player_move_dir.y -= 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case USER_BIND_KIND_MOVE_DOWN: {
|
||||||
|
player_move_dir.y += 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case USER_BIND_KIND_MOVE_LEFT: {
|
||||||
|
player_move_dir.x -= 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case USER_BIND_KIND_MOVE_RIGHT: {
|
||||||
|
player_move_dir.x += 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct game_cmd cmd = (struct game_cmd) {
|
||||||
|
.kind = GAME_CMD_KIND_PLAYER_MOVE,
|
||||||
|
.move_dir = v2_norm(player_move_dir)
|
||||||
|
};
|
||||||
|
if (!L.debug_camera) {
|
||||||
|
struct v2 focus_move_dir = v2_div(L.screen_mouse_delta, PIXELS_PER_UNIT * L.world_view.zoom);
|
||||||
|
focus_move_dir = v2_mul(focus_move_dir, MOUSE_SENSITIVITY);
|
||||||
|
cmd.focus_move_dir = focus_move_dir;
|
||||||
|
}
|
||||||
|
queue_game_cmd(&cmd_list, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -582,7 +604,6 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
/* Pull ticks */
|
/* Pull ticks */
|
||||||
|
|
||||||
/* FIXME: use real game DT */
|
|
||||||
f64 blend_time_offset = (1.0 / GAME_FPS) * USER_INTERP_OFFSET_TICK_RATIO;
|
f64 blend_time_offset = (1.0 / GAME_FPS) * USER_INTERP_OFFSET_TICK_RATIO;
|
||||||
f64 blend_time = L.time > blend_time_offset ? L.time - blend_time_offset : 0;
|
f64 blend_time = L.time > blend_time_offset ? L.time - blend_time_offset : 0;
|
||||||
|
|
||||||
@ -610,9 +631,9 @@ INTERNAL void user_update(void)
|
|||||||
L.world.time = math_lerp_f64(t0->time, t1->time, (f64)tick_blend);
|
L.world.time = math_lerp_f64(t0->time, t1->time, (f64)tick_blend);
|
||||||
|
|
||||||
/* Blend entities */
|
/* Blend entities */
|
||||||
struct entity_array t0_entities = world_get_entities(t0);
|
struct entity_array t0_entities = entity_store_as_array(&t0->entity_store);
|
||||||
struct entity_array t1_entities = world_get_entities(t1);
|
struct entity_array t1_entities = entity_store_as_array(&t1->entity_store);
|
||||||
struct entity_array world_entities = world_get_entities(&L.world);
|
struct entity_array world_entities = entity_store_as_array(&L.world.entity_store);
|
||||||
|
|
||||||
u64 num_entities = min_u64(t0_entities.count, t1_entities.count);
|
u64 num_entities = min_u64(t0_entities.count, t1_entities.count);
|
||||||
for (u64 i = 0; i < num_entities; ++i) {
|
for (u64 i = 0; i < num_entities; ++i) {
|
||||||
@ -626,6 +647,7 @@ INTERNAL void user_update(void)
|
|||||||
e->acceleration = v2_lerp(e0->acceleration, e1->acceleration, tick_blend);
|
e->acceleration = v2_lerp(e0->acceleration, e1->acceleration, tick_blend);
|
||||||
e->velocity = v2_lerp(e0->velocity, e1->velocity, tick_blend);
|
e->velocity = v2_lerp(e0->velocity, e1->velocity, tick_blend);
|
||||||
e->player_acceleration = math_lerp_f32(e0->player_acceleration, e1->player_acceleration, tick_blend);
|
e->player_acceleration = math_lerp_f32(e0->player_acceleration, e1->player_acceleration, tick_blend);
|
||||||
|
e->player_focus_dir = v2_lerp(e0->player_focus_dir, e1->player_focus_dir, tick_blend);
|
||||||
|
|
||||||
e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend);
|
e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend);
|
||||||
e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend);
|
e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend);
|
||||||
@ -638,13 +660,12 @@ INTERNAL void user_update(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct entity_array entities_array = world_get_entities(&L.world);
|
struct entity_array entities_array = entity_store_as_array(&L.world.entity_store);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Update view from game camera
|
* Update view from game camera
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* Find camera */
|
|
||||||
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||||
struct entity *ent = &entities_array.entities[entity_index];
|
struct entity *ent = &entities_array.entities[entity_index];
|
||||||
if (!ent->valid) continue;
|
if (!ent->valid) continue;
|
||||||
@ -657,6 +678,7 @@ INTERNAL void user_update(void)
|
|||||||
L.world_view.center = center;
|
L.world_view.center = center;
|
||||||
L.world_view.rot = rot;
|
L.world_view.rot = rot;
|
||||||
L.world_view.zoom = zoom;
|
L.world_view.zoom = zoom;
|
||||||
|
L.world_mouse = view_inverse_xform_v2(L.world_view, L.screen_mouse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -776,6 +798,22 @@ INTERNAL void user_update(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Draw crosshair */
|
||||||
|
if (!L.debug_camera && entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
||||||
|
struct v2 focus_pos = v2_add(ent->world_xform.og, ent->player_focus_dir);
|
||||||
|
struct v2 focus_pos_screen = view_xform_v2(L.world_view, focus_pos);
|
||||||
|
u32 tint = RGBA_F(1, 1, 1, 0.5);
|
||||||
|
|
||||||
|
struct texture *t = texture_load_async(STR("res/graphics/crosshair.ase"));
|
||||||
|
if (t) {
|
||||||
|
struct xform xf = XFORM_TRS(.t = focus_pos_screen, .s = t->size);
|
||||||
|
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, xf);
|
||||||
|
draw_texture_quad(L.screen_canvas, DRAW_TEXTURE_PARAMS(.texture = t, .tint = tint), quad);
|
||||||
|
}
|
||||||
|
|
||||||
|
L.last_focus_screen_pos = focus_pos_screen;
|
||||||
|
}
|
||||||
|
|
||||||
/* Debug draw info */
|
/* Debug draw info */
|
||||||
if (L.debug_draw && !is_camera) {
|
if (L.debug_draw && !is_camera) {
|
||||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||||
@ -790,7 +828,7 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
f32 offset = 1;
|
f32 offset = 1;
|
||||||
struct v2 pos = v2_add(xf.og, v2_mul(V2(0, -1), offset));
|
struct v2 pos = v2_add(xf.og, v2_mul(V2(0, -1), offset));
|
||||||
pos = view_xform_point(L.world_view, pos);
|
pos = view_xform_v2(L.world_view, pos);
|
||||||
pos = v2_round(pos);
|
pos = v2_round(pos);
|
||||||
|
|
||||||
struct string disp_name = ent->sprite_name;
|
struct string disp_name = ent->sprite_name;
|
||||||
@ -827,8 +865,21 @@ INTERNAL void user_update(void)
|
|||||||
f32 thickness = 5;
|
f32 thickness = 5;
|
||||||
f32 arrow_height = 15;
|
f32 arrow_height = 15;
|
||||||
|
|
||||||
struct v2 start = view_xform_point(L.world_view, ent->world_xform.og);
|
struct v2 start = view_xform_v2(L.world_view, ent->world_xform.og);
|
||||||
struct v2 end = view_xform_point(L.world_view, parent->world_xform.og);
|
struct v2 end = view_xform_v2(L.world_view, parent->world_xform.og);
|
||||||
|
draw_solid_arrow_line(L.screen_canvas, start, end, thickness, arrow_height, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw focus */
|
||||||
|
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
||||||
|
u32 color = RGBA_F(0.75, 0, 0.75, 0.5);
|
||||||
|
f32 thickness = 3;
|
||||||
|
f32 arrow_height = 10;
|
||||||
|
|
||||||
|
struct v2 focus_pos = v2_add(ent->world_xform.og, ent->player_focus_dir);
|
||||||
|
|
||||||
|
struct v2 start = view_xform_v2(L.world_view, ent->world_xform.og);
|
||||||
|
struct v2 end = view_xform_v2(L.world_view, focus_pos);
|
||||||
draw_solid_arrow_line(L.screen_canvas, start, end, thickness, arrow_height, color);
|
draw_solid_arrow_line(L.screen_canvas, start, end, thickness, arrow_height, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -842,15 +893,6 @@ INTERNAL void user_update(void)
|
|||||||
/* Update listener using world view */
|
/* Update listener using world view */
|
||||||
mixer_set_listener(L.world_view.center, V2(-math_sin(L.world_view.rot), -math_cos(L.world_view.rot)));
|
mixer_set_listener(L.world_view.center, V2(-math_sin(L.world_view.rot), -math_cos(L.world_view.rot)));
|
||||||
|
|
||||||
/* Send world mouse pos */
|
|
||||||
struct v2 world_mouse = view_mouse_pos(L.world_view);
|
|
||||||
if (!L.debug_camera) {
|
|
||||||
queue_game_cmd(&cmd_list, (struct game_cmd) {
|
|
||||||
.kind = GAME_CMD_KIND_PLAYER_FOCUS,
|
|
||||||
.pos = world_mouse
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Debug draw info */
|
/* Debug draw info */
|
||||||
if (L.debug_draw) {
|
if (L.debug_draw) {
|
||||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||||
@ -880,7 +922,7 @@ INTERNAL void user_update(void)
|
|||||||
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view.zoom: %F"), FMT_FLOAT((f64)L.world_view.zoom)));
|
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view.zoom: %F"), FMT_FLOAT((f64)L.world_view.zoom)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_mouse: (%F, %F)"), FMT_FLOAT((f64)world_mouse.x), FMT_FLOAT((f64)world_mouse.y)));
|
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_mouse: (%F, %F)"), FMT_FLOAT((f64)L.world_mouse.x), FMT_FLOAT((f64)L.world_mouse.y)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("debug_camera: %F"), FMT_STR(L.debug_camera ? STR("true") : STR("false"))));
|
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("debug_camera: %F"), FMT_STR(L.debug_camera ? STR("true") : STR("false"))));
|
||||||
|
|||||||
@ -18,6 +18,7 @@ enum user_bind_kind {
|
|||||||
USER_BIND_KIND_DEBUG_CAMERA,
|
USER_BIND_KIND_DEBUG_CAMERA,
|
||||||
USER_BIND_KIND_ZOOM_IN,
|
USER_BIND_KIND_ZOOM_IN,
|
||||||
USER_BIND_KIND_ZOOM_OUT,
|
USER_BIND_KIND_ZOOM_OUT,
|
||||||
|
USER_BIND_KIND_PAN,
|
||||||
|
|
||||||
USER_BIND_KIND_COUNT
|
USER_BIND_KIND_COUNT
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,11 +22,3 @@ void world_copy_replace(struct world *dest, struct world *src)
|
|||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct entity_array world_get_entities(struct world *world)
|
|
||||||
{
|
|
||||||
return (struct entity_array) {
|
|
||||||
.entities = (struct entity *)world->entity_store.arena.base,
|
|
||||||
.count = world->entity_store.count
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@ -13,13 +13,12 @@ struct world {
|
|||||||
f64 time;
|
f64 time;
|
||||||
|
|
||||||
struct v2 player_move_dir; /* Player movement direction */
|
struct v2 player_move_dir; /* Player movement direction */
|
||||||
struct v2 player_focus; /* Mouse cursor pos in world coordinates */
|
struct v2 player_focus_move_dir; /* Focus movement direction */
|
||||||
|
|
||||||
struct entity_store entity_store;
|
struct entity_store entity_store;
|
||||||
};
|
};
|
||||||
|
|
||||||
void world_alloc(struct world *world);
|
void world_alloc(struct world *world);
|
||||||
void world_copy_replace(struct world *dest, struct world *src);
|
void world_copy_replace(struct world *dest, struct world *src);
|
||||||
struct entity_array world_get_entities(struct world *world);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user