diff --git a/audio/Audio.cpp b/audio/Audio.cpp index 0c98b39..a3b1edb 100644 --- a/audio/Audio.cpp +++ b/audio/Audio.cpp @@ -19,6 +19,7 @@ #endif #include "Audio.h" +#include "AudioSetting.h" #include "Wav.h" void audio_from_file(RingMemory* ring, const char* path, Audio* audio) @@ -31,4 +32,88 @@ void audio_from_file(RingMemory* ring, const char* path, Audio* audio) } } +inline +void audio_fill_buffer(AudioSetting* setting, uint32 to_fill, Audio* sound, int16* buffer1, int32 buffer1_size, int16* buffer2 = NULL, int32 buffer2_size = 0) +{ + uint32 limit = to_fill / setting->sample_size; + buffer1_size /= setting->sample_size; + buffer2_size /= setting->sample_size; + uint32 sample_count = sound->size / sound->sample_size; + f32 volume_scale = (f32) setting->volume / 100.0f; + const int16* data = (int16*) sound->data; + uint32 sample_index = setting->sample_index; + + uint32 i; + for (i = 0; i < limit && i < buffer1_size; ++i) { + if (sample_index >= sample_count) { + sample_index = 0; + + // @question why are we doing this? + setting->sample_index = 0; + } + + buffer1[i * 2] = (int16) (data[sample_index * 2] * volume_scale); + buffer1[i * 2 + 1] = (int16) (data[sample_index * 2 + 1] * volume_scale); + + ++sample_index; + } + + for (; i < limit && buffer2_size; ++i) { + if (sample_index >= sample_count) { + sample_index = 0; + + // @question why are we doing this? + setting->sample_index = 0; + } + + buffer2[i * 2] = (int16) (data[sample_index * 2] * volume_scale); + buffer2[i * 2 + 1] = (int16) (data[sample_index * 2 + 1] * volume_scale); + + ++sample_index; + } + + ++setting->sample_output; + setting->sample_buffer_size = to_fill; +} + +// @bug This is slower +/* +inline +void fill_audio_buffer(AudioSetting* audio_handle, uint32 to_fill, Audio* sound, int32 steps = 8) +{ + uint32 limit = to_fill / audio_handle->sample_size; + uint32 sample_count = sound->size / sound->sample_size; + uint32 sample_index = audio_handle->sample_index; + + // Copy all data until end + int32 offset; + memcpy( + audio_handle->buffer, + sound->data + audio_handle->sample_index * audio_handle->sample_size, + (offset = OMS_MIN(sample_count - sample_index, limit)) * audio_handle->sample_size + ); + + // If we are wrapping (play sound on loop) + // @todo we still need a setting if we actually want to do this + if (offset != limit) { + audio_handle->sample_index = 0; + memcpy( + audio_handle->buffer + offset * audio_handle->sample_size, + sound->data, + (limit - offset) * audio_handle->sample_size + ); + } + + simd_mult( + (int16 *) audio_handle->buffer, + (f32) audio_handle->volume / 100.0f, + (int16 *) audio_handle->buffer, limit * 2, + steps + ); + + ++audio_handle->sample_output; + audio_handle->sample_buffer_size = to_fill; +} +*/ + #endif diff --git a/environment/Globe.h b/environment/Globe.h new file mode 100644 index 0000000..7ba2f50 --- /dev/null +++ b/environment/Globe.h @@ -0,0 +1,31 @@ +#ifndef TOS_ENVIRONMENT_GLOBE_H +#define TOS_ENVIRONMENT_GLOBE_H + +#include "../stdlib/Types.h" +#include + +// day_length in seconds +f32 time_of_day(f64 time, f32 day_length) { + f64 t = time; + t = t / day_length; + t = t - (int32) t; + + return (f32) t; +} + +// time can either be actual time in seconds OR relative time to progra start +f32 daylight_get(f64 time, f32 day_length) { + f32 timer = time_of_day(time, day_length); + + if (timer < 0.5) { + f32 t = (timer - 0.25) * 100; + + return 1 / (1 + powf(2, -t)); + } + + f32 t = (timer - 0.85) * 100; + + return 1 - 1 / (1 + powf(2, -t)); +} + +#endif \ No newline at end of file diff --git a/font/Font.h b/font/Font.h index 8bf8781..3a5b447 100644 --- a/font/Font.h +++ b/font/Font.h @@ -39,6 +39,8 @@ struct Font { char texture_name[32]; f32 size; // Default font size at which the font renders best f32 line_height; // How tall is a single line (mostly important for multiple lines) + + // WARNING: Glyphs MUST be sorted ascending based on codepoint Glyph* glyphs; }; diff --git a/gpuapi/RenderUtils.h b/gpuapi/RenderUtils.h index 55ebf87..6629bec 100644 --- a/gpuapi/RenderUtils.h +++ b/gpuapi/RenderUtils.h @@ -333,15 +333,83 @@ void vertex_input(Vertex3DTextureColorIndex* __restrict vertices, uint32* __rest ); } +f32 text_calculate_dimensions_height( + f32 height, + const Font* __restrict font, const char* __restrict text, f32 scale, int32 length +) { + f32 y = font->line_height * scale; + + // @todo remember to restrict to width/height if value > 0 -> force width to remain below certain value + + for (int i = 0; i < length; ++i) { + if (text[i] == '\n') { + y += font->line_height * scale; + } + } + + return y; +} + +f32 text_calculate_dimensions_width( + f32 width, + const Font* __restrict font, const char* __restrict text, f32 scale, int32 length +) { + f32 x = 0; + f32 offset_x = 0; + + uint32 first_glyph = font->glyphs[0].codepoint; + + // @todo remember to restrict to width/height if value > 0 -> force width to remain below certain value + + for (int i = 0; i < length; ++i) { + int32 character = utf8_get_char_at(text, i); + + if (character == '\n') { + x = OMS_MAX(x, offset_x); + offset_x = 0; + + continue; + } + + Glyph* glyph = NULL; + // We try to jump t othe correct glyph based on the glyph codepoint + // If that doesn't work we iterate the glyph list BUT only until the last possible match (glyphs must be sorted ascending) + if (font->glyph_count > character - first_glyph + && font->glyphs[character - first_glyph].codepoint == character + ) { + glyph = &font->glyphs[character - first_glyph]; + } else { + // @performance consider to do binary search + for (int j = 0; j <= character - first_glyph && j < font->glyph_count; ++j) { + if (font->glyphs[j].codepoint == character) { + glyph = &font->glyphs[j]; + + break; + } + } + } + + if (!glyph) { + continue; + } + + offset_x += (glyph->metrics.width + glyph->metrics.offset_x + glyph->metrics.advance_x) * scale; + } + + return OMS_MAX(x, offset_x); +} + void text_calculate_dimensions( f32* __restrict width, f32* __restrict height, - const Font* __restrict font, const char* text, f32 scale, int32 length + const Font* __restrict font, const char* __restrict text, f32 scale, int32 length ) { f32 x = 0; f32 y = font->line_height * scale; f32 offset_x = 0; + uint32 first_glyph = font->glyphs[0].codepoint; + // @todo remember to restrict to width/height if value > 0 -> force width to remain below certain value for (int i = 0; i < length; ++i) { @@ -357,11 +425,20 @@ void text_calculate_dimensions( } Glyph* glyph = NULL; - for (int j = 0; j < font->glyph_count; ++j) { - if (font->glyphs[j].codepoint == character) { - glyph = &font->glyphs[j]; + // We try to jump t othe correct glyph based on the glyph codepoint + // If that doesn't work we iterate the glyph list BUT only until the last possible match (glyphs must be sorted ascending) + if (font->glyph_count > character - first_glyph + && font->glyphs[character - first_glyph].codepoint == character + ) { + glyph = &font->glyphs[character - first_glyph]; + } else { + // @performance consider to do binary search + for (int j = 0; j <= character - first_glyph && j < font->glyph_count; ++j) { + if (font->glyphs[j].codepoint == character) { + glyph = &font->glyphs[j]; - break; + break; + } } } @@ -369,7 +446,7 @@ void text_calculate_dimensions( continue; } - offset_x += (glyph->metrics.width + glyph->metrics.offset_x) * scale; + offset_x += (glyph->metrics.width + glyph->metrics.offset_x + glyph->metrics.advance_x) * scale; } *width = OMS_MAX(x, offset_x); @@ -386,7 +463,13 @@ f32 vertex_text_create( // If we do a different alignment we need to pre-calculate the width and height if (align_h != 0 || align_v != 0) { - text_calculate_dimensions(&width, &height, font, text, scale, length); + if (align_h != 0 && align_v != 0) { + text_calculate_dimensions(&width, &height, font, text, scale, length); + } else if (align_h != 0) { + width = text_calculate_dimensions_width(width, font, text, scale, length); + } else { + height = text_calculate_dimensions_height(height, font, text, scale, length); + } if (align_h == UI_ALIGN_H_RIGHT) { x -= width; @@ -401,6 +484,8 @@ f32 vertex_text_create( } } + uint32 first_glyph = font->glyphs[0].codepoint; + f32 offset_x = x; for (int i = 0; i < length; ++i) { int32 character = utf8_get_char_at(text, i); @@ -412,11 +497,20 @@ f32 vertex_text_create( } Glyph* glyph = NULL; - for (int j = 0; j < font->glyph_count; ++j) { - if (font->glyphs[j].codepoint == character) { - glyph = &font->glyphs[j]; + // We try to jump t othe correct glyph based on the glyph codepoint + // If that doesn't work we iterate the glyph list BUT only until the last possible match (glyphs must be sorted ascending) + if (font->glyph_count > character - first_glyph + && font->glyphs[character - first_glyph].codepoint == character + ) { + glyph = &font->glyphs[character - first_glyph]; + } else { + // @performance consider to do binary search + for (int j = 0; j <= character - first_glyph && j < font->glyph_count; ++j) { + if (font->glyphs[j].codepoint == character) { + glyph = &font->glyphs[j]; - break; + break; + } } } @@ -506,7 +600,13 @@ f32 ui_text_create( f32 tmp_width = width->value_int; f32 tmp_height = height->value_int; - text_calculate_dimensions(&tmp_width, &tmp_height, &theme->font, text->value_str, scale, length); + if (align_h != NULL && align_v != NULL) { + text_calculate_dimensions(&tmp_width, &tmp_height, &theme->font, text->value_str, scale, length); + } else if (align_h != NULL) { + tmp_width = text_calculate_dimensions_width(tmp_width, &theme->font, text->value_str, scale, length); + } else { + tmp_height = text_calculate_dimensions_height(tmp_height, &theme->font, text->value_str, scale, length); + } if (align_h->value_int == UI_ALIGN_H_RIGHT) { x -= width->value_int; @@ -521,6 +621,8 @@ f32 ui_text_create( } } + uint32 first_glyph = theme->font.glyphs[0].codepoint; + int32 start = *index; f32 offset_x = x->value_int; f32 offset_y = y->value_int; @@ -535,11 +637,20 @@ f32 ui_text_create( } Glyph* glyph = NULL; - for (int j = 0; j < theme->font.glyph_count; ++j) { - if (theme->font.glyphs[j].codepoint == character) { - glyph = &theme->font.glyphs[j]; + // We try to jump t othe correct glyph based on the glyph codepoint + // If that doesn't work we iterate the glyph list BUT only until the last possible match (glyphs must be sorted ascending) + if (theme->font.glyph_count > character - first_glyph + && theme->font.glyphs[character - first_glyph].codepoint == character + ) { + glyph = &theme->font.glyphs[character - first_glyph]; + } else { + // @performance consider to do binary search + for (int j = 0; j <= character - first_glyph && j < theme->font.glyph_count; ++j) { + if (theme->font.glyphs[j].codepoint == character) { + glyph = &theme->font.glyphs[j]; - break; + break; + } } } diff --git a/input/ControllerType.h b/input/ControllerType.h new file mode 100644 index 0000000..636f341 --- /dev/null +++ b/input/ControllerType.h @@ -0,0 +1,24 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_INPUT_CONTROLLER_TYPE_H +#define TOS_PLATFORM_WIN32_INPUT_CONTROLLER_TYPE_H + +#include "../stdlib/Types.h" + +enum ControllerType { + CONTROLLER_TYPE_NONE, + CONTROLLER_TYPE_DUALSHOCK4, + CONTROLLER_TYPE_DUALSENSE, + CONTROLLER_TYPE_XBOX_360, + CONTROLLER_TYPE_XBOX_ONE, + CONTROLLER_TYPE_XBOX_S, + CONTROLLER_TYPE_OTHER, +}; + +#endif \ No newline at end of file diff --git a/input/Input.h b/input/Input.h index 020cdec..dd91f12 100644 --- a/input/Input.h +++ b/input/Input.h @@ -133,6 +133,7 @@ struct Input { LPDIRECTINPUTDEVICE8* direct_controller; // used by direct input controller #endif + byte controller_type; bool state_change_button; bool state_change_mouse; @@ -434,7 +435,7 @@ void input_set_state(InputState* state, InputKey* __restrict new_key) free_state = &state->state_keys[i]; } else if (state->state_keys[i].key_id == new_key->key_id) { state->state_keys[i].key_state = new_key->key_state; - state->state_keys[i].value = new_key->value; + state->state_keys[i].value += new_key->value; state->state_keys[i].time = new_key->time; action_required = false; } @@ -592,23 +593,24 @@ input_hotkey_state(Input* input) continue; } - bool is_pressed = hotkey_keys_are_active(&input->state, mapping, hotkeys_for_key[possible_hotkey_idx]); - // store active hotkey, if it is not already active - if (is_pressed) { - input->state.state_hotkeys[active_hotkeys] = hotkeys_for_key[possible_hotkey_idx]; - ++active_hotkeys; + bool is_pressed = hotkey_keys_are_active(&input->state, mapping, hotkeys_for_key[possible_hotkey_idx]); + if (!is_pressed) { + continue; + } - // Run callback if defined - if (input->input_mapping1.callbacks[hotkeys_for_key[possible_hotkey_idx]] != 0 - && old_hotkeys[0] != hotkeys_for_key[possible_hotkey_idx] - && old_hotkeys[1] != hotkeys_for_key[possible_hotkey_idx] - && old_hotkeys[2] != hotkeys_for_key[possible_hotkey_idx] - && old_hotkeys[3] != hotkeys_for_key[possible_hotkey_idx] - && old_hotkeys[4] != hotkeys_for_key[possible_hotkey_idx] - ) { - input->input_mapping1.callbacks[hotkeys_for_key[possible_hotkey_idx]](input->callback_data); - } + input->state.state_hotkeys[active_hotkeys] = hotkeys_for_key[possible_hotkey_idx]; + ++active_hotkeys; + + // Run callback if defined + if (input->input_mapping1.callbacks[hotkeys_for_key[possible_hotkey_idx]] != 0 + && old_hotkeys[0] != hotkeys_for_key[possible_hotkey_idx] + && old_hotkeys[1] != hotkeys_for_key[possible_hotkey_idx] + && old_hotkeys[2] != hotkeys_for_key[possible_hotkey_idx] + && old_hotkeys[3] != hotkeys_for_key[possible_hotkey_idx] + && old_hotkeys[4] != hotkeys_for_key[possible_hotkey_idx] + ) { + input->input_mapping1.callbacks[hotkeys_for_key[possible_hotkey_idx]](input->callback_data); } } } diff --git a/log/Debug.cpp b/log/Debug.cpp index 15506f8..8623fd8 100644 --- a/log/Debug.cpp +++ b/log/Debug.cpp @@ -32,6 +32,25 @@ void update_timing_stat(uint32 stat, const char* function) debug_container->perf_stats[stat].old_tick_count = new_tick_count; } +inline +void update_timing_stat_start(uint32 stat, const char* function) +{ + uint64 new_tick_count = __rdtsc(); + + debug_container->perf_stats[stat].old_tick_count = new_tick_count; +} + +inline +void update_timing_stat_end(uint32 stat, const char* function) +{ + uint64 new_tick_count = __rdtsc(); + + debug_container->perf_stats[stat].function = function; + debug_container->perf_stats[stat].delta_tick = new_tick_count - debug_container->perf_stats[stat].old_tick_count; + debug_container->perf_stats[stat].delta_time = (double) debug_container->perf_stats[stat].delta_tick / (double) debug_container->performance_count_frequency; + debug_container->perf_stats[stat].old_tick_count = new_tick_count; +} + inline void reset_counter(int32 id) { @@ -253,6 +272,8 @@ byte* log_get_memory(uint64 size, byte aligned = 1, bool zeroed = false) if (save || debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) { log_to_file(); } + + ASSERT_SIMPLE(false); } void log(const char* format, LogDataType data_type, void* data, bool should_log, bool save, const char* file, const char* function, int32 line) @@ -297,6 +318,8 @@ byte* log_get_memory(uint64 size, byte aligned = 1, bool zeroed = false) if (save || debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) { log_to_file(); } + + ASSERT_SIMPLE(false); } #endif diff --git a/log/TimingStat.h b/log/TimingStat.h index 15fcbfa..3026f3c 100644 --- a/log/TimingStat.h +++ b/log/TimingStat.h @@ -32,8 +32,16 @@ struct TimingStat { #if DEBUG || INTERNAL void update_timing_stat(uint32, const char*); #define UPDATE_TIMING_STAT(stat) update_timing_stat(stat, __func__) + + // These are only needed if we need to delay the overwrite by 1 frame (e.g. ui update) + void update_timing_stat_start(uint32, const char*); + void update_timing_stat_end(uint32, const char*); + #define UPDATE_TIMING_STAT_START(stat) update_timing_stat_start(stat, __func__) + #define UPDATE_TIMING_STAT_END(stat) update_timing_stat_end(stat, __func__) #else #define UPDATE_TIMING_STAT(stat) ((void) 0) + #define UPDATE_TIMING_STAT_START(stat) ((void) 0) + #define UPDATE_TIMING_STAT_END(stat) ((void) 0) #endif #endif \ No newline at end of file diff --git a/models/settings/Settings.h b/models/settings/Settings.h index c2145d1..2977f39 100644 --- a/models/settings/Settings.h +++ b/models/settings/Settings.h @@ -102,6 +102,7 @@ struct CSettings { char path[MAX_PATH]; bool is_changed = false; byte simd_version; + int32 simd_step_size; bool supports_abm; // Network data @@ -178,6 +179,7 @@ struct CSettings { byte gpu_anti_aliasing_detail = 0; byte gpu_sharpening = SETTING_TYPE_DISABLED; byte gpu_ambient_occlusion = SETTING_TYPE_DISABLED; + byte gpu_color_deficiency; bool gpu_gamma_correction = true; bool gpu_normal_mapping = true; @@ -241,38 +243,21 @@ struct CSettings { char game_theme[32]; - v4_f32* game_ui_dim[50]; + v4_f32 game_ui_dim[50]; // @todo replace settings below with bit flag // UI uint64 ui_visibility_flags = 0; + uint64 game_visibility_flags = 0; // HUD bool game_hud_animated; - bool game_ui_show_hotkeys; - bool game_show_health_bar_self = false; - bool game_show_health_bar_player = false; - bool game_show_health_bar_monster = false; - bool game_show_health_numbers = false; - bool game_show_resource_numbers = false; bool game_show_buffs = false; - bool game_show_xp_bar_numbers = true; - bool game_show_name_self = false; - bool game_show_name_player = false; - bool game_show_name_monster = false; - bool game_show_name_npc = false; - bool game_show_title_self = false; - bool game_show_title_other = false; byte game_minion_visibility_self = 128; byte game_minion_visibility_player = 128; - bool game_show_dmg_numbers = false; - bool game_show_cooldown_times = false; - bool game_show_dodge = true; - bool game_show_effect_gains = true; // e.g. XP - bool game_minimap_show_merchants = false; bool game_minimap_show_quest = false; bool game_minimap_show_dungeons = false; @@ -284,8 +269,6 @@ struct CSettings { bool game_map_show_dungeons = false; bool game_map_show_names = false; - bool game_show_subtitles = true; - // Mounts uint32 game_default_mount = 0; @@ -413,7 +396,7 @@ void load_settings(CSettings* __restrict client_settings, char* data) // Get name name = pos; - while (!is_eol(pos) && *pos != '\0' && !is_whitespace(*pos)) { + while (!is_eol(pos) && *pos != '\0' && !is_whitespace(*pos) && *pos != '[') { ++pos; } @@ -441,6 +424,8 @@ void load_settings(CSettings* __restrict client_settings, char* data) client_settings->gpu_aspect_ratio = (f32) atof(pos); } else if (strncmp(name, "_attack_effect_quality", sizeof("_attack_effect_quality") - 1) == 0) { } else if (strncmp(name, "_blur", sizeof("_blur") - 1) == 0) { + } else if (strncmp(name, "_color_deficiency", sizeof("_color_deficiency") - 1) == 0) { + client_settings->gpu_color_deficiency = (byte) atoi(pos); } else if (strncmp(name, "_brightness", sizeof("_brightness") - 1) == 0) { } else if (strncmp(name, "_camera_shake", sizeof("_camera_shake") - 1) == 0) { } else if (strncmp(name, "_caustics_quality", sizeof("_caustics_quality") - 1) == 0) { @@ -546,8 +531,20 @@ void load_settings(CSettings* __restrict client_settings, char* data) } else if (strncmp(name, "_show_title_other", sizeof("_show_title_other") - 1) == 0) { } else if (strncmp(name, "_show_title_self", sizeof("_show_title_self") - 1) == 0) { } else if (strncmp(name, "_show_xp_bar_numbers", sizeof("_show_xp_bar_numbers") - 1) == 0) { + } else if (strncmp(name, "_ui_visibility_flags", sizeof("_ui_visibility_flags") - 1) == 0) { + client_settings->ui_visibility_flags = strtoull(pos, &pos, 10); + } else if (strncmp(name, "_visibility_flags", sizeof("_visibility_flags") - 1) == 0) { + client_settings->game_visibility_flags = strtoull(pos, &pos, 10); } else if (strncmp(name, "_theme", sizeof("_theme") - 1) == 0) { + pos += strcpy_to_eol(pos, client_settings->game_theme); } else if (strncmp(name, "_ui_dim", sizeof("_ui_dim") - 1) == 0) { + int32 index = strtoul(++pos, &pos, 10); + pos += 2; + + client_settings->game_ui_dim[index].x = strtof(pos, &pos); ++pos; + client_settings->game_ui_dim[index].y = strtof(pos, &pos); ++pos; + client_settings->game_ui_dim[index].width = strtof(pos, &pos); ++pos; + client_settings->game_ui_dim[index].height = strtof(pos, &pos); } else if (strncmp(name, "_ui_show_hotkeys", sizeof("_ui_show_hotkeys") - 1) == 0) { } else if (strncmp(name, "_view", sizeof("_view") - 1) == 0) { } else if (strncmp(name, "_window1_dim", sizeof("_window1_dim") - 1) == 0) { diff --git a/models/settings/setting_types.h b/models/settings/setting_types.h index 2f34caa..08275c1 100644 --- a/models/settings/setting_types.h +++ b/models/settings/setting_types.h @@ -78,6 +78,34 @@ #define SETTING_UI_VISIBILITY_APM 2 #define SETTING_UI_VISIBILITY_DEBUG 4 #define SETTING_UI_VISIBILITY_WIREFRAME 8 +#define SETTING_UI_VISIBILITY_HOTKEYS 16 +#define SETTING_UI_VISIBILITY_XP_BAR 32 +#define SETTING_UI_VISIBILITY_COOLDOWN_TIMER 64 +#define SETTING_UI_VISIBILITY_MINIMAP 128 +#define SETTING_UI_VISIBILITY_CHAT 256 +#define SETTING_UI_VISIBILITY_CLOCK 512 +#define SETTING_UI_VISIBILITY_SUBTITLES 1024 +#define SETTING_UI_VISIBILITY_BAR 1024 +#define SETTING_UI_VISIBILITY_HEALTH 2048 +#define SETTING_UI_VISIBILITY_RESOURCE 4096 +#define SETTING_UI_VISIBILITY_INFO 8192 // = e.g. quest info + +#define SETTING_GAME_VISIBILITY_BAR_SELF 1 +#define SETTING_GAME_VISIBILITY_BAR_PLAYER 2 +#define SETTING_GAME_VISIBILITY_BAR_OTHER 4 +#define SETTING_GAME_VISIBILITY_BAR_NUMBERS 8 +#define SETTING_GAME_VISIBILITY_BUFFS_SELF 16 +#define SETTING_GAME_VISIBILITY_BUFFS_PLAYER 32 +#define SETTING_GAME_VISIBILITY_BUFFS_OTHER 64 +#define SETTING_GAME_VISIBILITY_NAME_SELF 128 +#define SETTING_GAME_VISIBILITY_NAME_PLAYER 256 +#define SETTING_GAME_VISIBILITY_NAME_OTHER 512 +#define SETTING_GAME_VISIBILITY_TITLE_SELF 1024 +#define SETTING_GAME_VISIBILITY_TITLE_PLAYER 2048 +#define SETTING_GAME_VISIBILITY_TITLE_OTHER 4096 +#define SETTING_GAME_VISIBILITY_DMG_NUMBERS 8192 +#define SETTING_GAME_VISIBILITY_XP_NUMBERS 16384 +#define SETTING_GAME_VISIBILITY_EFFECTS 32768 #define SETTING_INPUT_DEVICE_TYPE_MOUSE_KEYBOARD 1 #define SETTING_INPUT_DEVICE_TYPE_CONTROLLER 2 diff --git a/object/FaceType.h b/object/FaceType.h deleted file mode 100644 index 783ba1a..0000000 --- a/object/FaceType.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Jingga - * - * @copyright Jingga - * @license OMS License 2.0 - * @version 1.0.0 - * @link https://jingga.app - */ -#ifndef TOS_OBJECT_FACE_TYPE_H -#define TOS_OBJECT_FACE_TYPE_H - -enum FaceType { - FACE_TYPE_VERTICES = 1, - FACE_TYPE_TEXTURES = 2, - FACE_TYPE_NORMALS = 4, - FACE_TYPE_COLORS = 8, - FACE_TYPE_ALL = 15 -}; - -#endif \ No newline at end of file diff --git a/object/Mesh.h b/object/Mesh.h index 7fcb7b4..9d46d8f 100644 --- a/object/Mesh.h +++ b/object/Mesh.h @@ -10,7 +10,6 @@ #define TOS_OBJECT_MESH_H #include "Vertex.h" -#include "FaceType.h" #include "../stdlib/Types.h" #if _WIN32 @@ -43,29 +42,7 @@ struct Mesh { // Separate: [position] [normal] [tex_coord] [color] (separate array for elements) uint32 vertex_type; uint32 vertex_count; // can mean only position or combination of position, normal, tex, ... - uint32 normal_count; - uint32 tex_coord_count; - uint32 color_count; - float* vertices; - - // The following references only exist in some situations - // depends on the settings above - float* normals; - float* tex_coords; - float* colors; - - uint32 face_type; - uint32 face_count; - uint32 face_normal_count; - uint32 face_tex_coord_count; - uint32 face_color_count; - uint32* faces; - - // The following references only exist in some situations - // depends on the settings above - uint32* face_textures; - uint32* face_normals; - uint32* face_colors; + f32* vertices; // @todo this only works if you have sub meshes e.g. one for body, one for hat, one for weapon etc. uint32 vertex_ref; @@ -95,7 +72,8 @@ struct Mesh { // WARNING: mesh needs to have memory already reserved and asigned to data void mesh_from_file_txt( Mesh* mesh, - byte* data + byte* data, + RingMemory* ring ) { char* pos = (char *) data; @@ -109,15 +87,24 @@ void mesh_from_file_txt( mesh->vertices = (f32 *) mesh->data; - mesh->vertex_count = 0; - mesh->normal_count = 0; - mesh->tex_coord_count = 0; - mesh->color_count = 0; - mesh->face_count = 0; - mesh->face_normal_count = 0; - mesh->face_tex_coord_count = 0; - mesh->face_color_count = 0; + // @todo The temp memory reservation is bad, once the file format is really finalized we need to change this. + // We can't just assume these sizes + int32 vertex_count = 0; + f32* vertices = (f32 *) ring_get_memory(ring, 500000 * sizeof(f32)); + + int32 normal_count = 0; + f32* normals = (f32 *) ring_get_memory(ring, 500000 * sizeof(f32)); + + int32 tex_coord_count = 0; + f32* tex_coords = (f32 *) ring_get_memory(ring, 500000 * sizeof(f32)); + + int32 color_count = 0; + f32* colors = (f32 *) ring_get_memory(ring, 500000 * sizeof(f32)); + + int32 face_type = VERTEX_TYPE_POSITION; + int32 face_count = 0; + int32* faces = (int32 *) ring_get_memory(ring, 500000 * sizeof(int32)); uint32 temp_color_count = 0; @@ -133,6 +120,7 @@ void mesh_from_file_txt( // Parse type // WARNING: The code below could fail if [1] is outside of range // However that should never happen for well formed files + // @todo create an enum to make it easier to read int32 state = 0; if (*pos == 'v' && pos[1] == ' ') { state = 1; @@ -162,6 +150,8 @@ void mesh_from_file_txt( state = 13; } else if (*pos == 'u' && pos[3] == 'h') { state = 14; + } else if (*pos == 'c' && pos[3] == 'o') { + state = 15; } else { // not supported or comment while (*pos != '\n' && *pos != '\0') { @@ -194,60 +184,51 @@ void mesh_from_file_txt( case 0: break; case 1: { // 'v' - if (mesh->vertex_count == 0) { + if (vertex_count == 0) { mesh->vertex_type |= VERTEX_TYPE_POSITION; } - mesh->vertices[mesh->vertex_count * 3] = strtof(pos, &pos); ++pos; - mesh->vertices[mesh->vertex_count * 3 + 1] = strtof(pos, &pos); ++pos; - mesh->vertices[mesh->vertex_count * 3 + 2] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 3] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 3 + 1] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 3 + 2] = strtof(pos, &pos); ++pos; // has color information // @todo Move to own case statement // 'co' if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - if (mesh->vertex_count == 0) { + if (vertex_count == 0) { mesh->vertex_type |= VERTEX_TYPE_COLOR; } - mesh->vertices[mesh->vertex_count * 12 + 8] = strtof(pos, &pos); ++pos; - mesh->vertices[mesh->vertex_count * 12 + 9] = strtof(pos, &pos); ++pos; - mesh->vertices[mesh->vertex_count * 12 + 10] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 12 + 8] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 12 + 9] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 12 + 10] = strtof(pos, &pos); ++pos; // handle optional alpha [a] if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - mesh->vertices[mesh->vertex_count * 12 + 11] = strtof(pos, &pos); ++pos; + vertices[vertex_count * 12 + 11] = strtof(pos, &pos); ++pos; } else { - mesh->vertices[mesh->vertex_count * 12 + 11] = 1.0f; + vertices[vertex_count * 12 + 11] = 1.0f; } ++temp_color_count; } - ++mesh->vertex_count; + ++vertex_count; } break; case 2: { // 'vn' - // @bug This requires normals to be defined before textures - if (mesh->normal_count == 0) { - mesh->normals = mesh->vertices + mesh->vertex_count * 3; - } + normals[normal_count * 3] = strtof(pos, &pos); ++pos; + normals[normal_count * 3 + 1] = strtof(pos, &pos); ++pos; + normals[normal_count * 3 + 2] = strtof(pos, &pos); ++pos; - mesh->normals[mesh->normal_count * 3] = strtof(pos, &pos); ++pos; - mesh->normals[mesh->normal_count * 3 + 1] = strtof(pos, &pos); ++pos; - mesh->normals[mesh->normal_count * 3 + 2] = strtof(pos, &pos); ++pos; - - ++mesh->normal_count; + ++normal_count; } break; case 3: { // 'vt' - if (mesh->tex_coord_count == 0) { - mesh->tex_coords = mesh->vertices + mesh->vertex_count * 3 + mesh->normal_count * 3; - } + tex_coords[tex_coord_count * 2] = strtof(pos, &pos); ++pos; + tex_coords[tex_coord_count * 2 + 1] = strtof(pos, &pos); ++pos; - mesh->tex_coords[mesh->tex_coord_count * 2] = strtof(pos, &pos); ++pos; - mesh->tex_coords[mesh->tex_coord_count * 2 + 1] = strtof(pos, &pos); ++pos; - - ++mesh->tex_coord_count; + ++tex_coord_count; } break; case 4: { // 'vp' @@ -280,10 +261,6 @@ void mesh_from_file_txt( } break; case 7: { // 'f' - if (mesh->face_count == 0) { - mesh->faces = (uint32 *) (mesh->vertices + mesh->vertex_count * 3 + mesh->normal_count * 3 + mesh->tex_coord_count * 2 + mesh->color_count * 4); - } - int32 ftype = 0; char* tmp = pos; while (*tmp != ' ') { @@ -303,43 +280,43 @@ void mesh_from_file_txt( while (*pos != '\0' && *pos != '\n') { if (ftype == 0) { // v1 v2 v3 ... - if (mesh->face_count == 0) { - mesh->face_type = FACE_TYPE_VERTICES; + if (face_count == 0) { + face_type = VERTEX_TYPE_POSITION; } - mesh->faces[(mesh->face_count * max_blocks * 1) + block] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 1) + block] = strtol(pos, &pos, 10) - 1; ++pos; } else if (ftype == 1) { // v1/vt1 v2/vt2 v3/vt3 ... - if (mesh->face_count == 0) { - mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_TEXTURES; + if (face_count == 0) { + face_type = VERTEX_TYPE_POSITION | VERTEX_TYPE_TEXTURE_COORD; } - mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; - mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; } else if (ftype == 2) { // v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ... - if (mesh->face_count == 0) { - mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_TEXTURES | FACE_TYPE_NORMALS; + if (face_count == 0) { + face_type = VERTEX_TYPE_POSITION | VERTEX_TYPE_TEXTURE_COORD | VERTEX_TYPE_NORMAL; } - mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3] = strtol(pos, &pos, 10) - 1; ++pos; - mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3 + 1] = strtol(pos, &pos, 10) - 1; ++pos; - mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3 + 2] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 3) + block * 3] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 3) + block * 3 + 1] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 3) + block * 3 + 2] = strtol(pos, &pos, 10) - 1; ++pos; } else if (ftype == 3) { // v1//vn1 v2//vn2 v3//vn3 ... - if (mesh->face_count == 0) { - mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_NORMALS; + if (face_count == 0) { + face_type = VERTEX_TYPE_POSITION | VERTEX_TYPE_NORMAL; } - mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; ++pos; - mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; } ++block; } - ++mesh->face_count; + ++face_count; } break; case 8: { // 'g' @@ -405,15 +382,83 @@ void mesh_from_file_txt( } break; } } + + mesh->vertex_type = face_type; + + // Populate the vertex data based on the face data + if (face_count > 0) { + int32 vertex_size = 3; + int32 face_size = 1; + + // We need this since in the text file textures are defined before the normals (v/vt/vn) + int32 normal_offset = ((mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) ? 1 : 0); + + int32 texture_offset = ((mesh->vertex_type & VERTEX_TYPE_NORMAL) ? 1 : 0); + + if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { + vertex_size += 3; + ++face_size; + } + + if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { + vertex_size += 2; + ++face_size; + } + + if (mesh->vertex_type & VERTEX_TYPE_COLOR) { + vertex_size += 4; + ++face_size; + } + + mesh->vertex_count = face_count * 3; + + // Every face consists of 3 vertecies -> *3 + for (int32 i = 0; i < face_count * 3; ++i) { + const f32* vertex_pos = &vertices[faces[i * face_size] * 3]; + memcpy( + mesh->data + i * vertex_size * sizeof(f32), + vertex_pos, + 3 * sizeof(f32) + ); + + // Normals come before texture coordinates since we most likely need them more than texture (e.g. pre-copmuting of shadows on cpu etc.) + if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { + const f32* normal_pos = &normals[faces[i * face_size + 1 + normal_offset] * 3]; + + memcpy( + mesh->data + i * vertex_size * sizeof(f32) + + 3 * sizeof(f32), // Offset by position + normal_pos, + 3 * sizeof(f32) + ); + } + + if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { + const f32* texture_pos = &tex_coords[faces[i * face_size + 1] * 2]; + + memcpy( + mesh->data + i * vertex_size * sizeof(f32) + + 3 * sizeof(f32) // Offset by position + + texture_offset * 3 * sizeof(f32), // Offset by normal + texture_pos, + 2 * sizeof(f32) + ); + } + } + } else { + // No face data -> just output the vertices + mesh->vertex_count = vertex_count; + memcpy(mesh->vertices, vertices, 3 * sizeof(f32) * mesh->vertex_count); + } } -enum ObjectLoadingRestriction { - OBJECT_LOADING_RESTRICTION_POSITION = 1, - OBJECT_LOADING_RESTRICTION_NORMAL = 2, - OBJECT_LOADING_RESTRICTION_TEXTURE = 4, - OBJECT_LOADING_RESTRICTION_COLOR = 8, - OBJECT_LOADING_RESTRICTION_FACES = 16, - OBJECT_LOADING_RESTRICTION_EVERYTHING = 31 +enum MeshLoadingRestriction { + MESH_LOADING_RESTRICTION_POSITION = 1, + MESH_LOADING_RESTRICTION_NORMAL = 2, + MESH_LOADING_RESTRICTION_TEXTURE = 4, + MESH_LOADING_RESTRICTION_COLOR = 8, + MESH_LOADING_RESTRICTION_FACES = 16, + MESH_LOADING_RESTRICTION_EVERYTHING = 31 }; // @todo sometimes we don't care about some data, we should have an option which defines which data should be loaded @@ -424,8 +469,8 @@ int32 mesh_from_file( const char* path, Mesh* mesh, const char* group = NULL, - int32 load_format = OBJECT_LOADING_RESTRICTION_EVERYTHING, - int32 size = 8 + int32 load_format = MESH_LOADING_RESTRICTION_EVERYTHING, + int32 steps = 8 ) { FileBody file; @@ -444,22 +489,10 @@ int32 mesh_from_file( mesh->vertex_count = *((int32 *) pos); pos += sizeof(mesh->vertex_count); - mesh->normal_count = *((int32 *) pos); - pos += sizeof(mesh->normal_count); - - mesh->tex_coord_count = *((int32 *) pos); - pos += sizeof(mesh->tex_coord_count); - - mesh->color_count = *((int32 *) pos); - pos += sizeof(mesh->color_count); - #if !_WIN32 && !__LITTLE_ENDIAN mesh->version = endian_swap(mesh->version); mesh->vertex_type = endian_swap(mesh->vertex_type); mesh->verted_count = endian_swap(mesh->verted_count); - mesh->normal_count = endian_swap(mesh->normal_count); - mesh->tex_coord_count = endian_swap(mesh->tex_coord_count); - mesh->color_count = endian_swap(mesh->color_count); #endif int32 vertex_size = 0; @@ -488,108 +521,17 @@ int32 mesh_from_file( offset += sizeof(f32) * vertex_size * mesh->vertex_count; } - if (mesh->normal_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(f32) * 3 * mesh->normal_count); - mesh->normals = (f32 *) (mesh->data + offset); - - pos += sizeof(f32) * 3 * mesh->normal_count; - offset += sizeof(f32) * 3 * mesh->normal_count; - } - - if (mesh->tex_coord_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(f32) * 3 * mesh->tex_coord_count); - mesh->tex_coords = (f32 *) (mesh->data + offset); - - pos += sizeof(f32) * 2 * mesh->tex_coord_count; - offset += sizeof(f32) * 2 * mesh->tex_coord_count; - } - - if (mesh->color_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(f32) * 4 * mesh->color_count); - mesh->colors = (f32 *) (mesh->data + offset); - - pos += sizeof(f32) * 4 * mesh->color_count; - offset += sizeof(f32) * 4 * mesh->color_count; - } - - // Read face data - mesh->face_type = *((int32 *) pos); - pos += sizeof(mesh->face_type); - - mesh->face_count = *((int32 *) pos); - pos += sizeof(mesh->face_count); - - mesh->face_normal_count = *((int32 *) pos); - pos += sizeof(mesh->face_normal_count); - - mesh->face_tex_coord_count = *((int32 *) pos); - pos += sizeof(mesh->face_tex_coord_count); - - mesh->face_color_count = *((int32 *) pos); - pos += sizeof(mesh->face_color_count); - - #if !_WIN32 && !__LITTLE_ENDIAN - mesh->face_type = endian_swap(mesh->face_type); - mesh->face_count = endian_swap(mesh->face_count); - mesh->face_normal_count = endian_swap(mesh->face_normal_count); - mesh->face_tex_coord_count = endian_swap(mesh->face_tex_coord_count); - mesh->face_color_count = endian_swap(mesh->face_color_count); + /* + #if OPENGL + if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { + for (int i = 0; i < mesh->vertex_count; ++i) { + mesh->vertices[i * vertex_size + 3] *= -1; + mesh->vertices[i * vertex_size + 3 + 1] *= -1; + mesh->vertices[i * vertex_size + 3 + 2] *= -1; + } + } #endif - - int32 face_size = 0; - if (mesh->face_type & FACE_TYPE_VERTICES) { - face_size += 3; - } - - if ((mesh->face_type & FACE_TYPE_NORMALS)) { - face_size += 3; - } - - if ((mesh->face_type & FACE_TYPE_TEXTURES)) { - face_size += 3; - } - - if ((mesh->face_type & FACE_TYPE_COLORS)) { - face_size += 3; - } - - // faces can be either in the form - // f: v/vt/vn ... - // or: - // f: v ... - // f: vn ... - // f: vt ... - if (mesh->face_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(uint32) * face_size * mesh->face_count); - mesh->faces = (uint32 *) (mesh->data + offset); - - pos += sizeof(uint32) * face_size * mesh->face_count; - offset += sizeof(uint32) * face_size * mesh->face_count; - } - - if (mesh->face_normal_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_normal_count); - mesh->face_normals = (uint32 *) (mesh->data + offset); - - pos += sizeof(uint32) * 3 * mesh->face_normal_count; - offset += sizeof(uint32) * 3 * mesh->face_normal_count; - } - - if (mesh->face_tex_coord_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_tex_coord_count); - mesh->face_textures = (uint32 *) (mesh->data + offset); - - pos += sizeof(uint32) * 3 * mesh->face_tex_coord_count; - offset += sizeof(uint32) * 3 * mesh->face_tex_coord_count; - } - - if (mesh->face_color_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_color_count); - mesh->face_colors = (uint32 *) (mesh->data + offset); - - pos += sizeof(uint32) * 3 * mesh->face_color_count; - offset += sizeof(uint32) * 3 * mesh->face_color_count; - } + */ SWAP_ENDIAN_LITTLE_SIMD( (int32 *) mesh->data, @@ -605,9 +547,8 @@ void mesh_to_file( RingMemory* ring, const char* path, const Mesh* mesh, - int32 vertex_save_format = VERTEX_TYPE_POSITION, - int32 face_save_format = FACE_TYPE_VERTICES, - int32 size = 8 + int32 vertex_save_format = VERTEX_TYPE_ALL, + int32 steps = 8 ) { FileBody file; @@ -616,7 +557,6 @@ void mesh_to_file( // @todo check the actual size, we are currently more or less guessing file.size = sizeof(mesh) + sizeof(Vertex3D) * mesh->vertex_count - + sizeof(f32) * 12 * mesh->vertex_count + 4096; file.content = ring_get_memory(ring, file.size, 64); @@ -627,377 +567,57 @@ void mesh_to_file( pos += sizeof(mesh->version); // vertices + if (vertex_save_format == VERTEX_TYPE_ALL) { + vertex_save_format = mesh->vertex_type; + } + memcpy(pos, &vertex_save_format, sizeof(vertex_save_format)); pos += sizeof(vertex_save_format); memcpy(pos, &mesh->vertex_count, sizeof(mesh->vertex_count)); pos += sizeof(mesh->vertex_count); - // We are can save the mesh in a different format from the current format -> need to adjust some values - uint32 normal_count = mesh->normal_count == 0 && (mesh->vertex_type & VERTEX_TYPE_NORMAL) - ? mesh->vertex_count - : mesh->normal_count; - - memcpy(pos, &normal_count, sizeof(mesh->normal_count)); - pos += sizeof(mesh->normal_count); - - uint32 tex_coord_count = mesh->tex_coord_count == 0 && (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) - ? mesh->vertex_count - : mesh->tex_coord_count; - - memcpy(pos, &tex_coord_count, sizeof(mesh->tex_coord_count)); - pos += sizeof(mesh->tex_coord_count); - - uint32 color_count = mesh->color_count == 0 && (mesh->vertex_type & VERTEX_TYPE_COLOR) - ? mesh->vertex_count - : mesh->color_count; - - memcpy(pos, &color_count, sizeof(mesh->color_count)); - pos += sizeof(mesh->color_count); - // verticies - if (mesh->vertex_count > 0) { - int32 vertex_size = 0; - if (mesh->vertex_type & VERTEX_TYPE_POSITION) { - vertex_size += 3; - } - - if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { - vertex_size += 3; - } - - if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { - vertex_size += 2; - } - - if (mesh->vertex_type & VERTEX_TYPE_COLOR) { - vertex_size += 4; - } - - int32 out_vertex_size = 0; - if (vertex_save_format & VERTEX_TYPE_POSITION) { - out_vertex_size += 3; - } - - if (vertex_save_format & VERTEX_TYPE_NORMAL) { - out_vertex_size += 3; - } - - if (vertex_save_format & VERTEX_TYPE_TEXTURE_COORD) { - out_vertex_size += 2; - } - - if (vertex_save_format & VERTEX_TYPE_COLOR) { - out_vertex_size += 4; - } - - if ((mesh->vertex_type == VERTEX_TYPE_ALL && vertex_save_format == VERTEX_TYPE_ALL) - || (mesh->vertex_type == VERTEX_TYPE_POSITION && vertex_save_format == VERTEX_TYPE_POSITION) - ) { - // data is the same as in the array - memcpy(pos, mesh->vertices, vertex_size * sizeof(f32) * mesh->vertex_count); - pos += vertex_size * sizeof(f32) * mesh->vertex_count; - } else { - f32* temp = mesh->vertices; - f32* end = mesh->vertices + mesh->vertex_count * vertex_size; - - int32 offset; - - byte* vertice_start = pos; - - // @bug index gets increased every iteration BUT different groups and objects in the source may have different data - // This comes again down to how to handle hierarchal data with multiple groups and objects - int32 index = 0; - - // iterate over all vertices to create new output format - while (temp < end) { - // @question why do I even need offset? couldn't I just directly manipulate temp? - offset = 0; - - // First we save everything in one large array if that is the setting - if (vertex_save_format & VERTEX_TYPE_POSITION) { - if (mesh->vertex_type & VERTEX_TYPE_POSITION) { - memcpy(pos, temp, sizeof(f32) * 3); - pos += sizeof(f32) * 3; - - offset += 3; - } else { - memset(pos, 0, sizeof(f32) * 3); - pos += sizeof(f32) * 3; - } - } - - // We want separate arrays for some data - if ((mesh->vertex_type & VERTEX_TYPE_NORMAL) && !(vertex_save_format & VERTEX_TYPE_NORMAL)) { - // go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data - memcpy(vertice_start - + sizeof(f32) * out_vertex_size * mesh->vertex_count - + index * sizeof(f32) * 3, temp + offset, sizeof(f32) * 3); - - offset += 3; - } else if (vertex_save_format & VERTEX_TYPE_NORMAL) { - if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { - memcpy(pos, temp + offset, sizeof(f32) * 3); - pos += sizeof(f32) * 3; - - offset += 3; - } else { - memset(pos, 0, sizeof(f32) * 3); - pos += sizeof(f32) * 3; - } - } - - // We want separate arrays for some data - if ((mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) && !(vertex_save_format & VERTEX_TYPE_TEXTURE_COORD)) { - // go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data - memcpy(vertice_start - + sizeof(f32) * out_vertex_size * mesh->vertex_count - + sizeof(f32) * normal_count * 3 - + index * sizeof(f32) * 3, temp + offset, sizeof(f32) * 3); - - offset += 2; - } else if (vertex_save_format & VERTEX_TYPE_TEXTURE_COORD) { - if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { - memcpy(pos, temp + offset, sizeof(f32) * 2); - pos += sizeof(f32) * 2; - - offset += 2; - } else { - memset(pos, 0, sizeof(f32) * 2); - pos += sizeof(f32) * 2; - } - } - - // We want separate arrays for some data - if ((mesh->vertex_type & VERTEX_TYPE_COLOR) && !(vertex_save_format & VERTEX_TYPE_COLOR)) { - // go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data - memcpy(vertice_start - + sizeof(f32) * out_vertex_size * mesh->vertex_count - + sizeof(f32) * normal_count * 3 - + sizeof(f32) * tex_coord_count * 2 - + index * sizeof(f32) * 4, temp + offset, sizeof(f32) * 4); - - offset += 4; - } else if (vertex_save_format & VERTEX_TYPE_COLOR) { - if (mesh->vertex_type & VERTEX_TYPE_COLOR) { - memcpy(pos, temp + offset, sizeof(f32) * 4); - pos += sizeof(f32) * 4; - - offset += 4; - } else { - memset(pos, 0, sizeof(f32) * 4); - pos += sizeof(f32) * 4; - } - } - - temp += offset; - ++index; - } - } - - // check if we have clean array data already -> output this array data directly - if (mesh->normals && mesh->normal_count > 0) { - memcpy(pos, mesh->normals, mesh->normal_count * sizeof(f32) * 3); - pos += mesh->normal_count * sizeof(f32) * 3; - } - - if (mesh->tex_coords && mesh->tex_coord_count > 0) { - memcpy(pos, mesh->tex_coords, mesh->tex_coord_count * sizeof(f32) * 2); - pos += mesh->tex_coord_count * sizeof(f32) * 2; - } - - if (mesh->colors && mesh->color_count > 0) { - memcpy(pos, mesh->colors, mesh->color_count * sizeof(f32) * 4); - pos += mesh->color_count * sizeof(f32) * 4; - } + int32 vertex_size = 0; + if (mesh->vertex_type & VERTEX_TYPE_POSITION) { + vertex_size += 3; } - // faces/indices - memcpy(pos, &face_save_format, sizeof(face_save_format)); - pos += sizeof(face_save_format); + if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { + vertex_size += 3; + } - memcpy(pos, &mesh->face_count, sizeof(mesh->face_count)); - pos += sizeof(mesh->face_count); + if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { + vertex_size += 2; + } - // We are can save the mesh in a different format from the current format -> need to adjust some values - uint32 face_normal_count = mesh->face_normal_count == 0 && (mesh->face_type & FACE_TYPE_NORMALS) - ? mesh->face_count - : mesh->face_normal_count; + if (mesh->vertex_type & VERTEX_TYPE_COLOR) { + vertex_size += 4; + } - memcpy(pos, &face_normal_count, sizeof(mesh->face_normal_count)); - pos += sizeof(mesh->face_normal_count); + int32 out_vertex_size = 0; + if (vertex_save_format & VERTEX_TYPE_POSITION) { + out_vertex_size += 3; + } - uint32 face_tex_coord_count = mesh->face_tex_coord_count == 0 && (mesh->face_type & FACE_TYPE_TEXTURES) - ? mesh->face_count - : mesh->face_tex_coord_count; + if (vertex_save_format & VERTEX_TYPE_NORMAL) { + out_vertex_size += 3; + } - memcpy(pos, &face_tex_coord_count, sizeof(mesh->face_tex_coord_count)); - pos += sizeof(mesh->face_tex_coord_count); + if (vertex_save_format & VERTEX_TYPE_TEXTURE_COORD) { + out_vertex_size += 2; + } - uint32 face_color_count = mesh->face_color_count == 0 && (mesh->face_type & FACE_TYPE_COLORS) - ? mesh->face_count - : mesh->face_color_count; + if (vertex_save_format & VERTEX_TYPE_COLOR) { + out_vertex_size += 4; + } - memcpy(pos, &face_color_count, sizeof(mesh->face_color_count)); - pos += sizeof(mesh->face_color_count); - - if (mesh->face_count > 0) { - // WARNING: Carefull, we again assume only 3 elements per face - - int32 face_size = 0; - if (mesh->face_type & FACE_TYPE_VERTICES) { - face_size += 3; - } - - if (mesh->face_type & FACE_TYPE_NORMALS) { - face_size += 3; - } - - if (mesh->face_type & FACE_TYPE_TEXTURES) { - face_size += 3; - } - - if (mesh->face_type & FACE_TYPE_COLORS) { - face_size += 3; - } - - int32 out_face_size = 0; - if (face_save_format & FACE_TYPE_VERTICES) { - out_face_size += 3; - } - - if (face_save_format & FACE_TYPE_NORMALS) { - out_face_size += 3; - } - - if (face_save_format & FACE_TYPE_TEXTURES) { - out_face_size += 3; - } - - if (face_save_format & FACE_TYPE_COLORS) { - out_face_size += 3; - } - - if ((mesh->face_type == FACE_TYPE_ALL && face_save_format == FACE_TYPE_ALL) - || (mesh->face_type == FACE_TYPE_VERTICES && face_save_format == FACE_TYPE_VERTICES) - ) { - // data is the same as in the array - memcpy(pos, mesh->faces, face_size * sizeof(uint32) * mesh->face_count); - pos += face_size * sizeof(uint32) * mesh->face_count; - } else { - uint32* temp = mesh->faces; - uint32* end = mesh->faces + mesh->face_count * face_size; - - int32 offset; - - byte* face_start = pos; - - // @bug index gets increased every iteration BUT different groups and objects in the source may have different data - // This comes again down to how to handle hierarchal data with multiple groups and objects - int32 index = 0; - - // iterate over all faces to create new output format - // one iteration represents 1 block (a block could be v/vt/vn or, v, or v//vn, ...) - while (temp < end) { - // @question why do I even need offset? couldn't I just directly manipulate temp? - offset = 0; - - // First we save everything in one large array if that is the setting - if (face_save_format & FACE_TYPE_VERTICES) { - if (mesh->face_type & FACE_TYPE_VERTICES) { - memcpy(pos, temp, sizeof(uint32)); - pos += sizeof(uint32); - - offset += 1; - } else { - memset(pos, 0, sizeof(f32)); - pos += sizeof(f32); - } - } - - // We want separate arrays for some data - if (mesh->face_type & FACE_TYPE_NORMALS && !(face_save_format & FACE_TYPE_NORMALS)) { - // go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data - memcpy(face_start - + sizeof(uint32) * out_face_size * mesh->face_count - + index * sizeof(uint32), temp + offset, sizeof(uint32)); - - offset += 1; - } else if (face_save_format & FACE_TYPE_NORMALS) { - if (mesh->face_type & FACE_TYPE_NORMALS) { - memcpy(pos, temp + offset, sizeof(uint32)); - pos += sizeof(uint32); - - offset += 1; - } else { - memset(pos, 0, sizeof(uint32)); - pos += sizeof(uint32); - } - } - - // We want separate arrays for some data - if (mesh->face_type & FACE_TYPE_TEXTURES && !(face_save_format & FACE_TYPE_TEXTURES)) { - // go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data - memcpy(face_start - + sizeof(uint32) * out_face_size * mesh->face_count - + sizeof(uint32) * 3 * face_normal_count - + index * sizeof(uint32), temp + offset, sizeof(uint32)); - - offset += 1; - } else if (face_save_format & FACE_TYPE_TEXTURES) { - if (mesh->face_type & FACE_TYPE_TEXTURES) { - memcpy(pos, temp + offset, sizeof(uint32)); - pos += sizeof(uint32); - - offset += 1; - } else { - memset(pos, 0, sizeof(uint32)); - pos += sizeof(uint32); - } - } - - // We want separate arrays for some data - if (mesh->face_type & VERTEX_TYPE_COLOR && !(face_save_format & VERTEX_TYPE_COLOR)) { - // go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data - memcpy(face_start - + sizeof(uint32) * out_face_size * mesh->face_count - + sizeof(uint32) * 3 * face_normal_count - + sizeof(uint32) * 3 * face_tex_coord_count - + index * sizeof(uint32), temp + offset, sizeof(uint32)); - - offset += 1; - } else if (face_save_format & VERTEX_TYPE_COLOR) { - if (mesh->face_type & VERTEX_TYPE_COLOR) { - memcpy(pos, temp + offset, sizeof(uint32)); - pos += sizeof(uint32); - - offset += 1; - } else { - memset(pos, 0, sizeof(uint32)); - pos += sizeof(uint32); - } - } - - temp += offset; - ++index; - } - } - - // check if we have clean array data already -> output this array data directly - if (mesh->face_normals && mesh->face_normal_count > 0) { - memcpy(pos, mesh->face_normals, mesh->face_normal_count * sizeof(uint32) * 3); - pos += mesh->face_normal_count * sizeof(uint32) * 3; - } - - if (mesh->face_textures && mesh->face_tex_coord_count > 0) { - memcpy(pos, mesh->face_textures, mesh->face_tex_coord_count * sizeof(uint32) * 3); - pos += mesh->face_tex_coord_count * sizeof(uint32) * 3; - } - - if (mesh->face_colors && mesh->face_color_count > 0) { - memcpy(pos, mesh->face_colors, mesh->face_color_count * sizeof(uint32) * 3); - pos += mesh->face_color_count * sizeof(uint32) * 3; - } + if ((mesh->vertex_type == VERTEX_TYPE_ALL && vertex_save_format == VERTEX_TYPE_ALL) + || (mesh->vertex_type == vertex_save_format) + ) { + // data is the same as in the array + memcpy(pos, mesh->vertices, vertex_size * sizeof(f32) * mesh->vertex_count); + pos += vertex_size * sizeof(f32) * mesh->vertex_count; } file.size = pos - file.content; @@ -1009,14 +629,6 @@ void mesh_to_file( steps ); - /* - FileBody file2; - file2.content = ring_get_memory(ring, file.size, 64); - file2.size = encode_lzp(file.content, file.size, file2.content); - - file_write(path, &file2); - */ - file_write(path, &file); } diff --git a/object/Texture.h b/object/Texture.h index 0201e2f..257a88d 100644 --- a/object/Texture.h +++ b/object/Texture.h @@ -43,11 +43,8 @@ struct Texture { // If yes remember to update prepare_texture() byte texture_data_type; - byte texture_wrap_type_s; - byte texture_wrap_type_t; - byte texture_wrap_type_r; - byte texture_minification; + byte data[16]; Image image; }; diff --git a/object/Vertex.h b/object/Vertex.h index 0f8ff1f..4b4653a 100644 --- a/object/Vertex.h +++ b/object/Vertex.h @@ -90,7 +90,7 @@ enum VertexType { VERTEX_TYPE_NORMAL = 2, VERTEX_TYPE_TEXTURE_COORD = 4, VERTEX_TYPE_COLOR = 8, - VERTEX_TYPE_ALL = 15 + VERTEX_TYPE_ALL = 15, }; #endif \ No newline at end of file diff --git a/platform/win32/UtilsWin32.h b/platform/win32/UtilsWin32.h index 0dc304c..44bf345 100644 --- a/platform/win32/UtilsWin32.h +++ b/platform/win32/UtilsWin32.h @@ -24,6 +24,23 @@ #define strtok_r strtok_s +inline +time_t system_time() +{ + SYSTEMTIME systemTime; + FILETIME fileTime; + ULARGE_INTEGER largeInt; + + GetLocalTime(&systemTime); + SystemTimeToFileTime(&systemTime, &fileTime); + + // Convert FILETIME to a 64-bit integer + largeInt.LowPart = fileTime.dwLowDateTime; + largeInt.HighPart = fileTime.dwHighDateTime; + + return ((time_t) (largeInt.QuadPart / 10000000ULL)) - ((time_t) 11644473600ULL); +} + // @todo Consider to implement directly mapped files (CreateFileMapping) for certain files (e.g. map data or texture data, ...) inline void relative_to_absolute(const char* rel, char* path) diff --git a/platform/win32/audio/DirectSound.h b/platform/win32/audio/DirectSound.h index 1140a0f..73fba9c 100644 --- a/platform/win32/audio/DirectSound.h +++ b/platform/win32/audio/DirectSound.h @@ -16,6 +16,7 @@ #include "../../../audio/AudioSetting.h" #include "../../../utils/MathUtils.h" #include "../../../log/Log.h" +#include "../../../audio/Audio.cpp" struct DirectSoundSetting { LPDIRECTSOUND8 audio_handle; @@ -191,6 +192,9 @@ void audio_play_buffer(AudioSetting* setting, DirectSoundSetting* api_setting) 0 ); + // @performance why are we copying again, we already created our buffer, now we have to copy it again?! + // Ideally we should have already copied it into the correct final one, no? + // We should probably provide a audio_buffer_fill function, that does this -> we could remove one whole memcopy memcpy( (void *) region1, (void *) setting->buffer, @@ -211,4 +215,43 @@ void audio_play_buffer(AudioSetting* setting, DirectSoundSetting* api_setting) setting->sample_buffer_size = 0; } +// Basically the same as audio_play_buffer but by using this we can avoid one copy +// The only reason we have audio_play_buffer is that there might be situations where this is not possible +inline +void audio_fill_play_buffer(AudioSetting* setting, uint32 to_fill, Audio* sound, DirectSoundSetting* api_setting) +{ + setting->sample_buffer_size = to_fill; + + if (setting->sample_buffer_size == 0) { + return; + } + + if (!setting->is_playing) { + audio_play(setting, api_setting); + } + + void *region1; + DWORD region1_size; + + void *region2; + DWORD region2_size; + + DWORD bytes_to_lock = (setting->sample_index * setting->sample_size) % setting->buffer_size; + + api_setting->secondary_buffer->Lock( + bytes_to_lock, setting->sample_buffer_size, + ®ion1, ®ion1_size, + ®ion2, ®ion2_size, + 0 + ); + + audio_fill_buffer(setting, to_fill, sound, (int16 *) region1, (int32) region1_size, (int16 *) region2, (int32) region2_size); + + api_setting->secondary_buffer->Unlock(region1, region1_size, region2, region2_size); + + setting->sample_index += setting->sample_buffer_size / setting->sample_size; + setting->sample_buffer_size = 0; +} + + #endif \ No newline at end of file diff --git a/platform/win32/audio/XAudio2.h b/platform/win32/audio/XAudio2.h index 76189a9..0efb0c4 100644 --- a/platform/win32/audio/XAudio2.h +++ b/platform/win32/audio/XAudio2.h @@ -17,6 +17,7 @@ #include "../../../audio/AudioSetting.h" #include "../../../utils/MathUtils.h" #include "../../../log/Log.h" +#include "../../../audio/Audio.cpp" struct XAudio2Setting { IXAudio2* audio_handle; @@ -196,6 +197,9 @@ void audio_play_buffer(AudioSetting* setting, XAudio2Setting* api_setting) { uint32 idx = setting->sample_output % 2; + // @performance why are we copying again, we already created our buffer, now we have to copy it again?! + // Ideally we should have already copied it into the correct final one, no? + // We should probably provide a audio_buffer_fill function, that does this -> we could remove one whole memcopy memcpy( (void *) api_setting->internal_buffer[idx].pAudioData, setting->buffer, @@ -212,4 +216,33 @@ void audio_play_buffer(AudioSetting* setting, XAudio2Setting* api_setting) { setting->sample_buffer_size = 0; } +// Basically the same as audio_play_buffer but by using this we can avoid one copy +// The only reason we have audio_play_buffer is that there might be situations where this is not possible +inline +void audio_fill_play_buffer(AudioSetting* setting, uint32 to_fill, Audio* sound, XAudio2Setting* api_setting) +{ + setting->sample_buffer_size = to_fill; + + if (!api_setting->source_voice || setting->sample_buffer_size == 0) { + return; + } + + if (!setting->is_playing) { + audio_play(setting, api_setting); + } + + uint32 idx = setting->sample_output % 2; + + audio_fill_buffer(setting, to_fill, sound, (int16 *) api_setting->internal_buffer[idx].pAudioData, to_fill); + + if (!SUCCEEDED(api_setting->source_voice->SubmitSourceBuffer(&api_setting->internal_buffer[idx]))) { + LOG("Xaudio2: SubmitSourceBuffer failed\n", true, true); + + return; + } + + setting->sample_index += setting->sample_buffer_size / setting->sample_size; + setting->sample_buffer_size = 0; +} + #endif diff --git a/platform/win32/input/HidInput.h b/platform/win32/input/HidInput.h new file mode 100644 index 0000000..b29a1dd --- /dev/null +++ b/platform/win32/input/HidInput.h @@ -0,0 +1,164 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_INPUT_HID_H +#define TOS_PLATFORM_WIN32_INPUT_HID_H + +#include +#include +#include +#include +#include + +#include "../../../input/Input.h" +#include "../../../input/ControllerType.h" +#include "../../../memory/RingMemory.h" +#include "controller/DualShock4.h" + +#pragma comment(lib, "hid.lib") +#pragma comment(lib, "setupapi.lib") + +void hid_init_contorllers(Input* __restrict states, int32 state_count, RingMemory* ring) { + + HANDLE* controller_handles = NULL; + + // Get the GUID for HID devices + GUID hid_guid; + HidD_GetHidGuid(&hid_guid); + + // Get a handle to the device information set + HDEVINFO device_info_set = SetupDiGetClassDevs(&hid_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (device_info_set == INVALID_HANDLE_VALUE) { + return; + } + + SP_DEVICE_INTERFACE_DATA device_interface_data; + device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + DWORD device_index = 0; + int32 controller_found = 0; + + while (SetupDiEnumDeviceInterfaces(device_info_set, NULL, &hid_guid, device_index, &device_interface_data)) { + ++device_index; + DWORD required_size = 0; + + // First call to get required buffer size for device detail data + SetupDiGetDeviceInterfaceDetail(device_info_set, &device_interface_data, NULL, 0, &required_size, NULL); + PSP_DEVICE_INTERFACE_DETAIL_DATA device_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA) ring_get_memory(ring, required_size, 8); + device_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + // Get device interface detail + if (!SetupDiGetDeviceInterfaceDetail(device_info_set, &device_interface_data, device_detail_data, required_size, NULL, NULL)) { + continue; + } + + // Open the device + HANDLE device_handle = CreateFile( + device_detail_data->DevicePath, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL + ); + + if (device_handle == INVALID_HANDLE_VALUE) { + continue; + } + + // Check if the device is a gamepad or joystick by reading its attributes + HIDD_ATTRIBUTES attributes; + attributes.Size = sizeof(HIDD_ATTRIBUTES); + if (!HidD_GetAttributes(device_handle, &attributes)) { + continue; + } + + // Get the preparsed data to check usage page and usage ID + PHIDP_PREPARSED_DATA preparsed_data; + if (!HidD_GetPreparsedData(device_handle, &preparsed_data)) { + continue; + } + + HIDP_CAPS caps; + if (HidP_GetCaps(preparsed_data, &caps) == HIDP_STATUS_SUCCESS) { + HidD_FreePreparsedData(preparsed_data); + continue; + } + + // Check for game controllers (Generic Desktop Page, Gamepad or Joystick Usage) + if (caps.UsagePage == 0x01 && caps.Usage == 0x05) { + if (states[controller_found].handle_controller != NULL) { + ++controller_found; + } + + states[controller_found].handle_controller = device_handle; + // @bug This is not always true, how to check? + states[controller_found].connection_type = INPUT_CONNECTION_TYPE_USB; + + if (attributes.VendorID == 0x054C + && (attributes.ProductID == 0x05C4 || attributes.ProductID == 0x09CC) + ) { + states[controller_found].controller_type = CONTROLLER_TYPE_DUALSHOCK4; + } else if (attributes.VendorID == 0x054C + && (attributes.ProductID == 0x0CE6 || attributes.ProductID == 0x0DF2) + ) { + states[controller_found].controller_type = CONTROLLER_TYPE_DUALSENSE; + } else if (attributes.VendorID == 0x045E && attributes.ProductID == 0x02E0) { + states[controller_found].controller_type = CONTROLLER_TYPE_XBOX_360; + } else if (attributes.VendorID == 0x045E && attributes.ProductID == 0x02FF) { + states[controller_found].controller_type = CONTROLLER_TYPE_XBOX_ONE; + } else if (attributes.VendorID == 0x045E && attributes.ProductID == 0x028E) { + states[controller_found].controller_type = CONTROLLER_TYPE_XBOX_S; + } else { + states[controller_found].controller_type = CONTROLLER_TYPE_OTHER; + } + } else if (caps.UsagePage == 0x01 && caps.Usage == 0x04) { + if (states[controller_found].handle_controller != NULL) { + ++controller_found; + } + + states[controller_found].handle_controller = device_handle; + // @bug This is not always true, how to check? + states[controller_found].connection_type = INPUT_CONNECTION_TYPE_USB; + states[controller_found].controller_type = CONTROLLER_TYPE_OTHER; + } else { + CloseHandle(device_handle); + } + + HidD_FreePreparsedData(preparsed_data); + } + + SetupDiDestroyDeviceInfoList(device_info_set); +} + +uint32 hid_divice_poll(Input* state, uint64 time) { + UCHAR buffer[128]; + DWORD bytes_read; + + if (!ReadFile(state->handle_controller, buffer, sizeof(buffer), &bytes_read, NULL)) { + return 0; + } + + ControllerInput controller = {}; + switch(state->controller_type) { + case CONTROLLER_TYPE_DUALSHOCK4: { + input_map_dualshock4(&controller, state->connection_type, buffer); + } break; + default: { + }; + } + input_set_controller_state(state, &controller, time); + + state->state_change_button = true; + state->time_last_input_check = time; + + return 0; +} + +#endif \ No newline at end of file diff --git a/platform/win32/input/RawInput.h b/platform/win32/input/RawInput.h index 4c3f5ea..7e2ca01 100644 --- a/platform/win32/input/RawInput.h +++ b/platform/win32/input/RawInput.h @@ -13,6 +13,7 @@ #include "../../../stdlib/Types.h" #include "../../../input/Input.h" +#include "../../../input/ControllerType.h" #include "../../../input/ControllerInput.h" #include "controller/DualShock4.h" #include "../../../utils/TestUtils.h" @@ -24,9 +25,11 @@ #define INPUT_MOUSE_BUTTON_1 1 #define INPUT_MOUSE_BUTTON_2 2 -#define INPUT_MOUSE_BUTTON_3 4 -#define INPUT_MOUSE_BUTTON_4 8 -#define INPUT_MOUSE_BUTTON_5 16 +#define INPUT_MOUSE_BUTTON_3 3 +#define INPUT_MOUSE_BUTTON_4 4 +#define INPUT_MOUSE_BUTTON_5 5 +#define INPUT_MOUSE_BUTTON_WHEEL 6 +#define INPUT_MOUSE_BUTTON_HWHEEL 7 // IMPORTANT: // Even if it is nowhere documented (at least not to our knowledge) the GetRawInputDeviceInfoA, GetRawInputBuffer functions requried @@ -53,7 +56,6 @@ int rawinput_init_mousekeyboard(HWND hwnd, Input* __restrict states, RingMemory* int32 mouse_found = 0; int32 keyboard_found = 0; - int32 controller_found = 0; int32 i; for (i = 0; i < device_count; ++i) { @@ -108,6 +110,7 @@ int rawinput_init_mousekeyboard(HWND hwnd, Input* __restrict states, RingMemory* return i; } +// WARNING: While this works we highly recommend to use hid_init_contorllers int rawinput_init_controllers(HWND hwnd, Input* __restrict states, RingMemory* ring) { uint32 device_count; @@ -126,9 +129,6 @@ int rawinput_init_controllers(HWND hwnd, Input* __restrict states, RingMemory* r } uint32 cb_size = 256; - - int32 mouse_found = 0; - int32 keyboard_found = 0; int32 controller_found = 0; int32 i; @@ -150,6 +150,24 @@ int rawinput_init_controllers(HWND hwnd, Input* __restrict states, RingMemory* r // @bug This is not always true, how to check? states[controller_found].connection_type = INPUT_CONNECTION_TYPE_USB; + if (rdi.hid.dwVendorId == 0x054C + && (rdi.hid.dwProductId == 0x05C4 || rdi.hid.dwProductId == 0x09CC) + ) { + states[controller_found].controller_type = CONTROLLER_TYPE_DUALSHOCK4; + } else if (rdi.hid.dwVendorId == 0x054C + && (rdi.hid.dwProductId == 0x0CE6 || rdi.hid.dwProductId == 0x0DF2) + ) { + states[controller_found].controller_type = CONTROLLER_TYPE_DUALSENSE; + } else if (rdi.hid.dwVendorId == 0x045E && rdi.hid.dwProductId == 0x02E0) { + states[controller_found].controller_type = CONTROLLER_TYPE_XBOX_360; + } else if (rdi.hid.dwVendorId == 0x045E && rdi.hid.dwProductId == 0x02FF) { + states[controller_found].controller_type = CONTROLLER_TYPE_XBOX_ONE; + } else if (rdi.hid.dwVendorId == 0x045E && rdi.hid.dwProductId == 0x028E) { + states[controller_found].controller_type = CONTROLLER_TYPE_XBOX_S; + } else { + states[controller_found].controller_type = CONTROLLER_TYPE_OTHER; + } + // Gamepad rid[0].usUsagePage = 0x01; rid[0].usUsage = 0x05; @@ -168,6 +186,7 @@ int rawinput_init_controllers(HWND hwnd, Input* __restrict states, RingMemory* r states[controller_found].handle_controller = pRawInputDeviceList[i].hDevice; // @bug This is not always true, how to check? states[controller_found].connection_type = INPUT_CONNECTION_TYPE_USB; + states[controller_found].controller_type = CONTROLLER_TYPE_OTHER; // Joystick rid[0].usUsagePage = 0x01; @@ -222,54 +241,51 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* states, int32 state_coun if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) { key.key_state = KEY_STATE_PRESSED; - key.key_id = 1; + key.key_id = INPUT_MOUSE_BUTTON_1; } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) { key.key_state = KEY_STATE_RELEASED; - key.key_id = 1; + key.key_id = INPUT_MOUSE_BUTTON_1; } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) { key.key_state = KEY_STATE_PRESSED; - key.key_id = 2; + key.key_id = INPUT_MOUSE_BUTTON_2; } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) { key.key_state = KEY_STATE_RELEASED; - key.key_id = 2; + key.key_id = INPUT_MOUSE_BUTTON_2; } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) { key.key_state = KEY_STATE_PRESSED; - key.key_id = 3; + key.key_id = INPUT_MOUSE_BUTTON_3; } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) { key.key_state = KEY_STATE_RELEASED; - key.key_id = 3; + key.key_id = INPUT_MOUSE_BUTTON_3; } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) { key.key_state = KEY_STATE_PRESSED; - key.key_id = 4; + key.key_id = INPUT_MOUSE_BUTTON_4; } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) { key.key_state = KEY_STATE_RELEASED; - key.key_id = 4; + key.key_id = INPUT_MOUSE_BUTTON_4; } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) { key.key_state = KEY_STATE_PRESSED; - key.key_id = 5; + key.key_id = INPUT_MOUSE_BUTTON_5; } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) { key.key_state = KEY_STATE_RELEASED; - key.key_id = 5; + key.key_id = INPUT_MOUSE_BUTTON_5; + } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) { + key.key_state = KEY_STATE_RELEASED; + key.key_id = INPUT_MOUSE_BUTTON_WHEEL; + key.value = (int16) raw->data.mouse.usButtonData; + } else if (raw->data.mouse.usButtonFlags & RI_MOUSE_HWHEEL) { + key.key_state = KEY_STATE_RELEASED; + key.key_id = INPUT_MOUSE_BUTTON_HWHEEL; + key.value = (int16) raw->data.mouse.usButtonData; } else { return 0; } - /* @todo implement - if (raw->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) { - states[i].state.wheel_delta += raw->data.mouse.usButtonData; - } - - if (raw->data.mouse.usButtonFlags & RI_MOUSE_HWHEEL) { - states[i].state.hwheel_delta += raw->data.mouse.usButtonData; - } - */ - // @question is mouse wheel really considered a button change? ++input_count; key.key_id |= INPUT_MOUSE_PREFIX; - key.value = 0; key.time = time; input_set_state(&states[i].state, &key); @@ -337,34 +353,38 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* states, int32 state_coun InputKey key = {(uint16) (raw->data.keyboard.VKey | INPUT_KEYBOARD_PREFIX), new_state, 0, time}; input_set_state(&states[i].state, &key); states[i].state_change_button = true; - } else if (raw->header.dwType == RIM_TYPEHID) { - if (raw->header.dwSize > sizeof(RAWINPUT)) { - // @performance This shouldn't be done every time, it should be polling based - // Controllers often CONSTANTLY send data -> really bad - // Maybe we can add timer usage instead of polling? - while (i < state_count - && states[i].handle_controller != raw->header.hDevice - ) { - ++i; - } - - if (i >= state_count || !states[i].connection_type - || time - states[i].time_last_input_check < 5 - ) { - return 0; - } - - // @todo Find a way to handle most common controllers - // DualSense - // Xbox - // Xinput - // Best way would probably to define the controller type in the input - ControllerInput controller = {}; - input_map_dualshock4(&controller, states[i].connection_type, raw->data.hid.bRawData); - input_set_controller_state(&states[i], &controller, time); - - states[i].time_last_input_check = time; + } else if (raw->header.dwType == RIM_TYPEHID + && raw->header.dwSize > sizeof(RAWINPUT) + ) { + // @performance This shouldn't be done every time, it should be polling based + // Controllers often CONSTANTLY send data -> really bad + // Maybe we can add timer usage instead of polling? + // But we would still need to register them, right? + // Ideally we wouldn't even have to register them then because they would still pollute the general buffer + while (i < state_count + && states[i].handle_controller != raw->header.hDevice + ) { + ++i; } + + if (i >= state_count || !states[i].connection_type + || time - states[i].time_last_input_check < 5 + ) { + return 0; + } + + ControllerInput controller = {}; + switch(states[i].controller_type) { + case CONTROLLER_TYPE_DUALSHOCK4: { + input_map_dualshock4(&controller, states[i].connection_type, raw->data.hid.bRawData); + } break; + default: { + }; + } + input_set_controller_state(&states[i], &controller, time); + + states[i].state_change_button = true; + states[i].time_last_input_check = time; } return input_count; @@ -389,9 +409,7 @@ void input_handle(LPARAM lParam, Input* __restrict states, int state_count, Ring int32 input_handle_buffered(int buffer_size, Input* __restrict states, int state_count, RingMemory* ring, uint64 time) { - int32 input_count = 0; uint32 cb_size; - GetRawInputBuffer(NULL, &cb_size, sizeof(RAWINPUTHEADER)); if (!cb_size) { return 0; @@ -402,6 +420,7 @@ int32 input_handle_buffered(int buffer_size, Input* __restrict states, int state PRAWINPUT raw_input = (PRAWINPUT) ring_get_memory(ring, cb_size, 4); + int32 input_count = 0; uint32 input; while (true) { diff --git a/stdlib/Types.h b/stdlib/Types.h index 132a5d7..b6c5c0c 100644 --- a/stdlib/Types.h +++ b/stdlib/Types.h @@ -161,6 +161,10 @@ struct v4_f32 { f32 x, y, z, w; }; + struct { + f32 x1, y1, x2, y2; + }; + struct { f32 r, g, b, a; }; diff --git a/stdlib/simd/SIMD_I16.h b/stdlib/simd/SIMD_I16.h index 7b3a8a4..7b38e2d 100644 --- a/stdlib/simd/SIMD_I16.h +++ b/stdlib/simd/SIMD_I16.h @@ -789,4 +789,85 @@ inline bool all_false(int16_32 a) // @todo from down here we can optimize some of the code by NOT using the wrappers // the code is self contained and we could use te intrinsic functions directly +inline +void simd_mult(const int16* a, f32 b, int16* result, int32 size, int32 steps) +{ + int32 i = 0; + + if (steps == 16) { + __m512i a_16; + __m512 af_lo, af_hi; + __m512 b_16 = _mm512_set1_ps(b); + __m512 result_lo, result_hi; + __m512i result_16; + + for (; i <= size - steps; i += steps) { + a_16 = _mm512_loadu_si512((__m512i*) a); + + af_lo = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(a_16, 0))); + af_hi = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(a_16, 1))); + + result_lo = _mm512_mul_ps(af_lo, b_16); + result_hi = _mm512_mul_ps(af_hi, b_16); + + result_16 = _mm512_packs_epi32(_mm512_cvtps_epi32(result_lo), _mm512_cvtps_epi32(result_hi)); + _mm512_storeu_si512((__m512i*) result, result_16); + + a += steps; + result += steps; + } + } else if (steps == 8) { + __m256i a_8; + __m256 af_lo, af_hi; + __m256 b_8 = _mm256_set1_ps(b); + __m256 result_lo, result_hi; + __m256i result_8; + + for (; i <= size - steps; i += steps) { + a_8 = _mm256_loadu_si256((__m256i*) a); + + af_lo = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_extracti128_si256(a_8, 0))); + af_hi = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_extracti128_si256(a_8, 1))); + + result_lo = _mm256_mul_ps(af_lo, b_8); + result_hi = _mm256_mul_ps(af_hi, b_8); + + result_8 = _mm256_packs_epi32(_mm256_cvtps_epi32(result_lo), _mm256_cvtps_epi32(result_hi)); + _mm256_storeu_si256((__m256i*) result, result_8); + + a += steps; + result += steps; + } + } else if (steps == 4) { + __m128i a_4; + __m128 af_lo, af_hi; + __m128 b_4 = _mm_set1_ps(b); + __m128 result_lo, result_hi; + __m128i result_4; + + for (; i <= size - steps; i += steps) { + a_4 = _mm_loadu_si128((__m128i*) a); + + af_lo = _mm_cvtepi32_ps(_mm_cvtepi16_epi32(a_4)); + af_hi = _mm_cvtepi32_ps(_mm_cvtepi16_epi32(_mm_srli_si128(a_4, 8))); + + result_lo = _mm_mul_ps(af_lo, b_4); + result_hi = _mm_mul_ps(af_hi, b_4); + + result_4 = _mm_packs_epi32(_mm_cvtps_epi32(result_lo), _mm_cvtps_epi32(result_hi)); + _mm_storeu_si128((__m128i*) result, result_4); + + a += steps; + result += steps; + } + } + + // Handle any remaining elements + for (; i < size; ++i) { + *result = (int16) ((f32) (*a) * b); + ++a; + ++result; + } +} + #endif \ No newline at end of file diff --git a/utils/StringUtils.h b/utils/StringUtils.h index 5e96e67..0fb32e9 100644 --- a/utils/StringUtils.h +++ b/utils/StringUtils.h @@ -467,11 +467,25 @@ inline int32 chars_to_eol(const char* str) { int32 offset = 0; - while (!is_eol(str) && *str != '\0') { + while (!is_eol(str) && *str++ != '\0') { ++offset; } return offset; } +inline +int32 strcpy_to_eol(const char* src, char* dst) +{ + int32 offset = 0; + while (!is_eol(src) && *src != '\0') { + *dst++ = *src++; + ++offset; + } + + *dst = '\0'; + + return offset; +} + #endif \ No newline at end of file diff --git a/utils/Utils.h b/utils/Utils.h index 82e34c9..69d95b9 100644 --- a/utils/Utils.h +++ b/utils/Utils.h @@ -10,6 +10,7 @@ #define TOS_UTILS_H #include +#include #include "../stdlib/Types.h"