Pārlūkot izejas kodu

Add experimental MIDI controller input support

The game now uses MIDI support for alternative input methods.
feature/data-structs
TheoryOfNekomata pirms 2 gadiem
vecāks
revīzija
9012772322
15 mainītis faili ar 499 papildinājumiem un 137 dzēšanām
  1. +1
    -0
      .gitignore
  2. +9
    -1
      CMakeLists.txt
  3. +68
    -3
      src/packages/game/IZ_app.c
  4. +4
    -5
      src/packages/game/IZ_app.h
  5. +27
    -7
      src/packages/game/input/IZ_input.c
  6. +12
    -5
      src/packages/game/input/IZ_input.h
  7. +81
    -40
      src/packages/game/input/IZ_joystick.c
  8. +9
    -4
      src/packages/game/input/IZ_joystick.h
  9. +39
    -28
      src/packages/game/input/IZ_keyboard.c
  10. +3
    -3
      src/packages/game/input/IZ_keyboard.h
  11. +181
    -0
      src/packages/game/input/IZ_midi.c
  12. +58
    -0
      src/packages/game/input/IZ_midi.h
  13. +2
    -38
      src/packages/game/main.c
  14. +4
    -2
      src/packages/game/output/IZ_video.c
  15. +1
    -1
      src/packages/game/output/IZ_video.h

+ 1
- 0
.gitignore Parādīt failu

@@ -60,3 +60,4 @@ $RECYCLE.BIN/
.idea/
cmake-build-debug/
dependencies/
assets/

+ 9
- 1
CMakeLists.txt Parādīt failu

@@ -43,12 +43,13 @@ add_executable(
src/packages/game/input/IZ_keyboard.h
src/packages/game/IZ_config.c
src/packages/game/IZ_config.h
src/packages/game/geometry/IZ_point2d.c src/packages/game/geometry/IZ_point2d.h src/packages/game/geometry/IZ_vector2d.c src/packages/game/geometry/IZ_vector2d.h src/packages/game/geometry/IZ_rect.c src/packages/game/geometry/IZ_rect.h src/packages/game/core/IZ_object.c src/packages/game/core/IZ_object.h src/packages/game/core/IZ_creature.c src/packages/game/core/IZ_creature.h src/packages/game/core/IZ_entity.c src/packages/game/core/IZ_entity.h src/packages/game/memory/IZ_pool.c src/packages/game/memory/IZ_pool.h src/packages/game/input/IZ_input.c src/packages/game/input/IZ_input.h)
src/packages/game/geometry/IZ_point2d.c src/packages/game/geometry/IZ_point2d.h src/packages/game/geometry/IZ_vector2d.c src/packages/game/geometry/IZ_vector2d.h src/packages/game/geometry/IZ_rect.c src/packages/game/geometry/IZ_rect.h src/packages/game/core/IZ_object.c src/packages/game/core/IZ_object.h src/packages/game/core/IZ_creature.c src/packages/game/core/IZ_creature.h src/packages/game/core/IZ_entity.c src/packages/game/core/IZ_entity.h src/packages/game/memory/IZ_pool.c src/packages/game/memory/IZ_pool.h src/packages/game/input/IZ_input.c src/packages/game/input/IZ_input.h src/packages/game/input/IZ_midi.c src/packages/game/input/IZ_midi.h)

target_link_libraries(
game
SDL2main
SDL2
portmidi
)

add_executable(
@@ -109,3 +110,10 @@ if (WIN32)
"${PROJECT_SOURCE_DIR}/dependencies/SDL2/lib/${PROJECT_ARCH}/SDL2.dll" # <--this is in-file
$<TARGET_FILE_DIR:game>) # <--this is out-file path
endif ()

if (WIN32)
add_custom_command(TARGET game POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${PROJECT_SOURCE_DIR}/dependencies/portmidi/Release/portmidi.dll" # <--this is in-file
$<TARGET_FILE_DIR:game>) # <--this is out-file path
endif ()

+ 68
- 3
src/packages/game/IZ_app.c Parādīt failu

@@ -17,14 +17,79 @@ IZ_ProcedureResult IZ_InitializeApp(IZ_App* app) {
return 2;
}

for (uint8_t p = 0; p < PLAYERS; p += 1) {
IZ_InitializeInput(config_path, &app->input_state[p], p);
}
IZ_InitializeInput(config_path, &app->input_state);

app->quit = false;
return 0;
}

void IZ_TeardownApp(IZ_App* app) {
IZ_TeardownInput(&app->input_state);
IZ_TeardownVideo(&app->video_state);
SDL_Quit();
}

void IZ_HandleSDLEvents(IZ_App* app) {
while (SDL_PollEvent(&app->input_state.sdl_event) != 0) {
if (app->input_state.sdl_event.type == SDL_QUIT) {
app->quit = true;
break;
}

IZ_HandleSDLInputEvents(app->input_state.sdl_event, &app->input_state);
}
}

void IZ_HandlePortMIDIEvents(IZ_App* app) {
for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
int32_t midi_events_count = Pm_Read(
app->input_state.midi_input_state[player_index].stream,
app->input_state.midi_input_state[player_index].event_buffer,
1024
);

if (midi_events_count > 0) {
for (int32_t midi_event_index = 0; midi_event_index < midi_events_count; midi_event_index += 1) {
IZ_HandlePortMIDIInputEvents(
app->input_state.midi_input_state->event_buffer[midi_event_index],
&app->input_state
);
}
}
}
}

void IZ_HandleEvents(IZ_App* app) {
IZ_HandleSDLEvents(app);
IZ_HandlePortMIDIEvents(app);
}

IZ_ProcedureResult IZ_RunApp(IZ_App* app, uint8_t argc, char* argv[]) {
printf_s("Args (%u):\n", argc);
for (uint8_t i = 0; i < argc; i += 1) {
printf_s(" %s", argv[i]);
}

IZ_ProcedureResult init_result = IZ_InitializeApp(app);
if (init_result) {
return init_result;
}

while (true) {
uint64_t ticks = SDL_GetTicks64();

// TODO do audio processing
// TODO do networking?

// process events
IZ_HandleEvents(app);
if (app->quit) {
break;
}

IZ_UpdateVideo(&app->video_state, &app->input_state, ticks);
}

IZ_TeardownApp(app);
return 0;
}

+ 4
- 5
src/packages/game/IZ_app.h Parādīt failu

@@ -2,20 +2,19 @@
#define IZ_APP_H

#include <SDL.h>
#include <stdbool.h>
#include "input/IZ_input.h"
#include "output/IZ_video.h"
#include "memory/IZ_pool.h"
#include "input/IZ_action.h"

typedef struct {
IZ_InputState input_state[PLAYERS];
IZ_InputState input_state;
IZ_VideoState video_state;

IZ_Pool memory_pool;
bool quit;
} IZ_App;

IZ_ProcedureResult IZ_InitializeApp(IZ_App*);

void IZ_TeardownApp(IZ_App*);
IZ_ProcedureResult IZ_RunApp(IZ_App*, uint8_t, char**);

#endif

+ 27
- 7
src/packages/game/input/IZ_input.c Parādīt failu

@@ -1,18 +1,38 @@
#include "IZ_input.h"

void IZ_HandleInputEvents(SDL_Event e, IZ_InputState* state) {
void IZ_HandleSDLInputEvents(SDL_Event e, IZ_InputState* state) {
IZ_HandleJoystickEvents(e, &state->joystick_state, &state->action);
IZ_HandleKeyboardEvents(e, &state->keyboard_state, &state->action);
}

void IZ_InitializeInput(const char* config_path, IZ_InputState* state, uint8_t p) {
if (IZ_InitializeKeyboardConfig(config_path, &state->keyboard_state.config, p)) {
fprintf_s(stderr, "Error committing keyboard config for player %d.\n", p);
void IZ_HandlePortMIDIInputEvents(PmEvent e, IZ_InputState* state) {
IZ_HandleMIDIInputEvents(e, &state->midi_input_state, &state->action);
}

void IZ_InitializeInput(const char* config_path, IZ_InputState* state) {
*state = (IZ_InputState) {};

IZ_ProcedureResult joystick_result = IZ_InitializeJoystickState(config_path, &state->joystick_state);
if (joystick_result) {
fprintf_s(stderr, "Error committing joystick config. Code: %u.\n", joystick_result);
}

IZ_ProcedureResult keyboard_result = IZ_InitializeKeyboardState(config_path, &state->keyboard_state);
if (keyboard_result) {
fprintf_s(stderr, "Error committing keyboard config. Code: %u.\n", keyboard_result);
}

IZ_ProcedureResult midi_input_result = IZ_InitializeMIDIInput(config_path, &state->midi_input_state);
if (midi_input_result) {
fprintf_s(stderr, "Error committing MIDI input config. Code: %u.\n", midi_input_result);
}

if (IZ_InitializeJoystickConfig(config_path, &state->joystick_state.config, p)) {
fprintf_s(stderr, "Error committing joystick config for player %d.\n", p);
for (uint8_t p = 0; p < PLAYERS; p += 1) {
state->action[p] = 0;
}
}

state->action = 0;
void IZ_TeardownInput(IZ_InputState* state) {
IZ_TeardownJoystickState(&state->joystick_state);
IZ_TeardownMIDIInput(&state->midi_input_state);
}

+ 12
- 5
src/packages/game/input/IZ_input.h Parādīt failu

@@ -4,15 +4,22 @@
#include "IZ_action.h"
#include "IZ_keyboard.h"
#include "IZ_joystick.h"
#include "IZ_midi.h"

typedef struct {
IZ_Action action;
IZ_KeyboardState keyboard_state;
IZ_JoystickState joystick_state;
IZ_Action action[PLAYERS];
SDL_Event sdl_event;
IZ_KeyboardState keyboard_state[PLAYERS];
IZ_JoystickState joystick_state[PLAYERS];
IZ_MIDIInputState midi_input_state[PLAYERS];
} IZ_InputState;

void IZ_HandleInputEvents(SDL_Event, IZ_InputState*);
void IZ_HandleSDLInputEvents(SDL_Event, IZ_InputState*);

void IZ_InitializeInput(const char*, IZ_InputState*, uint8_t);
void IZ_HandlePortMIDIInputEvents(PmEvent, IZ_InputState*);

void IZ_InitializeInput(const char*, IZ_InputState*);

void IZ_TeardownInput(IZ_InputState*);

#endif

+ 81
- 40
src/packages/game/input/IZ_joystick.c Parādīt failu

@@ -2,18 +2,18 @@

void IZ_HandleJoystickDeviceEvents(SDL_Event e, IZ_JoystickState* state) {
if (e.type == SDL_JOYDEVICEADDED) {
if (SDL_NumJoysticks() <= PLAYERS && !state->joystick_instance) {
state->joystick_instance = SDL_JoystickOpen(e.jdevice.which);
if (SDL_NumJoysticks() <= PLAYERS && !state->device) {
state->device = SDL_JoystickOpen(e.jdevice.which);
}
return;
}

if (e.type == SDL_JOYDEVICEREMOVED) {
if (
state->joystick_instance
&& SDL_JoystickInstanceID(state->joystick_instance) == e.jdevice.which
state->device
&& SDL_JoystickInstanceID(state->device) == e.jdevice.which
) {
state->joystick_instance = NULL;
state->device = NULL;
}
}
}
@@ -82,56 +82,97 @@ void IZ_HandleJoystickButtonEvents(SDL_Event e, IZ_JoystickState* state, IZ_Acti
}
}

void IZ_HandleJoystickEvents(SDL_Event e, IZ_JoystickState* state, IZ_Action* action) {
IZ_HandleJoystickDeviceEvents(e, state);
IZ_HandleJoystickAxisEvents(e, state, action);
IZ_HandleJoystickHatEvents(e, action);
IZ_HandleJoystickButtonEvents(e, state, action);
void IZ_HandleJoystickEvents(SDL_Event e, IZ_JoystickState(* state)[PLAYERS], IZ_Action(* action)[PLAYERS]) {
for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
IZ_HandleJoystickDeviceEvents(e, state[player_index]);
IZ_HandleJoystickAxisEvents(e, state[player_index], action[player_index]);
IZ_HandleJoystickHatEvents(e, action[player_index]);
IZ_HandleJoystickButtonEvents(e, state[player_index], action[player_index]);
}
}

void IZ_LoadJoystickConfig(const char* config_path, IZ_JoystickConfig* config, uint8_t player_index) {
char joystick_control_mapping_section_name[26];
sprintf_s(joystick_control_mapping_section_name, 26, "Joystick.%d.ControlMapping", player_index);
void IZ_LoadJoystickConfig(const char* config_path, IZ_JoystickState(* state)[PLAYERS]) {
char control_mapping_section_name[26];
char main_section_name[11];
for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
sprintf_s(control_mapping_section_name, 26, "Joystick.%d.ControlMapping", player_index);

for (uint8_t i = 4; i < CONTROLS; i += 1) {
state[player_index]->config.control_mapping[i] = ini_getl(
control_mapping_section_name,
ACTION_NAMES[i],
IZ_DEFAULT_JOYSTICK_CONTROLS[player_index][i],
config_path
);
}

for (uint8_t i = 4; i < CONTROLS; i += 1) {
config->control_mapping[i] = ini_getl(joystick_control_mapping_section_name, ACTION_NAMES[i], IZ_DEFAULT_JOYSTICK_CONTROLS[player_index][i], config_path);
sprintf_s(main_section_name, 11, "Joystick.%d", player_index);
state[player_index]->config.axis_threshold = ini_getl(main_section_name, "AxisThreshold", IZ_DEFAULT_AXIS_THRESHOLD, config_path);
state[player_index]->config.device_id = ini_getl(main_section_name, "DeviceID", player_index, config_path);
}

char joystick_section_name[] = "Joystick.0";
joystick_section_name[9] = (char) (48 + player_index);
config->axis_threshold = ini_getl(joystick_section_name, "AxisThreshold", 8000, config_path);
}

IZ_ProcedureResult IZ_SaveJoystickConfig(const char* config_path, IZ_JoystickConfig* config, uint8_t player_index) {
char joystick_control_mapping_section_name[26];
sprintf_s(joystick_control_mapping_section_name, 26, "Joystick.%d.ControlMapping", player_index);
IZ_ProcedureResult IZ_SaveJoystickConfig(const char* config_path, IZ_JoystickState(* state)[PLAYERS]) {
uint8_t problem = 0;

char control_mapping_section_name[26];
char main_section_name[11];

for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
sprintf_s(control_mapping_section_name, 26, "Joystick.%d.ControlMapping", player_index);
for (uint8_t i = 4; i < CONTROLS; i += 1) {
if (!ini_putl(
control_mapping_section_name,
ACTION_NAMES[i],
state[player_index]->config.control_mapping[i],
config_path
)) {
return 1;
}
}

for (uint8_t i = 4; i < CONTROLS; i += 1) {
sprintf_s(main_section_name, 11, "Joystick.%d", player_index);
if (!ini_putl(
joystick_control_mapping_section_name,
ACTION_NAMES[i],
config->control_mapping[i],
config_path)
) {
return 1;
main_section_name,
"DeviceID",
state[player_index]->config.device_id,
config_path
)) {
problem |= (1 << player_index);
}

if (!ini_putl(
main_section_name,
"AxisThreshold",
state[player_index]->config.axis_threshold,
config_path
)) {
problem |= (1 << player_index);
}
}

char joystick_section_name[] = "Joystick.0";
joystick_section_name[9] = (char) (48 + player_index);
if (!ini_putl(
joystick_section_name,
"AxisThreshold",
config->axis_threshold,
config_path)
) {
return problem;
}

IZ_ProcedureResult IZ_InitializeJoystickState(const char* config_path, IZ_JoystickState(* state)[PLAYERS]) {
IZ_LoadJoystickConfig(config_path, state);
if (IZ_SaveJoystickConfig(config_path, state)) {
return 1;
}

uint8_t joysticks_count = SDL_NumJoysticks();
for (uint8_t player_index = 0; player_index < joysticks_count; player_index += 1) {
state[player_index]->device = SDL_JoystickOpen(state[player_index]->config.device_id);
}

return 0;
}

IZ_ProcedureResult IZ_InitializeJoystickConfig(const char* config_path, IZ_JoystickConfig* config, uint8_t p) {
IZ_LoadJoystickConfig(config_path, config, p);
return IZ_SaveJoystickConfig(config_path, config, p);
void IZ_TeardownJoystickState(IZ_JoystickState(* state)[PLAYERS]) {
for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
if (!state[player_index]->device) {
continue;
}
SDL_JoystickClose(state[player_index]->device);
}
}

+ 9
- 4
src/packages/game/input/IZ_joystick.h Parādīt failu

@@ -8,6 +8,8 @@

typedef uint8_t IZ_PadButton;

static const uint16_t IZ_DEFAULT_AXIS_THRESHOLD = 8000;

typedef enum {
IZ_JOY_AXIS_DIRECTION_HORIZONTAL1 = 0,
IZ_JOY_AXIS_DIRECTION_VERTICAL1 = 1,
@@ -17,11 +19,12 @@ typedef enum {

typedef struct {
uint16_t axis_threshold;
SDL_JoystickID device_id;
IZ_PadButton control_mapping[CONTROLS];
} IZ_JoystickConfig;

typedef struct {
SDL_Joystick* joystick_instance;
SDL_Joystick* device;
IZ_JoystickConfig config;
} IZ_JoystickState;

@@ -46,10 +49,12 @@ static IZ_PadButton IZ_DEFAULT_JOYSTICK_CONTROLS[PLAYERS][CONTROLS] = {
},
};

IZ_ProcedureResult IZ_SaveJoystickConfig(const char*, IZ_JoystickConfig*, uint8_t);
IZ_ProcedureResult IZ_SaveJoystickConfig(const char*, IZ_JoystickState(*)[PLAYERS]);

void IZ_HandleJoystickEvents(SDL_Event, IZ_JoystickState(*)[PLAYERS], IZ_Action(*)[PLAYERS]);

void IZ_HandleJoystickEvents(SDL_Event, IZ_JoystickState*, IZ_Action*);
IZ_ProcedureResult IZ_InitializeJoystickState(const char*, IZ_JoystickState(*)[PLAYERS]);

IZ_ProcedureResult IZ_InitializeJoystickConfig(const char*, IZ_JoystickConfig*, uint8_t);
void IZ_TeardownJoystickState(IZ_JoystickState(*)[PLAYERS]);

#endif

+ 39
- 28
src/packages/game/input/IZ_keyboard.c Parādīt failu

@@ -1,6 +1,6 @@
#include "IZ_keyboard.h"

void IZ_HandleKeyboardEvents(SDL_Event e, IZ_KeyboardState* state, IZ_Action* action) {
void IZ_HandleKewyboardKeyUpDownEvents(SDL_Event e, IZ_KeyboardState* state, IZ_Action* action) {
for (uint8_t i = 0; i < CONTROLS; i += 1) {
if (e.key.keysym.sym == state->config.control_mapping[i]) {
const uint16_t bitflag = (0x1 << i);
@@ -16,42 +16,53 @@ void IZ_HandleKeyboardEvents(SDL_Event e, IZ_KeyboardState* state, IZ_Action* ac
}
}

IZ_ProcedureResult IZ_SaveKeyboardConfig(const char* config_path, IZ_KeyboardConfig* config, uint8_t player_index) {
char keyboard_section_name[26];
sprintf_s(keyboard_section_name, 26, "Keyboard.%d.ControlMapping", player_index);
for (uint8_t i = 0; i < CONTROLS; i += 1) {
if (!ini_puts(
keyboard_section_name,
ACTION_NAMES[i],
SDL_GetKeyName(config->control_mapping[i]),
config_path)
) {
return 1;
void IZ_HandleKeyboardEvents(SDL_Event e, IZ_KeyboardState(* state)[PLAYERS], IZ_Action(* action)[PLAYERS]) {
for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
IZ_HandleKewyboardKeyUpDownEvents(e, state[player_index], action[player_index]);
}
}

IZ_ProcedureResult IZ_SaveKeyboardConfig(const char* config_path, IZ_KeyboardState(* state)[PLAYERS]) {
uint8_t problem = 0;
char control_mapping_section_name[26];
for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
sprintf_s(control_mapping_section_name, 26, "Keyboard.%d.ControlMapping", player_index);
for (uint8_t i = 0; i < CONTROLS; i += 1) {
if (!ini_puts(
control_mapping_section_name,
ACTION_NAMES[i],
SDL_GetKeyName(state[player_index]->config.control_mapping[i]),
config_path
)) {
problem |= (1 << player_index);
}
}
}

return 0;
return problem;
}

void IZ_LoadKeyboardConfig(const char* config_path, IZ_KeyboardConfig* config, uint8_t player_index) {
void IZ_LoadKeyboardConfig(const char* config_path, IZ_KeyboardState(* state)[PLAYERS]) {
char buffer[128];
char keyboard_section_name[26];
sprintf_s(keyboard_section_name, 26, "Keyboard.%d.ControlMapping", player_index);
for (uint8_t i = 0; i < CONTROLS; i += 1) {
ini_gets(
keyboard_section_name,
ACTION_NAMES[i],
SDL_GetKeyName(IZ_DEFAULT_KEYBOARD_CONTROLS[player_index][i]),
buffer,
128,
config_path
);
for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
sprintf_s(keyboard_section_name, 26, "Keyboard.%d.ControlMapping", player_index);
for (uint8_t i = 0; i < CONTROLS; i += 1) {
ini_gets(
keyboard_section_name,
ACTION_NAMES[i],
SDL_GetKeyName(IZ_DEFAULT_KEYBOARD_CONTROLS[player_index][i]),
buffer,
128,
config_path
);

config->control_mapping[i] = SDL_GetKeyFromName(buffer);
state[player_index]->config.control_mapping[i] = SDL_GetKeyFromName(buffer);
}
}
}

IZ_ProcedureResult IZ_InitializeKeyboardConfig(const char* config_path, IZ_KeyboardConfig* config, uint8_t p) {
IZ_LoadKeyboardConfig(config_path, config, p);
return IZ_SaveKeyboardConfig(config_path, config, p);
IZ_ProcedureResult IZ_InitializeKeyboardState(const char* config_path, IZ_KeyboardState(* state)[PLAYERS]) {
IZ_LoadKeyboardConfig(config_path, state);
return IZ_SaveKeyboardConfig(config_path, state);
}

+ 3
- 3
src/packages/game/input/IZ_keyboard.h Parādīt failu

@@ -35,10 +35,10 @@ static const SDL_KeyCode IZ_DEFAULT_KEYBOARD_CONTROLS[PLAYERS][CONTROLS] = {
},
};

IZ_ProcedureResult IZ_SaveKeyboardConfig(const char*, IZ_KeyboardConfig*, uint8_t);
IZ_ProcedureResult IZ_SaveKeyboardConfig(const char*, IZ_KeyboardState(*)[PLAYERS]);

void IZ_HandleKeyboardEvents(SDL_Event, IZ_KeyboardState*, IZ_Action*);
void IZ_HandleKeyboardEvents(SDL_Event, IZ_KeyboardState(*)[PLAYERS], IZ_Action(*)[PLAYERS]);

IZ_ProcedureResult IZ_InitializeKeyboardConfig(const char*, IZ_KeyboardConfig*, uint8_t);
IZ_ProcedureResult IZ_InitializeKeyboardState(const char*, IZ_KeyboardState(*)[PLAYERS]);

#endif

+ 181
- 0
src/packages/game/input/IZ_midi.c Parādīt failu

@@ -0,0 +1,181 @@
#include "IZ_midi.h"

char* IZ_GetMIDINoteName(uint8_t midi_note) {
static const char* pitch_names[] = {
"C",
"C#",
"D",
"D#",
"E",
"F",
"F#",
"G",
"G#",
"A",
"A#",
"B"
};

const uint8_t pitch_class = midi_note % 12;
const uint8_t octave = midi_note / 12;
static char note_name[4];
sprintf_s(note_name, 4, "%s%u", pitch_names[pitch_class], octave);
return note_name;
}

uint8_t IZ_GetMIDINoteFromName(char* name) {
char name_copy[4];
memcpy_s(name_copy, 4, name, 4);
_strlwr_s(name_copy, 4);

uint8_t octave;
const char base_pitch_name[] = "c d ef g a b";

if (strlen(name_copy) == 2) {
octave = name_copy[1] - '0';
for (uint8_t i = 0; i < 12; i += 1) {
if (base_pitch_name[i] == name_copy[0]) {
return (octave * 12) + i;
}
}
return 255u;
}

uint8_t pitch_class;
octave = name_copy[2] - '0';
if (strstr(name_copy, "c#") || strstr(name_copy, "db")) {
pitch_class = 1;
} else if (strstr(name_copy, "d#") || strstr(name_copy, "eb")) {
pitch_class = 3;
} else if (strstr(name_copy, "f#") || strstr(name_copy, "gb")) {
pitch_class = 6;
} else if (strstr(name_copy, "g#") || strstr(name_copy, "ab")) {
pitch_class = 8;
} else if (strstr(name_copy, "a#") || strstr(name_copy, "bb")) {
pitch_class = 10;
} else {
return 255u;
}

return (octave * 12) + pitch_class;
}

void IZ_HandleMIDINoteOnOffEvents(PmEvent e, IZ_MIDIInputState* state, IZ_Action* action) {
uint32_t message = e.message;
uint8_t status = message & 0xFFu;
uint8_t data1 = (message >> 8) & 0xFFu;
// uint8_t data2 = (message >> 16) & 0xFFu;

for (uint8_t i = 0; i < CONTROLS; i += 1) {
if (data1 == state->config.control_mapping[i]) {
const uint16_t bitflag = (0x1 << i);
if (status == IZ_MIDI_NOTE_ON) {
*action |= bitflag;
return;
}
if (status == IZ_MIDI_NOTE_OFF) {
*action &= ~bitflag;
return;
}
}
}
}

void IZ_HandleMIDIInputEvents(PmEvent e, IZ_MIDIInputState(* state)[PLAYERS], IZ_Action(* action)[PLAYERS]) {
for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
IZ_HandleMIDINoteOnOffEvents(e, state[player_index], action[player_index]);
}
}

IZ_ProcedureResult IZ_SaveMIDIInputConfig(const char* config_path, IZ_MIDIInputState(* state)[PLAYERS]) {
uint8_t problem = 0;

char control_mapping_section_name[27];
char main_section_name[12];

for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
sprintf_s(control_mapping_section_name, 27, "MIDIInput.%d.ControlMapping", player_index);
for (uint8_t i = 0; i < CONTROLS; i += 1) {
if (!ini_puts(
control_mapping_section_name,
ACTION_NAMES[i],
IZ_GetMIDINoteName(state[player_index]->config.control_mapping[i]),
config_path
)) {
problem |= (1 << player_index);
}
}

sprintf_s(main_section_name, 12, "MIDIInput.%d", player_index);
if (!ini_putl(
main_section_name,
"DeviceID",
state[player_index]->config.device_id,
config_path
)) {
problem |= (1 << player_index);
}
}

return problem;
}

void IZ_LoadMIDIInputConfig(const char* config_path, IZ_MIDIInputState(* state)[PLAYERS]) {
char buffer[128];
char control_mapping_section_name[27];
char main_section_name[12];

for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
sprintf_s(control_mapping_section_name, 27, "MIDIInput.%d.ControlMapping", player_index);
for (uint8_t i = 0; i < CONTROLS; i += 1) {
ini_gets(
control_mapping_section_name,
ACTION_NAMES[i],
IZ_GetMIDINoteName(IZ_DEFAULT_MIDI_INPUT_CONTROLS[player_index][i]),
buffer,
128,
config_path
);

state[player_index]->config.control_mapping[i] = IZ_GetMIDINoteFromName(buffer);
}

sprintf_s(main_section_name, 12, "MIDIInput.%d", player_index);
state[player_index]->config.device_id = ini_getl(main_section_name, "DeviceID", player_index, config_path);
}
}

IZ_ProcedureResult IZ_InitializeMIDIInput(const char* config_path, IZ_MIDIInputState(* state)[PLAYERS]) {
if (Pm_Initialize()) {
return 1;
}

IZ_LoadMIDIInputConfig(config_path, state);
if (IZ_SaveMIDIInputConfig(config_path, state)) {
return 2;
}

for (uint8_t player_index = 0; player_index < PLAYERS; player_index += 1) {
state[player_index]->device_info = Pm_GetDeviceInfo(state[player_index]->config.device_id);
state[player_index]->stream = NULL;
Pm_OpenInput(
&state[player_index]->stream,
state[player_index]->config.device_id,
NULL,
MIDI_EVENT_BUFFER_SIZE,
NULL,
NULL
);
}

return 0;
}

void IZ_TeardownMIDIInput(IZ_MIDIInputState(* state)[PLAYERS]) {
for (uint8_t i = 0; i < PLAYERS; i += 1) {
if (!state[i]->stream) {
continue;
}
Pm_Close(state[i]->stream);
}
}

+ 58
- 0
src/packages/game/input/IZ_midi.h Parādīt failu

@@ -0,0 +1,58 @@
#ifndef IZ_MIDI_H
#define IZ_MIDI_H

#include <string.h>
#include <portmidi.h>
#include <minIni.h>
#include "IZ_action.h"

#define MIDI_EVENT_BUFFER_SIZE 1024

typedef uint8_t IZ_MIDINote;

static const uint8_t IZ_MIDI_NOTE_ON = 0x90u;

static const uint8_t IZ_MIDI_NOTE_OFF = 0x80u;

typedef struct {
PmDeviceID device_id;
IZ_MIDINote control_mapping[CONTROLS];
} IZ_MIDIInputConfig;

typedef struct {
IZ_MIDIInputConfig config;
const PmDeviceInfo* device_info;
PmStream* stream;
PmEvent event_buffer[MIDI_EVENT_BUFFER_SIZE];
} IZ_MIDIInputState;

static const IZ_MIDINote IZ_DEFAULT_MIDI_INPUT_CONTROLS[PLAYERS][CONTROLS] = {
{
70,
72,
71,
69,
77,
76,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
}
};

IZ_ProcedureResult IZ_SaveMIDIInputConfig(const char*, IZ_MIDIInputState(*)[PLAYERS]);

void IZ_HandleMIDIInputEvents(PmEvent, IZ_MIDIInputState(*)[PLAYERS], IZ_Action(*)[PLAYERS]);

IZ_ProcedureResult IZ_InitializeMIDIInput(const char*, IZ_MIDIInputState(*)[PLAYERS]);

void IZ_TeardownMIDIInput(IZ_MIDIInputState(*)[PLAYERS]);

#endif

+ 2
- 38
src/packages/game/main.c Parādīt failu

@@ -1,43 +1,7 @@
#include <SDL.h>
#include <stdbool.h>

#include "IZ_app.h"

int main(int argc, char* args[]) {
int main(int argc, char* argv[]) {
IZ_App app;
IZ_ProcedureResult result = IZ_InitializeApp(&app);

if (result) {
return result;
}

bool quit = false;
SDL_Event e;
while (true) {
uint64_t ticks = SDL_GetTicks64();

// TODO do audio processing
// TODO do networking?

// process events
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = true;
break;
}

for (uint8_t p = 0; p < PLAYERS; p += 1) {
IZ_HandleInputEvents(e, &(app.input_state[p]));
}
}

if (quit) {
break;
}

IZ_UpdateVideo(&app.video_state, &app.input_state, ticks);
}

IZ_TeardownApp(&app);
return 0;
return IZ_RunApp(&app, argc, argv);
}

+ 4
- 2
src/packages/game/output/IZ_video.c Parādīt failu

@@ -21,6 +21,8 @@ void IZ_LoadVideoConfig(const char* config_path, IZ_VideoConfig* config) {
}

IZ_ProcedureResult IZ_InitializeVideo(const char* config_path, IZ_VideoState* state) {
*state = (IZ_VideoState) {};

IZ_LoadVideoConfig(config_path, &state->config);
if (IZ_SaveVideoConfig(config_path, &state->config)) {
fprintf_s(stderr, "Error committing video config.\n");
@@ -45,7 +47,7 @@ IZ_ProcedureResult IZ_InitializeVideo(const char* config_path, IZ_VideoState* st
return 0;
}

void IZ_UpdateVideo(IZ_VideoState* video_state, IZ_InputState(* input_states)[PLAYERS], uint64_t ticks) {
void IZ_UpdateVideo(IZ_VideoState* video_state, IZ_InputState* input_states, uint64_t ticks) {
if (ticks - video_state->last_update_at > 1000 / video_state->config.max_fps) {
// Update window
SDL_FillRect(video_state->surface, NULL, SDL_MapRGB(video_state->surface->format, 0x00, 0x00, 0x00));
@@ -71,7 +73,7 @@ void IZ_UpdateVideo(IZ_VideoState* video_state, IZ_InputState(* input_states)[PL
const uint8_t row = i / 4;
const IZ_Action bitflag = (0x1 << i);
const uint8_t size = 4;
if (input_states[p]->action & bitflag) {
if (input_states->action[p] & bitflag) {
SDL_FillRect(video_state->surface, &(SDL_Rect) {
column * size,
row * size,


+ 1
- 1
src/packages/game/output/IZ_video.h Parādīt failu

@@ -27,7 +27,7 @@ IZ_ProcedureResult IZ_InitializeVideo(const char*, IZ_VideoState*);

IZ_ProcedureResult IZ_SaveVideoConfig(const char*, IZ_VideoConfig*);

void IZ_UpdateVideo(IZ_VideoState*, IZ_InputState(*)[PLAYERS], uint64_t);
void IZ_UpdateVideo(IZ_VideoState*, IZ_InputState*, uint64_t);

void IZ_TeardownVideo(IZ_VideoState*);



Notiek ielāde…
Atcelt
Saglabāt