Began implementing event manager.

Updated SDL to latest version and added debug versions of sdl libraries in windows version.
Added commandline shortcuts to regenerate visual studio project and to launch visual studio with one command for windows.
dev
Shariq Shah 7 years ago
parent a79189b18e
commit 4a7010d1c8
  1. 1
      .gitignore
  2. 7
      build/genie.lua
  3. BIN
      lib/windows/sdl2/SDL2-staticd.lib
  4. BIN
      lib/windows/sdl2/SDL2.dll
  5. BIN
      lib/windows/sdl2/SDL2.lib
  6. BIN
      lib/windows/sdl2/SDL2d.dll
  7. BIN
      lib/windows/sdl2/SDL2d.lib
  8. BIN
      lib/windows/sdl2/SDL2main.lib
  9. BIN
      lib/windows/sdl2/SDL2maind.lib
  10. BIN
      lib/windows/sdl2/SDL2test.lib
  11. 58
      src/game/editor.c
  12. 242
      src/game/event.c
  13. 112
      src/game/event.h
  14. 8
      src/game/game.c
  15. 2
      src/game/game.h
  16. 25
      src/game/input.c
  17. 5
      todo.txt
  18. BIN
      tools/launch_cmd.lnk
  19. 3
      tools/launch_vs.bat
  20. 4
      tools/regen_project.bat
  21. 3
      tools/setup_env.bat

1
.gitignore vendored

@ -1,3 +1,4 @@
bin/*
build/*
.vs/*
.vscode

@ -75,7 +75,6 @@ solution "Symmetry"
configuration {"windows", "vs2017"}
includedirs {"../include/windows/sdl2/", "../include/common/soloud/", "../include/windows/"}
libdirs {"../lib/windows/sdl2/", "../lib/windows/soloud/", "../lib/windows/ode/"}
links {"SDL2"}
configuration "Debug"
links {"soloud_x64_d"}
@ -98,19 +97,19 @@ solution "Symmetry"
"rmdir release\\assets",
"mklink /D release\\assets ..\\..\\..\\assets"
}
links {"ode_double"}
links {"ode_double", "SDL2"}
configuration {"windows", "Debug", "vs2017"}
postbuildcommands
{
"copy ..\\..\\lib\\windows\\sdl2\\SDL2.dll debug\\ /Y",
"copy ..\\..\\lib\\windows\\sdl2\\SDL2d.dll debug\\ /Y",
"copy ..\\..\\lib\\windows\\soloud\\soloud_x64_d.dll debug\\ /Y",
"copy ..\\..\\lib\\windows\\ode\\ode_doubled.dll debug\\ /Y",
"copy ..\\..\\lib\\windows\\ode\\ode_doubled.pdb debug\\ /Y",
"rmdir debug\\assets",
"mklink /D debug\\assets ..\\..\\..\\assets"
}
links {"ode_doubled"}
links {"ode_doubled", "SDL2d"}
newaction {
trigger = "build_addon",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -591,33 +591,37 @@ void editor_camera_update(float dt)
//Picking
//If we're not looking around then allow picking
/* if(input_mousebutton_state_get(MSB_LEFT, KS_RELEASED)) */
/* { */
/* log_message("editor picking"); */
/* int mouse_x = 0, mouse_y = 0; */
/* platform->mouse_position_get(&mouse_x, &mouse_y); */
/* struct Ray ray = camera_screen_coord_to_ray(editor_camera, mouse_x, mouse_y); */
/* //log_message("Ray: %.3f, %.3f, %.3f", ray.direction.x, ray.direction.y, ray.direction.z); */
/* struct Scene* scene = game_state_get()->scene; */
/* struct Raycast_Result ray_result; */
/* scene_ray_intersect(scene, &ray, &ray_result); */
/* if(ray_result.num_entities_intersected > 0) */
/* { */
/* //For now, just select the first entity that is intersected */
/* struct Entity* intersected_entity = ray_result.entities_intersected[0]; */
/* if(editor_state.selected_entity && editor_state.selected_entity != intersected_entity) */
/* { */
/* editor_state.selected_entity->editor_selected = false; */
/* editor_state.selected_entity = NULL; */
/* } */
/* intersected_entity->editor_selected = true; */
/* editor_state.selected_entity = intersected_entity; */
/* } */
/* } */
if(input_mousebutton_state_get(MSB_LEFT, KS_RELEASED))
{
log_message("editor picking");
//int mouse_x = 0, mouse_y = 0;
//platform_mouse_position_get(&mouse_x, &mouse_y);
//struct Ray ray = camera_screen_coord_to_ray(editor_camera, mouse_x, mouse_y);
////log_message("Ray: %.3f, %.3f, %.3f", ray.direction.x, ray.direction.y, ray.direction.z);
//struct Scene* scene = game_state_get()->scene;
//struct Raycast_Result ray_result;
//scene_ray_intersect(scene, &ray, &ray_result);
//if(ray_result.num_entities_intersected > 0)
//{
// //For now, just select the first entity that is intersected
// struct Entity* intersected_entity = ray_result.entities_intersected[0];
// if(editor_state.selected_entity && editor_state.selected_entity != intersected_entity)
// {
// editor_state.selected_entity->editor_selected = false;
// editor_state.selected_entity = NULL;
// }
// intersected_entity->editor_selected = true;
// editor_state.selected_entity = intersected_entity;
//}
}
else if(input_mousebutton_state_get(MSB_LEFT, KS_PRESSED))
{
log_message("mouse pressed");
}
}
total_up_down_rot += turn_up_down;

@ -0,0 +1,242 @@
#include "event.h"
#include "../common/log.h"
#include <string.h>
#include <assert.h>
#include <SDL.h>
void event_manager_init(struct Event_Manager* event_manager)
{
assert(event_manager);
memset(event_manager->event_subsciptions, '\0', sizeof(struct Event_Subscription) * MAX_EVENT_SUBSCRIPTIONS);
for(int i = 0; i < MAX_EVENT_SUBSCRIPTIONS; i++)
{
struct Event_Subscription* subscription = &event_manager->event_subsciptions[i];
memset(subscription, '\0', sizeof(struct Event_Subscription));
subscription->event_type = EVT_NONE;
}
for(int i = 0; i < MAX_EVENTS; i++)
{
struct Event* event = &event_manager->event_pool[i];
memset(event, '\0', sizeof(struct Event));
event->type = EVT_NONE;
}
event_manager->sdl_event_id = SDL_RegisterEvents(1);
}
void event_manager_subscribe(struct Event_Manager* event_manager, int event_type, Event_Handler handler_func)
{
assert(event_manager && event_type < EVT_MAX && event_type > EVT_NONE);
//Check if this handler/subscriber already exists
bool subscribed = false;
for(int i = 0; i < MAX_EVENT_SUBSCRIPTIONS; i++)
{
struct Event_Subscription* subscription = &event_manager->event_subsciptions[i];
if(subscription->event_type == event_type && subscription->handler == handler_func)
{
log_message("Already subscibed to %s event", event_name_get(event_type));
subscribed = true;
break;
}
}
//Now that we've established that we are not subscribed already we find an empty slot and
//create a new subscription there
if(!subscribed)
{
for(int i = 0; i < MAX_EVENT_SUBSCRIPTIONS; i++)
{
struct Event_Subscription* subscription = &event_manager->event_subsciptions[i];
if(subscription->event_type == EVT_NONE)
{
subscription->event_type = event_type;
subscription->handler = handler_func;
subscribed = true;
break;
}
}
}
//if subscribed is still not true, it can only mean that all the existing slots are taken
//Show an error message in that case
if(!subscribed)
log_error("event_manager:subscribe", "Could not subscribe to %s event", event_name_get(event_type));
}
void event_manager_unsubscribe(struct Event_Manager* event_manager, int event_type, Event_Handler subscriber)
{
assert(event_manager && event_type < EVT_MAX);
for(int i = 0; i < MAX_EVENT_SUBSCRIPTIONS; i++)
{
struct Event_Subscription* subscription = &event_manager->event_subsciptions[i];
if(subscription->event_type == event_type && subscription->handler == subscriber)
{
subscription->handler = NULL;
subscription->event_type = EVT_NONE;
break;
}
}
}
void event_manager_send_event(struct Event_Manager* event_manager, struct Event* event)
{
assert(event_manager && event);
SDL_Event sdl_event;
SDL_memset(&sdl_event, 0, sizeof(sdl_event));
sdl_event.type = event_manager->sdl_event_id;
sdl_event.user.data1 = event;
int rc = SDL_PushEvent(&sdl_event);
if(rc != 1)
{
log_error("event_manager:send_event", "Could not push event, %s", event_name_get(event->type));
}
}
struct Event* event_manager_create_new_event(struct Event_Manager* event_manager)
{
struct Event* new_event = NULL;
for(int i = 0; i < MAX_EVENTS; i++)
{
if(event_manager->event_pool[i].type == EVT_NONE)
{
new_event = &event_manager->event_pool[i];
break;
}
}
if(!new_event)
log_warning("Out of event slots, event pool full!");
return new_event;
}
void event_manager_poll_events(struct Event_Manager* event_manager, bool* out_quit)
{
static SDL_Event event;
while(SDL_PollEvent(&event) != 0)
{
switch(event.type)
{
case SDL_QUIT:
*out_quit = true;
break;
case SDL_KEYDOWN: case SDL_KEYUP:
{
int scancode = event.key.keysym.scancode;
int key = event.key.keysym.sym;
int state = event.key.state;
bool repeat = event.key.repeat;
bool mod_ctrl = (event.key.keysym.mod & KMOD_CTRL) ? true : false;
bool mod_shift = (event.key.keysym.mod & KMOD_SHIFT) ? true : false;
bool mod_alt = (event.key.keysym.mod & KMOD_ALT) ? true : false;
struct Event* new_event = event_manager_create_new_event(event_manager);
new_event->type = event.type == SDL_KEYDOWN ? EVT_KEY_PRESSED : EVT_KEY_RELEASED;
new_event->key.key = event.key.keysym.sym;
new_event->key.scancode = event.key.keysym.scancode;
new_event->key.state = event.key.state;
new_event->key.repeat = event.key.repeat == 0 ? false : true;
new_event->key.mod_ctrl = (event.key.keysym.mod & KMOD_CTRL) ? true : false;
new_event->key.mod_shift = (event.key.keysym.mod & KMOD_SHIFT) ? true : false;
new_event->key.mod_alt = (event.key.keysym.mod & KMOD_ALT) ? true : false;
event_manager_send_event(event_manager, new_event);
//platform_state->on_keyboard_func(key, scancode, state, repeat, mod_ctrl, mod_shift, mod_alt);
//log_message("Key name : %s", SDL_GetKeyName(key));
break;
}
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP:
{
int button = event.button.button;
int state = event.button.state;
int num_clicks = event.button.clicks;
int x = event.button.x;
int y = event.button.y;
//platform_state->on_mousebutton_func(button, state, x, y, num_clicks);
break;
}
case SDL_MOUSEMOTION:
{
int xrel = event.motion.xrel;
int yrel = event.motion.yrel;
int x = event.motion.x;
int y = event.motion.y;
//platform_state->on_mousemotion_func(x, y, xrel, yrel);
break;
}
case SDL_MOUSEWHEEL:
{
int x = event.wheel.x;
int y = event.wheel.y;
//platform_state->on_mousewheel_func(x, y);
break;
}
case SDL_TEXTINPUT:
{
//platform_state->on_textinput_func(event.text.text);
break;
}
case SDL_WINDOWEVENT:
{
if(event.window.event == SDL_WINDOWEVENT_RESIZED)
{
//platform_state->on_windowresize_func(event.window.data1, event.window.data2);
}
}
break;
default:
{
if(event.type == event_manager->sdl_event_id)
{
struct Event* user_event = (struct Event*)event.user.data1;
//log_message("%s event", event_name_get(user_event->type));
for(int i = 0; i < MAX_EVENT_SUBSCRIPTIONS; i++)
{
struct Event_Subscription* subscription = &event_manager->event_subsciptions[i];
if(subscription->event_type == user_event->type)
{
if(subscription->handler) subscription->handler(user_event);
}
}
//return event to the pool now that it is consumed
memset(user_event, '\0', sizeof(*user_event));
user_event->type = EVT_NONE;
}
}
break;
}
}
}
void event_manager_cleanup(struct Event_Manager* event_manager)
{
}
const char* event_name_get(int event_type)
{
assert(event_type >= EVT_NONE && event_type <= EVT_MAX);
switch(event_type)
{
case EVT_NONE: return "None";
case EVT_KEY_PRESSED: return "Key Pressed";
case EVT_KEY_RELEASED: return "Key Released";
case EVT_MOUSEBUTTON_PRESSED: return "Mousebutton Pressed";
case EVT_MOUSEBUTTON_RELEASED: return "Mousebutton Released";
case EVT_MOUSEMOTION: return "Mouse Motion";
case EVT_WINDOW_RESIZED: return "Window Resized";
case EVT_MAX: return "Max Number of Events";
default: return "Invalid event_type";
}
}

@ -1,37 +1,107 @@
#ifndef EVENT_H
#define EVENT_H
#include "variant.h"
#include "../common/linmath.h"
#include "../common/num_types.h"
typedef void (*Event_Handler) (int object_index, const struct Variant* event_params, int num_params);
typedef void (*Event_Handler) (const struct Event* event);
#define MAX_EVENTS 128
#define MAX_EVENT_SUBSCRIPTIONS 256
enum Event_Types
{
EVT_NONE = 0,
EVT_KEY_PRESSED,
EVT_KEY_RELEASED,
EVT_MOUSEBUTTON_PRESSED,
EVT_MOUSEBUTTON_RELEASED,
EVT_MOUSEMOTION,
EVT_WINDOW_RESIZED,
EVT_MAX
};
struct Key_Event
{
int scancode;
int key;
int state;
bool repeat;
bool mod_ctrl;
bool mod_shift;
bool mod_alt;
};
struct Player_Damage_Event
{
int damage;
int enemy;
vec3 direction;
};
struct Event
{
int type;
union
{
struct Player_Damage_Event player_damage;
struct Key_Event key;
};
};
struct Event_Subscription
{
int object_index; // If a particular object has subscribed to this
// event then this holds the index of the object
// in it's particular subsystem list. For
// example, for a Transform, it will hold the
// index of the transform in the transform
// list. Otherwise, it holds -1.
int event_type;
Event_Handler handler;
};
enum System_Event
struct Event_Manager
{
SE_KEYBOARD = 0,
SE_MOUSEBUTTON,
SE_MOUSEMOTION,
SE_WINDOW_RESIZE,
SE_NUM_EVENTS
struct Event event_pool[MAX_EVENTS];
struct Event_Subscription event_subsciptions[MAX_EVENT_SUBSCRIPTIONS];
uint32 sdl_event_id;
};
#define BEGIN_EVENT_DEFINITION(event_name)
#define END_EVENT_DEFINITION };
////Event subsciption example
//void player_init()
//{
// struct Event_Manager* event_manager = game_state_get()->event_manager;
// event_manager_subscribe(event_manager, EVT_PLAYER_DAMAGE, &on_player_damage);
//}
//
////Event unsubscribe example
//void player_cleanup()
//{
// struct Event_Manager* event_manager = game_state_get()->event_manager;
// event_manager_unsubscribe(event_manager, EVT_PLAYER_DAMANGE, &on_player_damage);
//}
//
////Event recieve example usage
//void on_player_damage(struct Event* event_data)
//{
// struct Player_Damage_Event* player_damage_event = &event_data->player_damage;
// damage_player(player_damage_event->damage, player_damage_event->direction);
//}
//
////Event send example usage
//void enemy_tick()
//{
// struct Event_Manager* event_manager = game_state-get()->event_manager;
// struct Event* new_event = event_manager_create_new_event(event_manager);
// new_event->type = EVT_PLAYER_DAMAGE;
// new_event->player_damage.damage = 20;
// new_event->player_damage.enemy = enemy_id;
// event_manager_send_event(event_manager, new_event);
//}
//
int event_subscribe(int object_index, Event_Handler handler_func);
void event_unsubscribe(int subscription_index);
void event_handle_systemevent(int event_type, const struct Variant* event_params, int num_params);
void event_handle_userevent(int event_type, const struct Variant* event_params, int num_params);
void event_send(int event_type, const struct Variant* event_params, int num_params);
void event_manager_init(struct Event_Manager* event_manager);
void event_manager_subscribe(struct Event_Manager* event_manager, int event_type, Event_Handler subscriber);
void event_manager_unsubscribe(struct Event_Manager* event_manager, int event_type, Event_Handler subscriber);
struct Event* event_manager_create_new_event(struct Event_Manager* event_manager);
void event_manager_send_event(struct Event_Manager* event_manager, struct Event* event);
void event_manager_poll_events(struct Event_Manager* event_manager, bool* out_quit);
void event_manager_cleanup(struct Event_Manager* event_manager);
const char* event_name_get(int event_type);
#endif

@ -33,6 +33,7 @@
#include "../system/physics.h"
#include "../system/platform.h"
#include "im_render.h"
#include "event.h"
#define UNUSED(a) (void)a
#define MIN_NUM(a,b) ((a) < (b) ? (a) : (b))
@ -72,6 +73,7 @@ bool game_init(struct Window* window)
game_state->renderer = calloc(1, sizeof(*game_state->renderer));
game_state->scene = calloc(1, sizeof(*game_state->scene));
game_state->console = calloc(1, sizeof(*game_state->console));
game_state->event_manager = calloc(1, sizeof(*game_state->event_manager));
log_message_callback_set(game_on_log_message);
log_warning_callback_set(game_on_log_warning);
@ -88,6 +90,7 @@ bool game_init(struct Window* window)
}
event_manager_init(game_state->event_manager);
input_init();
shader_init();
texture_init();
@ -490,7 +493,8 @@ bool game_run(void)
if(delta_time > MAX_FRAME_TIME) delta_time = (1.f / 60.f); /* To deal with resuming from breakpoint we artificially set delta time */
gui_input_begin();
platform_poll_events(&should_window_close);
//platform_poll_events(&should_window_close);
event_manager_poll_events(game_state->event_manager, &should_window_close);
gui_input_end();
game_update(delta_time, &should_window_close);
@ -1882,10 +1886,12 @@ void game_cleanup(void)
framebuffer_cleanup();
texture_cleanup();
shader_cleanup();
event_manager_cleanup(game_state->event_manager);
free(game_state->console);
free(game_state->scene);
free(game_state->renderer);
free(game_state->event_manager);
}
free(game_state);
game_state = NULL;

@ -10,6 +10,7 @@ struct Entity;
struct Player;
struct Console;
struct Gui_State;
struct Event_Manager;
enum Game_Mode
{
@ -26,6 +27,7 @@ struct Game_State
struct Scene* scene;
struct Console* console;
struct Gui_State* gui;
struct Event_Manager* event_manager;
};

@ -11,8 +11,11 @@
#include "../common/parser.h"
#include "../system/platform.h"
#include "../system/file_io.h"
#include "event.h"
#include "game.h"
static void input_on_key(int key, int scancode, int state, int repeat, int mod_ctrl, int mod_shift, int mod_alt);
//static void input_on_key(int key, int scancode, int state, int repeat, int mod_ctrl, int mod_shift, int mod_alt);
static void input_on_key(const struct Event* event);
static void input_on_mousebutton(int button, int state, int x, int y, int8 num_clicks);
static void input_on_mousemotion(int x, int y, int xrel, int yrel);
static void input_on_mousewheel(int x, int y);
@ -21,7 +24,10 @@ static struct Hashmap* key_bindings = NULL;
void input_init(void)
{
platform_keyboard_callback_set(&input_on_key);
struct Event_Manager* event_manager = game_state_get()->event_manager;
event_manager_subscribe(event_manager, EVT_KEY_PRESSED, &input_on_key);
event_manager_subscribe(event_manager, EVT_KEY_RELEASED, &input_on_key);
//platform_keyboard_callback_set(&input_on_key);
platform_mousebutton_callback_set(&input_on_mousebutton);
platform_mousemotion_callback_set(&input_on_mousemotion);
platform_mousewheel_callback_set(&input_on_mousewheel);
@ -76,6 +82,7 @@ void input_init(void)
void input_cleanup(void)
{
event_manager_unsubscribe(game_state_get()->event_manager, EVT_KEY_PRESSED, &input_on_key);
char* key = NULL;
struct Variant* value = NULL;
HASHMAP_FOREACH(key_bindings, key, value)
@ -272,8 +279,16 @@ void input_mouse_pos_set(int xpos, int ypos)
platform_mouse_global_position_set(xpos, ypos);
}
void input_on_key(int key, int scancode, int state, int repeat, int mod_ctrl, int mod_shift, int mod_alt)
void input_on_key(const struct Event* event)
{
assert(event->type == EVT_KEY_PRESSED || event->type == EVT_KEY_RELEASED);
int key = event->key.key;
int state = event->key.state;
bool mod_ctrl = event->key.mod_ctrl;
bool mod_shift = event->key.mod_shift;;
bool mod_alt = event->key.mod_alt;;
int mods = KMD_NONE;
if(mod_ctrl) mods |= KMD_CTRL;
if(mod_shift) mods |= KMD_SHIFT;
@ -287,14 +302,14 @@ void input_on_key(int key, int scancode, int state, int repeat, int mod_ctrl, in
//Check with primary key
if(key_binding->key_primary == key && (key_binding->mods_primary & mods) == key_binding->mods_primary)
{
key_binding->state = state;
key_binding->state = event->type == EVT_KEY_PRESSED ? KS_PRESSED : KS_RELEASED;
break;
}
//If not, then check with secondary key
if(key_binding->key_secondary == key && (key_binding->mods_secondary & mods) == key_binding->mods_secondary)
{
key_binding->state = state;
key_binding->state = event->type == EVT_KEY_PRESSED ? KS_PRESSED : KS_RELEASED;
break;
}
}

@ -1,4 +1,5 @@
Todo:
- Ray picking for editor
- Add warning to genie build script when running on windows and WindowsSdkVersion cannot be found. This happens when the script is not run from vcvarsall command prompt
- Improve README and add a screenshot to make the repository ready for making it public
- Refactor all global application state into 'Application_Context' struct. A single global instance of which is available everywhere
@ -42,7 +43,6 @@ Todo:
- Ogg format loading and playback
- Sound streaming
- Implment missing sound source properties (inner/outer cone, getting sound source data)
- Ray picking for editor
- Shadow maps
- Print processor stats and machine capabilites RAM etc on every run to log.
- Do input maps really need to be queried by their string names?
@ -57,6 +57,9 @@ Todo:
- ???
- Profit!
Improvements:
- Better naming semantics for examples, init/deinit for initialization and cleanup and create/destroy when memory is allocated or deallocated
Bugs:
- Better handling of wav format checking at load time

Binary file not shown.

@ -0,0 +1,3 @@
@echo off
devenv W:\build\vs2017\Symmetry.sln

@ -0,0 +1,4 @@
@echo off
cd W:\build\
genie.exe vs2017

@ -1,8 +1,9 @@
@echo off
subst /D "W:"
subst W: %CD%\..
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
cls
set editor=""C:\Applications\Emacs\bin\runemacs.exe""
set path=W:\tools;%path% rem

Loading…
Cancel
Save