Started to render with normals. working

This commit is contained in:
Dennis Eichhorn 2024-11-09 02:05:07 +01:00
parent 149543016b
commit 2149c82b63
23 changed files with 983 additions and 707 deletions

View File

@ -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

31
environment/Globe.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef TOS_ENVIRONMENT_GLOBE_H
#define TOS_ENVIRONMENT_GLOBE_H
#include "../stdlib/Types.h"
#include <math.h>
// 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

View File

@ -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;
};

View File

@ -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;
}
}
}

24
input/ControllerType.h Normal file
View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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

View File

@ -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)

View File

@ -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,
&region1, &region1_size,
&region2, &region2_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

View File

@ -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

View File

@ -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 <windows.h>
#include <setupapi.h>
#include <hidsdi.h>
#include <stdio.h>
#include <stdlib.h>
#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

View File

@ -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) {

View File

@ -161,6 +161,10 @@ struct v4_f32 {
f32 x, y, z, w;
};
struct {
f32 x1, y1, x2, y2;
};
struct {
f32 r, g, b, a;
};

View File

@ -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

View File

@ -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

View File

@ -10,6 +10,7 @@
#define TOS_UTILS_H
#include <stdlib.h>
#include <time.h>
#include "../stdlib/Types.h"