diff --git a/compression/LZP.h b/compression/LZP.h index caf842a..8dc7d4a 100644 --- a/compression/LZP.h +++ b/compression/LZP.h @@ -132,7 +132,7 @@ uint32 lzp3_encode(const byte* in, size_t length, byte* out) { int32 out_size = 0; - int32 i = 0; + size_t i = 0; while (i < length) { int32 match_position = 0; int32 match_length = find_longest_match(window, window_start, (char *)&in[i], (int32) (length - i), &match_position); @@ -163,7 +163,7 @@ uint32 lzp3_decode(const byte* in, size_t length, byte* out) { int32 out_size = 0; - int32 i = 0; + size_t i = 0; while (i < length) { if (in[i] == 0xFF) { int32 match_position = in[i + 1]; diff --git a/gpuapi/RenderUtils.h b/gpuapi/RenderUtils.h index 0e20005..02c7005 100644 --- a/gpuapi/RenderUtils.h +++ b/gpuapi/RenderUtils.h @@ -456,6 +456,8 @@ void text_calculate_dimensions( *height = y; } +// @todo implement shadow (offset + angle + diffuse) or should this be a shader only thing? if so this would be a problem for us since we are handling text in the same shader as simple shapes +// we might want to implement distance field font atlas f32 vertex_text_create( Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, f32 x, f32 y, f32 width, f32 height, int32 align_h, int32 align_v, @@ -543,6 +545,8 @@ f32 vertex_text_create( return offset_x; } +// @todo implement shadow (offset + angle + diffuse) or should this be a shader only thing? if so this would be a problem for us since we are handling text in the same shader as simple shapes +// we might want to implement distance field font atlas f32 ui_text_create( Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex, UITheme* theme, UIElement* element diff --git a/gpuapi/opengl/OpenglUtils.h b/gpuapi/opengl/OpenglUtils.h index 8ed50e0..96dde47 100644 --- a/gpuapi/opengl/OpenglUtils.h +++ b/gpuapi/opengl/OpenglUtils.h @@ -176,7 +176,7 @@ GLuint shader_make(GLenum type, const char *source, RingMemory* ring) inline GLuint shader_load(GLenum type, const char* path, RingMemory* ring) { - uint64 temp = ring->pos; + byte* temp = ring->head; FileBody file; @@ -185,7 +185,7 @@ GLuint shader_load(GLenum type, const char* path, RingMemory* ring) { GLuint result = shader_make(type, (const char *) file.content, ring); // We can immediately dispose of it we can also reset our ring memory position - ring->pos = temp; + ring->head = temp; return result; } diff --git a/log/Debug.cpp b/log/Debug.cpp index b1d5977..aeabce5 100644 --- a/log/Debug.cpp +++ b/log/Debug.cpp @@ -13,12 +13,70 @@ global_persist DebugContainer* debug_container = NULL; #if _WIN32 #include void setup_performance_count() { + if (!debug_container) { + return; + } + LARGE_INTEGER perf_counter; QueryPerformanceFrequency(&perf_counter); debug_container->performance_count_frequency = perf_counter.QuadPart; } +#else + void setup_performance_count() { + if (!debug_container) { + return; + } + + FILE* fp = fopen("/proc/cpuinfo", "r"); + if (!fp) { + return; + } + + char line[256]; + uint64 cpu_freq = 0; + while (fgets(line, sizeof(line), fp)) { + if (sscanf(line, "cpu MHz%*[^0-9]%ld", &cpu_freq) == 1) { + break; + } + } + + fclose(fp); + + debug_container->performance_count_frequency = cpu_freq == 0 ? 1 : cpu_freq * 1000000; + } #endif +void log_to_file() +{ + // we don't log an empty log pool + if (!debug_container || debug_container->log_memory.pos == 0 || !debug_container->log_fp) { + return; + } + + #if _WIN32 + DWORD written; + if (!WriteFile( + debug_container->log_fp, (char *) debug_container->log_memory.memory, (uint32) debug_container->log_memory.pos - 1, &written, NULL) + ) { + CloseHandle(debug_container->log_fp); + } + #else + if (debug_container->log_fp < 0) { + return; + } + + if (!write(debug_container->log_fp, (char *) debug_container->log_memory.memory, (uint32) debug_container->log_memory.pos - 1)) { + close(debug_container->log_fp); + } + #endif + + memset(debug_container->log_memory.memory, 0, debug_container->log_memory.size); + + // reset log position to start of memory pool + debug_container->log_memory.pos = 0; + debug_container->log_memory.start = 0; +} + // IMPORTANT: This function should only be called when you actually use this data // e.g. log to display or file inline @@ -33,7 +91,7 @@ void update_timing_stat(uint32 stat, const char* function) } inline -void update_timing_stat_start(uint32 stat, const char* function) +void update_timing_stat_start(uint32 stat, const char*) { uint64 new_tick_count = __rdtsc(); @@ -92,7 +150,7 @@ void log_counter(int32 id, int32 value) inline DebugMemory* debug_memory_find(uint64 start) { - for (int32 i = 0; i < debug_container->dmc.memory_size; ++i) { + for (uint64 i = 0; i < debug_container->dmc.memory_size; ++i) { if (debug_container->dmc.memory_stats[i].start <= start && debug_container->dmc.memory_stats[i].start + debug_container->dmc.memory_stats[i].size >= start ) { @@ -152,7 +210,7 @@ void debug_memory_log(uint64 start, uint64 size, int32 type, const char* functio mem->last_action[mem->action_idx].start = start - mem->start; mem->last_action[mem->action_idx].size = size; - // @question consider to use other time_ms() since __rdtsc is variable (boost, power saving) + // We are using rdtsc since it is faster -> less debugging overhead than using time() mem->last_action[mem->action_idx].time = __rdtsc(); mem->last_action[mem->action_idx].function_name = function; @@ -179,7 +237,7 @@ void debug_memory_reserve(uint64 start, uint64 size, int32 type, const char* fun mem->reserve_action[mem->reserve_action_idx].start = start - mem->start; mem->reserve_action[mem->reserve_action_idx].size = size; - // @question consider to use other time_ms() since __rdtsc is variable (boost, power saving) + // We are using rdtsc since it is faster -> less debugging overhead than using time() mem->reserve_action[mem->reserve_action_idx].time = __rdtsc(); mem->reserve_action[mem->reserve_action_idx].function_name = function; @@ -195,7 +253,7 @@ void debug_memory_reset() uint64 time = __rdtsc() - 1000000000; - for (int32 i = 0; i < debug_container->dmc.memory_element_idx; ++i) { + for (uint64 i = 0; i < debug_container->dmc.memory_element_idx; ++i) { for (int32 j = 0; j < DEBUG_MEMORY_RANGE_MAX; ++j) { if (debug_container->dmc.memory_stats[i].last_action[j].time < time) { memset(&debug_container->dmc.memory_stats[i].last_action[j], 0, sizeof(DebugMemoryRange)); @@ -237,109 +295,90 @@ byte* log_get_memory(uint64 size, byte aligned = 1, bool zeroed = false) return offset; } -#ifdef _WIN32 - void log_to_file() - { - // we don't log an empty log pool - if (!debug_container || debug_container->log_memory.pos == 0 || !debug_container->log_fp || debug_container->log_fp == INVALID_HANDLE_VALUE) { - return; - } - - DWORD written; - if (!WriteFile(debug_container->log_fp, (char *) debug_container->log_memory.memory, (uint32) debug_container->log_memory.pos - 1, &written, NULL)) { - CloseHandle(debug_container->log_fp); - } - - memset(debug_container->log_memory.memory, 0, debug_container->log_memory.size); - - // reset log position to start of memory pool - debug_container->log_memory.pos = 0; - debug_container->log_memory.start = 0; +// @todo add file name, function name and function line +void log(const char* str, bool should_log, bool save, const char* file, const char* function, int32 line) +{ + if (!should_log || !debug_container) { + return; } - // @todo add file name, function name and function line - void log(const char* str, bool should_log, bool save, const char* file, const char* function, int32 line) - { - if (!should_log || !debug_container) { - return; - } + size_t str_len = strlen(str); + size_t file_len = strlen(file); + size_t function_len = strlen(function); - size_t str_len = strlen(str); - size_t file_len = strlen(file); - size_t function_len = strlen(function); + char line_str[10]; + int_to_str(line, line_str, '\0'); - char line_str[10]; - int_to_str(line, line_str, '\0'); + size_t line_len = strlen(line_str); - size_t line_len = strlen(line_str); + ASSERT_SIMPLE(str_len + file_len + function_len + line_len + 3 < MAX_LOG_LENGTH); - ASSERT_SIMPLE(str_len + file_len + function_len + line_len + 3 < MAX_LOG_LENGTH); + char* temp = (char *) log_get_memory(str_len + file_len + function_len + line_len + 3 + 1); + memcpy(temp, file, file_len); + temp[file_len] = ';'; - char* temp = (char *) log_get_memory(str_len + file_len + function_len + line_len + 3 + 1); - memcpy(temp, file, file_len); - temp[file_len] = ';'; + memcpy(&temp[file_len], function, function_len); + temp[file_len + 1 + function_len] = ';'; - memcpy(&temp[file_len], function, function_len); - temp[file_len + 1 + function_len] = ';'; + memcpy(&temp[file_len + 1 + function_len], line_str, line_len); + temp[file_len + 1 + function_len + 1 + line_len] = ';'; - memcpy(&temp[file_len + 1 + function_len], line_str, line_len); - temp[file_len + 1 + function_len + 1 + line_len] = ';'; + memcpy(&temp[file_len + 1 + function_len + 1 + line_len + 1], str, str_len); + temp[file_len + 1 + function_len + 1 + line_len + 1 + str_len] = '\0'; - memcpy(&temp[file_len + 1 + function_len + 1 + line_len + 1], str, str_len); - temp[file_len + 1 + function_len + 1 + line_len + 1 + str_len] = '\0'; - - if (save || debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) { - log_to_file(); - } - - ASSERT_SIMPLE(false); + if (save || debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) { + log_to_file(); } - void log(const char* format, LogDataType data_type, void* data, bool should_log, bool save, const char* file, const char* function, int32 line) - { - if (!should_log || !debug_container) { - return; - } + ASSERT_SIMPLE(false); +} - if (data_type == LOG_DATA_VOID) { - log(format, should_log, save, file, function, line); - } - - char* temp = (char *) log_get_memory(MAX_LOG_LENGTH); - - switch (data_type) { - case LOG_DATA_INT32: { - sprintf(temp, format, *((int32 *) data)); - } break; - case LOG_DATA_UINT32: { - sprintf(temp, format, *((uint32 *) data)); - } break; - case LOG_DATA_INT64: { - sprintf(temp, format, *((int64 *) data)); - } break; - case LOG_DATA_UINT64: { - sprintf(temp, format, *((uint64 *) data)); - } break; - case LOG_DATA_CHAR: { - sprintf(temp, format, *((char *) data)); - } break; - case LOG_DATA_CHAR_STR: { - sprintf(temp, format, *((char *) data)); - } break; - case LOG_DATA_FLOAT32: { - sprintf(temp, format, *((f32 *) data)); - } break; - case LOG_DATA_FLOAT64: { - sprintf(temp, format, *((f64 *) data)); - } break; - } - - 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) +{ + if (!should_log || !debug_container) { + return; } -#endif + + if (data_type == LOG_DATA_VOID) { + log(format, should_log, save, file, function, line); + } + + char* temp = (char *) log_get_memory(MAX_LOG_LENGTH); + + switch (data_type) { + case LOG_DATA_INT32: { + sprintf(temp, format, *((int32 *) data)); + } break; + case LOG_DATA_UINT32: { + sprintf(temp, format, *((uint32 *) data)); + } break; + case LOG_DATA_INT64: { + sprintf(temp, format, *((int64 *) data)); + } break; + case LOG_DATA_UINT64: { + sprintf(temp, format, *((uint64 *) data)); + } break; + case LOG_DATA_CHAR: { + sprintf(temp, format, *((char *) data)); + } break; + case LOG_DATA_CHAR_STR: { + sprintf(temp, format, *((char *) data)); + } break; + case LOG_DATA_FLOAT32: { + sprintf(temp, format, *((f32 *) data)); + } break; + case LOG_DATA_FLOAT64: { + sprintf(temp, format, *((f64 *) data)); + } break; + default: {} + } + + if (save || debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) { + log_to_file(); + } + + ASSERT_SIMPLE(false); +} + #endif \ No newline at end of file diff --git a/log/Debug.h b/log/Debug.h index 5473052..99cf579 100644 --- a/log/Debug.h +++ b/log/Debug.h @@ -14,6 +14,17 @@ #include "Log.h" #include "TimingStat.h" +struct LogMemory { + byte* memory; + + uint32 id; + uint64 size; + uint64 pos; + int32 alignment; + uint64 start; + uint64 end; +}; + struct DebugContainer { DebugMemoryContainer dmc; @@ -31,6 +42,8 @@ struct DebugContainer { #if _WIN32 HANDLE log_fp; + #elif __linux__ + int32 log_fp; #endif }; diff --git a/log/DebugMemory.h b/log/DebugMemory.h index f208af3..8fba803 100644 --- a/log/DebugMemory.h +++ b/log/DebugMemory.h @@ -54,7 +54,7 @@ struct DebugMemoryContainer { #if DEBUG || INTERNAL void debug_memory_init(uint64, uint64); void debug_memory_log(uint64, uint64, int32, const char*); - void debug_memory_reserve(uint64, uint64, const char*); + void debug_memory_reserve(uint64, uint64, int32, const char*); void debug_memory_reset(); #define DEBUG_MEMORY_INIT(start, size) debug_memory_init((start), (size)) diff --git a/log/Log.h b/log/Log.h index 507ea41..cf55316 100644 --- a/log/Log.h +++ b/log/Log.h @@ -41,17 +41,6 @@ enum LogDataType { LOG_DATA_FLOAT64 }; -struct LogMemory { - byte* memory; - - uint32 id; - uint64 size; - uint64 pos; - int32 alignment; - uint64 start; - uint64 end; -}; - void log_to_file(); void log(const char* str, bool should_log, bool save, const char* file, const char* function, int32 line); void log(const char* format, LogDataType data_type, void* data, bool should_log, bool save, const char* file, const char* function, int32 line); @@ -71,7 +60,7 @@ void log_counter(int32, int32); #define LOG(str, should_log, save) log((str), (should_log), (save), __FILE__, __func__, __LINE__) #define LOG_FORMAT(format, data_type, data, should_log, save) log((format), (data_type), (data), (should_log), (save), __FILE__, __func__, __LINE__) #define LOG_TO_FILE() log_to_file() - #define LOG_INCREMENT(a) log_increment((a)) + #define LOG_INCREMENT(a) log_increment((a), 1) #define LOG_INCREMENT_BY(a, b) log_increment((a), (b)) #define LOG_COUNTER(a, b) log_counter((a), (b)) #define RESET_COUNTER(a) reset_counter((a)) diff --git a/memory/Allocation.h b/memory/Allocation.h deleted file mode 100644 index fdef880..0000000 --- a/memory/Allocation.h +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Jingga - * - * @copyright Jingga - * @license OMS License 2.0 - * @version 1.0.0 - * @link https://jingga.app - */ -#ifndef TOS_MEMORY_ALLOCATION_H -#define TOS_MEMORY_ALLOCATION_H - -#include - -#if _WIN32 - #include - - inline - void* aligned_alloc(size_t alignment, size_t size) { - return _aligned_malloc(size, alignment); - } - - inline - void aligned_free(void** ptr) { - _aligned_free(*ptr); - *ptr = NULL; - } - - inline - void* playform_alloc(size_t size) - { - return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - } - - inline - void* playform_alloc_aligned(size_t size, int32 alignment) - { - void* ptr = VirtualAlloc(NULL, size + alignment + sizeof(void*), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - - void* aligned_ptr = (void*)(((uintptr_t)ptr + alignment + sizeof(void*) - 1) & ~(alignment - 1)); - ((void**) aligned_ptr)[-1] = ptr; - - return aligned_ptr; - } - - inline - void platform_free(void** ptr, size_t) { - VirtualFree(*ptr, 0, MEM_RELEASE); - *ptr = NULL; - } - - inline - void platform_aligned_free(void** aligned_ptr, size_t) { - void* ptr = ((void**) *aligned_ptr)[-1]; - VirtualFree(ptr, 0, MEM_RELEASE); - *aligned_ptr = NULL; - } -#else - #include - #include - - inline - void aligned_free(void** ptr) { - free(*ptr); - *ptr = NULL; - } - - inline - void* playform_alloc(size_t size) - { - // Get the system page size - size_t page_size = sysconf(_SC_PAGESIZE); - - // Round up to the nearest page size - size = (size + page_size - 1) & ~(page_size - 1); - - return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - } - - inline - void* playform_alloc_aligned(size_t size, int32 alignment) - { - // Get the system page size - size_t page_size = sysconf(_SC_PAGESIZE); - if (alignment < page_size) { - alignment = page_size; - } - - // Round up to the nearest alignment boundary - size = (size + alignment - 1) & ~(alignment - 1); - - void* ptr = mmap(NULL, size + alignment + sizeof(void*), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - void* aligned_ptr = (void*)(((uintptr_t)ptr + alignment + sizeof(void*) - 1) & ~(alignment - 1)); - ((void**) aligned_ptr)[-1] = ptr; - - return aligned_ptr; - } - - inline - void platform_free(void** ptr, size_t size) { - munmap(*ptr, size); - *ptr = NULL; - } - - inline - void platform_aligned_free(void** aligned_ptr, size_t size) { - void* ptr = ((void**) *aligned_ptr)[-1]; - munmap(ptr, size + ((uintptr_t) *aligned_ptr - (uintptr_t)ptr)); - *aligned_ptr = NULL; - } -#endif - -#endif \ No newline at end of file diff --git a/memory/BufferMemory.h b/memory/BufferMemory.h index 2b3c787..9e94712 100644 --- a/memory/BufferMemory.h +++ b/memory/BufferMemory.h @@ -14,16 +14,22 @@ #include "../utils/MathUtils.h" #include "../utils/EndianUtils.h" #include "../utils/TestUtils.h" -#include "Allocation.h" #include "../log/DebugMemory.h" +#if _WIN32 + #include "../platform/win32/Allocation.h" +#elif __linux__ + #include "../platform/linux/Allocation.h" +#endif + // @question Consider to use element_alignment to automatically align/pad elmeents struct BufferMemory { byte* memory; + byte* end; + byte* head; uint64 size; - uint64 pos; int32 alignment; int32 element_alignment; }; @@ -34,12 +40,14 @@ void buffer_alloc(BufferMemory* buf, uint64 size, int32 alignment = 64) ASSERT_SIMPLE(size); buf->memory = alignment < 2 - ? (byte *) playform_alloc(size) - : (byte *) playform_alloc_aligned(size, alignment); + ? (byte *) platform_alloc(size) + : (byte *) platform_alloc_aligned(size, alignment); + buf->end = buf->memory + size; + buf->head = buf->memory; + buf->size = size; buf->alignment = alignment; buf->element_alignment = 0; - buf->size = size; memset(buf->memory, 0, buf->size); @@ -65,8 +73,9 @@ void buffer_init(BufferMemory* buf, byte* data, uint64 size, int32 alignment = 6 // @bug what if an alignment is defined? buf->memory = data; + buf->end = buf->memory + size; + buf->head = buf->memory; buf->size = size; - buf->pos = 0; buf->alignment = alignment; buf->element_alignment = 0; @@ -78,8 +87,8 @@ inline void buffer_reset(BufferMemory* buf) { // @bug arent we wasting element 0 (see get_memory, we are not using 0 only next element) - DEBUG_MEMORY_DELETE((uint64) buf->memory, buf->pos); - buf->pos = 0; + DEBUG_MEMORY_DELETE((uint64) buf->memory, buf->head - buf->memory); + buf->head = buf->memory; } inline @@ -92,21 +101,23 @@ byte* buffer_get_memory(BufferMemory* buf, uint64 size, int32 aligned = 0, bool } if (aligned > 1) { - uintptr_t address = (uintptr_t) buf->memory; - buf->pos += (aligned - ((address + buf->pos) & (aligned - 1))) % aligned; + uintptr_t address = (uintptr_t) buf->head; + buf->head += (aligned - (address & (aligned - 1))) % aligned; } size = ROUND_TO_NEAREST(size, aligned); - ASSERT_SIMPLE(buf->pos + size <= buf->size); + ASSERT_SIMPLE(buf->head + size <= buf->end); - byte* offset = (byte *) (buf->memory + buf->pos); if (zeroed) { - memset((void *) offset, 0, size); + memset((void *) buf->head, 0, size); } - DEBUG_MEMORY_WRITE((uint64) offset, size); + DEBUG_MEMORY_WRITE((uint64) buf->head, size); - buf->pos += size; + byte* offset = buf->head; + buf->head += size; + + ASSERT_SIMPLE(offset); return offset; } @@ -120,9 +131,9 @@ int64 buffer_dump(const BufferMemory* buf, byte* data) *((uint64 *) data) = SWAP_ENDIAN_LITTLE(buf->size); data += sizeof(buf->size); - // Pos - *((uint64 *) data) = SWAP_ENDIAN_LITTLE(buf->pos); - data += sizeof(buf->pos); + // head + *((uint64 *) data) = SWAP_ENDIAN_LITTLE((uint64) (buf->head - buf->memory)); + data += sizeof(uint64); // Alignment *((int32 *) data) = SWAP_ENDIAN_LITTLE(buf->alignment); @@ -131,6 +142,10 @@ int64 buffer_dump(const BufferMemory* buf, byte* data) *((int32 *) data) = SWAP_ENDIAN_LITTLE(buf->element_alignment); data += sizeof(buf->element_alignment); + // End + *((uint64 *) data) = SWAP_ENDIAN_LITTLE((uint64) (buf->end - buf->memory)); + data += sizeof(buf->end); + // All memory is handled in the buffer -> simply copy the buffer memcpy(data, buf->memory, buf->size); data += buf->size; @@ -141,13 +156,15 @@ int64 buffer_dump(const BufferMemory* buf, byte* data) inline int64 buffer_load(BufferMemory* buf, const byte* data) { + const byte* start = data; + // Size buf->size = SWAP_ENDIAN_LITTLE(*((uint64 *) data)); data += sizeof(buf->size); - // Pos - buf->pos = SWAP_ENDIAN_LITTLE(*((uint64 *) data)); - data += sizeof(buf->pos); + // head + buf->head = buf->memory + SWAP_ENDIAN_LITTLE(*((uint64 *) data)); + data += sizeof(uint64); // Alignment buf->alignment = SWAP_ENDIAN_LITTLE(*((int32 *) data)); @@ -156,8 +173,14 @@ int64 buffer_load(BufferMemory* buf, const byte* data) buf->element_alignment = SWAP_ENDIAN_LITTLE(*((int32 *) data)); data += sizeof(buf->element_alignment); + // End + buf->end = buf->memory + SWAP_ENDIAN_LITTLE(*((uint64 *) data)); + data += sizeof(uint64); + memcpy(buf->memory, data, buf->size); data += buf->size; + + return data - start; } #endif \ No newline at end of file diff --git a/memory/ChunkMemory.h b/memory/ChunkMemory.h index 140d71a..1ad3a26 100644 --- a/memory/ChunkMemory.h +++ b/memory/ChunkMemory.h @@ -6,15 +6,22 @@ * @version 1.0.0 * @link https://jingga.app */ -#ifndef TOS_MEMORY_ELEMENT_MEMORY_H -#define TOS_MEMORY_ELEMENT_MEMORY_H +#ifndef TOS_MEMORY_CHUNK_MEMORY_H +#define TOS_MEMORY_CHUNK_MEMORY_H #include #include "../stdlib/Types.h" #include "../utils/MathUtils.h" +#include "../utils/TestUtils.h" #include "../utils/EndianUtils.h" -#include "Allocation.h" #include "../log/DebugMemory.h" +#include "BufferMemory.h" + +#if _WIN32 + #include "../platform/win32/Allocation.h" +#elif __linux__ + #include "../platform/linux/Allocation.h" +#endif struct ChunkMemory { byte* memory; @@ -37,8 +44,8 @@ void chunk_alloc(ChunkMemory* buf, uint64 count, uint64 chunk_size, int32 alignm ASSERT_SIMPLE(count); buf->memory = alignment < 2 - ? (byte *) playform_alloc(count * chunk_size + sizeof(buf->free) * CEIL_DIV(count, 64)) - : (byte *) playform_alloc_aligned(count * chunk_size + sizeof(buf->free) * CEIL_DIV(count, 64), alignment); + ? (byte *) platform_alloc(count * chunk_size + sizeof(buf->free) * CEIL_DIV(count, 64)) + : (byte *) platform_alloc_aligned(count * chunk_size + sizeof(buf->free) * CEIL_DIV(count, 64), alignment); buf->count = count; buf->size = count * chunk_size + sizeof(buf->free) * CEIL_DIV(count, 64); @@ -124,6 +131,8 @@ byte* chunk_get_element(ChunkMemory* buf, uint64 element, bool zeroed = false) DEBUG_MEMORY_READ((uint64) offset, buf->chunk_size); + ASSERT_SIMPLE(offset); + return offset; } diff --git a/memory/RingMemory.h b/memory/RingMemory.h index 66f92f6..243ce62 100644 --- a/memory/RingMemory.h +++ b/memory/RingMemory.h @@ -10,34 +10,37 @@ #define TOS_MEMORY_RING_MEMORY_H #include +#include #include "../stdlib/Types.h" #include "../utils/MathUtils.h" #include "../utils/EndianUtils.h" #include "../utils/TestUtils.h" -#include "Allocation.h" #include "BufferMemory.h" #include "../log/DebugMemory.h" +#if _WIN32 + #include "../platform/win32/Allocation.h" +#elif __linux__ + #include "../platform/linux/Allocation.h" +#endif + struct RingMemory { byte* memory; + byte* end; + + byte* head; + + // This variable is usually only used by single read/write code mostly found in threads. + // One thread inserts elements -> updates head + // The other thread reads elements -> updates tail + // This code itself doesn't change this variable + byte* tail; uint64 size; - uint64 pos; int32 alignment; int32 element_alignment; - - // The following two indices are only used in special cases such as iterating through a portion - // of the ring memory. In such cases it may be necessary to know where the start and end are. - // Examples for such cases are if a worker thread is pulling data from this ring memory in chunks. - - // @question Is it guaranteed that if a thread realizes end changed, that also the memory is changed - // or is it possible that end changed but it still has old *memory in the cache? - // if yes we need to also check and wait for *memory != NULL and obviously set the memory to NULL - // after using it. - uint64 start; - uint64 end; }; inline @@ -46,15 +49,15 @@ void ring_alloc(RingMemory* ring, uint64 size, int32 alignment = 64) ASSERT_SIMPLE(size); ring->memory = alignment < 2 - ? (byte *) playform_alloc(size) - : (byte *) playform_alloc_aligned(size, alignment); + ? (byte *) platform_alloc(size) + : (byte *) platform_alloc_aligned(size, alignment); + ring->end = ring->memory + size;; + ring->head = ring->memory; + ring->tail = ring->memory; ring->size = size; - ring->pos = 0; ring->alignment = alignment; ring->element_alignment = 0; - ring->start = 0; - ring->end = 0; memset(ring->memory, 0, ring->size); @@ -68,12 +71,12 @@ void ring_init(RingMemory* ring, BufferMemory* buf, uint64 size, int32 alignment ring->memory = buffer_get_memory(buf, size, alignment, true); + ring->end = ring->memory + size;; + ring->head = ring->memory; + ring->tail = ring->memory; ring->size = size; - ring->pos = 0; ring->alignment = alignment; ring->element_alignment = 0; - ring->start = 0; - ring->end = 0; DEBUG_MEMORY_INIT((uint64) ring->memory, ring->size); DEBUG_MEMORY_RESERVE((uint64) ring->memory, ring->size, 187); @@ -87,12 +90,12 @@ void ring_init(RingMemory* ring, byte* buf, uint64 size, int32 alignment = 64) // @bug what if an alignment is defined? ring->memory = buf; + ring->end = ring->memory + size;; + ring->head = ring->memory; + ring->tail = ring->memory; ring->size = size; - ring->pos = 0; ring->alignment = alignment; ring->element_alignment = 0; - ring->start = 0; - ring->end = 0; memset(ring->memory, 0, ring->size); @@ -111,35 +114,37 @@ void ring_free(RingMemory* buf) } inline -uint64 ring_calculate_position(const RingMemory* ring, uint64 pos, uint64 size, byte aligned = 0) +byte* ring_calculate_position(const RingMemory* ring, uint64 size, byte aligned = 0) { if (aligned == 0) { aligned = (byte) OMS_MAX(ring->element_alignment, 1); } - if (aligned) { - uintptr_t address = (uintptr_t) ring->memory; - pos += (aligned - ((address + ring->pos) & (aligned - 1))) % aligned; + byte* head = ring->head; + + if (aligned > 1) { + uintptr_t address = (uintptr_t) head; + head += (aligned - (address & (aligned - 1))) % aligned; } size = ROUND_TO_NEAREST(size, aligned); - if (pos + size > ring->size) { - pos = 0; + if (head + size > ring->end) { + head = ring->memory; if (aligned > 1) { - uintptr_t address = (uintptr_t) ring->memory; - pos += (aligned - ((address + ring->pos) & (aligned - 1))) % aligned; + uintptr_t address = (uintptr_t) head; + head += (aligned - (address & (aligned - 1))) % aligned; } } - return pos; + return head; } inline void ring_reset(RingMemory* ring) { DEBUG_MEMORY_DELETE((uint64) ring->memory, ring->size); - ring->pos = 0; + ring->head = ring->memory; } byte* ring_get_memory(RingMemory* ring, uint64 size, byte aligned = 0, bool zeroed = false) @@ -151,28 +156,30 @@ byte* ring_get_memory(RingMemory* ring, uint64 size, byte aligned = 0, bool zero } if (aligned > 1) { - uintptr_t address = (uintptr_t) ring->memory; - ring->pos += (aligned - ((address + ring->pos) & (aligned - 1))) % aligned; + uintptr_t address = (uintptr_t) ring->head; + ring->head += (aligned - (address& (aligned - 1))) % aligned; } size = ROUND_TO_NEAREST(size, aligned); - if (ring->pos + size > ring->size) { + if (ring->head + size > ring->end) { ring_reset(ring); if (aligned > 1) { - uintptr_t address = (uintptr_t) ring->memory; - ring->pos += (aligned - ((address + ring->pos) & (aligned - 1))) % aligned; + uintptr_t address = (uintptr_t) ring->head; + ring->head += (aligned - (address & (aligned - 1))) % aligned; } } - byte* offset = (byte *) (ring->memory + ring->pos); if (zeroed) { - memset((void *) offset, 0, size); + memset((void *) ring->head, 0, size); } - DEBUG_MEMORY_WRITE((uint64) offset, size); + DEBUG_MEMORY_WRITE((uint64) ring->head, size); - ring->pos += size; + byte* offset = ring->head; + ring->head += size; + + ASSERT_SIMPLE(offset); return offset; } @@ -190,34 +197,49 @@ byte* ring_get_element(const RingMemory* ring, uint64 element_count, uint64 elem } /** - * Checks if one additional element can be inserted without overwriting the start index + * Checks if one additional element can be inserted without overwriting the tail index */ inline bool ring_commit_safe(const RingMemory* ring, uint64 size, byte aligned = 0) { - uint64 pos = ring_calculate_position(ring, ring->pos, size, aligned); + // aligned * 2 since that should be the maximum overhead for an element + uint64 max_mem_required = size + aligned * 2; - if (ring->start == ring->end && ring->pos == 0) { + if (ring->tail < ring->head) { + return ((uint64) (ring->end - ring->head)) > max_mem_required + || ((uint64) (ring->tail - ring->memory)) > max_mem_required; + } else if (ring->tail > ring->head) { + return ((uint64) (ring->tail - ring->head)) > max_mem_required; + } else { + // @question Is this really the case? What if it is completely filled? return true; } +} - return ring->start < ring->pos - ? ring->start < pos - : pos < ring->start; +inline +void ring_force_head_update(const RingMemory* ring) +{ + _mm_clflush(ring->head); +} + +inline +void ring_force_tail_update(const RingMemory* ring) +{ + _mm_clflush(ring->tail); } inline int64 ring_dump(const RingMemory* ring, byte* data) { - byte* start = data; + byte* tail = data; // Size *((uint64 *) data) = SWAP_ENDIAN_LITTLE(ring->size); data += sizeof(ring->size); - // Pos - *((uint64 *) data) = SWAP_ENDIAN_LITTLE(ring->pos); - data += sizeof(ring->pos); + // head + *((uint64 *) data) = SWAP_ENDIAN_LITTLE((uint64) (ring->head - ring->memory)); + data += sizeof(ring->head); // Alignment *((int32 *) data) = SWAP_ENDIAN_LITTLE(ring->alignment); @@ -226,18 +248,18 @@ int64 ring_dump(const RingMemory* ring, byte* data) *((int32 *) data) = SWAP_ENDIAN_LITTLE(ring->element_alignment); data += sizeof(ring->element_alignment); - // Start/End - *((uint64 *) data) = SWAP_ENDIAN_LITTLE(ring->start); - data += sizeof(ring->start); + // tail/End + *((uint64 *) data) = SWAP_ENDIAN_LITTLE((uint64) (ring->tail - ring->memory)); + data += sizeof(ring->tail); - *((uint64 *) data) = SWAP_ENDIAN_LITTLE(ring->end); + *((uint64 *) data) = SWAP_ENDIAN_LITTLE((uint64) (ring->end - ring->memory)); data += sizeof(ring->end); // All memory is handled in the buffer -> simply copy the buffer memcpy(data, ring->memory, ring->size); data += ring->size; - return data - start; + return data - tail; } #endif \ No newline at end of file diff --git a/models/settings/Settings.h b/models/settings/Settings.h index e960ce9..d0bd7cc 100644 --- a/models/settings/Settings.h +++ b/models/settings/Settings.h @@ -10,715 +10,28 @@ #define TOS_MODELS_SETTINGS_H #include "../../stdlib/Types.h" -#include "../../gpuapi/AntiAliasing.h" -#include "../chat/ChatStatus.h" -#include "setting_types.h" -#include "../../module/Module.h" #if _WIN32 - #include - #include "../../platform/win32/input/controller/ControllerHandler.h" -#else __linux__ - #include - #define MAX_PATH PATH_MAX + #include +#elif __linux__ + #include #endif -#ifndef RENDER_CHUNK_RADIUS - #define RENDER_CHUNK_RADIUS 10 -#endif - -#ifndef RENDER_BLOCK_OBJECT_CHUNK_RADIUS - #define RENDER_BLOCK_OBJECT_CHUNK_RADIUS 10 -#endif - -#ifndef RENDER_INTERACTIVE_CHUNK_RADIUS - #define RENDER_INTERACTIVE_CHUNK_RADIUS 1 -#endif - -#ifndef RENDER_OBJECT_CHUNK_RADIUS - #define RENDER_OBJECT_CHUNK_RADIUS 1 -#endif - -#ifndef RENDER_MONSTER_CHUNK_RADIUS - #define RENDER_MONSTER_CHUNK_RADIUS 3 -#endif - -#ifndef RENDER_NPC_CHUNK_RADIUS - #define RENDER_NPC_CHUNK_RADIUS 3 -#endif - -#ifndef RENDER_PAYER_CHUNK_RADIUS - #define RENDER_PAYER_CHUNK_RADIUS 3 -#endif - -#define MAX_ACTIVE_EXTENSIONS 15 - -// @todo remove default values because we will load them during startup -struct SSettings { - char path[MAX_PATH]; - bool is_changed = false; - byte simd_version; - - char network_hostname[64]; - uint16 network_port; - - byte distance_terrain = RENDER_CHUNK_RADIUS; - byte distance_terrain_secondary = RENDER_BLOCK_OBJECT_CHUNK_RADIUS; - byte distance_terrain_tertiary = RENDER_INTERACTIVE_CHUNK_RADIUS; - byte distance_models = RENDER_OBJECT_CHUNK_RADIUS; - byte distance_monster = RENDER_MONSTER_CHUNK_RADIUS; - byte distance_npc = RENDER_NPC_CHUNK_RADIUS; - byte distance_player = RENDER_PAYER_CHUNK_RADIUS; - - uint32 cache_player = 8192; // = max active players on a server - uint32 cache_monster = 8192; - uint32 cache_npc = 8192; - uint32 cache_guild = 128; - uint32 cache_message = 1024; - - uint32 interpolation_buffer; - - bool is_auction_house_enabled = true; - bool is_direct_trading_enabled = true; - - // @todo add more server settings for tournaments, tournament modes - // @todo add more server settings for raids and dungeons - // @todo add more settings for pvp -}; - -// Player settings that the server needs to know about -struct PSettings { - byte render_distance_models = RENDER_OBJECT_CHUNK_RADIUS; - byte render_distance_monster = RENDER_MONSTER_CHUNK_RADIUS; - byte render_distance_npc = RENDER_NPC_CHUNK_RADIUS; - byte render_distance_player = RENDER_PAYER_CHUNK_RADIUS; - - byte chat_status = CHAT_STATUS_OFFLINE; - bool allow_invites = true; -}; - -// @performance Make sure the settings used in the update and render loop are close to each other to ensure they can be loaded in one cache line -struct CSettings { - // Evaluated during startup - char path[MAX_PATH]; - bool is_changed = false; +struct SIMDSettings { byte simd_version; int32 simd_step_size; bool supports_abm; - - // Network data - char network_hostname[64]; - uint16 network_port; - - byte gpu_api = SETTING_TYPE_GPU_API_NONE; - byte gpu_type = SETTING_TYPE_GPU_MEDIUM; - byte gpu_fps = SETTING_TYPE_UNLIMITED; - byte gpu_memory; // how much vram are we using on the gpu - byte system_ram; // how much ram are we using - byte system_threads; // how much ram are we using - byte system_cache; // how much hard drive cache do we want to allow? (oldest files will be deleted) - - f32 gpu_aspect_ratio; - byte gpu_brightness; - byte gpu_contrast; - byte gpu_gamma; - f32 gpu_fov; - int8 gpu_sync; - - byte gpu_render_distance_terrain = 10; - byte gpu_render_distance_terrain_secondary = 10; - byte gpu_render_distance_terrain_tertiary = 1; - byte gpu_render_distance_models = 1; - byte gpu_render_distance_monster = 3; - byte gpu_render_distance_npc = 3; - byte gpu_render_distance_player = 3; - - int32 gpu_render_count_mob = 1000; - - uint32 player_cache = 512; - uint32 monster_cache = 128; - uint32 npc_cache = 128; - uint32 guild_cache = 128; - uint32 message_cache = 64; - - byte gpu_animation_quality; - byte gpu_attack_effect_quality; - byte gpu_shadow_quality; - byte gpu_terrain_quality; - byte gpu_water_quality; - byte gpu_grass_density; - byte gpu_model_quality; - byte gpu_texture_quality; - byte gpu_foliage_distance; - byte gpu_detail_level; - byte gpu_reflection_quality; - byte gpu_refraction_quality; - byte gpu_caustics_quality; - byte gpu_footprint_quality; // mostly used for snow, sand mud - bool gpu_screen_effects; // e.g. water droplets/dust/freezing on screen - - bool gpu_raytracing = false; - bool gpu_lense_effect = true; - bool gpu_fog_effect = true; - bool gpu_particles_environment = true; - bool gpu_particles_players = true; - bool gpu_particles_monster = true; - bool gpu_particles_ui = true; - bool gpu_particles_skills = true; - bool gpu_particles_weapons = true; - - byte gpu_shadow_type = SETTING_TYPE_DISABLED; // none, baked, shadow mapping, point shadow, ray tracing - byte gpu_light_ssao = SETTING_TYPE_DISABLED; - byte gpu_light_bloom = SETTING_TYPE_DISABLED; - - byte gpu_reflection_blur = SETTING_TYPE_DISABLED; - byte gpu_motion_blur = SETTING_TYPE_DISABLED; - byte gpu_blur = SETTING_TYPE_DISABLED; - AntiAliasingType gpu_anti_aliasing; - int8 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; - bool gpu_parallax_mapping = true; - - bool gpu_depth_of_field = true; - bool gpu_chromatic_aberration = true; - bool gpu_vignetting = true; - bool gpu_light_shafts = true; - - f32 audio_volume_master; - f32 audio_volume_game; - f32 audio_volume_environment; - f32 audio_volume_music; - f32 audio_volume_speech; - - uint16 game_window1_dim[2]; - uint16 game_window1_pos[2]; - byte game_window1_mode = SETTING_TYPE_WINDOW_MODE_FULLSCREEN; - - byte game_view = SETTING_TYPE_PERSPECTIVE_FIRST; - byte game_camera_zoom; - bool game_camera_shake = false; - - // General game UI - byte game_crosshair; - - uint32 game_interpolation_buffer; - - bool game_player_chat = false; // bubble above player - byte game_chat_status = CHAT_STATUS_OFFLINE; - - // Extra windows - byte game_window2_type = SETTING_TYPE_DISABLED; - bool game_window2_visible = false; - uint32 game_window2_dim[2] = {1024, 768}; - uint32 game_window2_pos[2]; - - byte game_window3_type = SETTING_TYPE_DISABLED; - bool game_window3_visible = false; - uint32 game_window3_dim[2] = {1024, 768}; - uint32 game_window3_pos[2]; - - byte game_window4_type = SETTING_TYPE_DISABLED; - bool game_window4_visible = false; - uint32 game_window4_dim[2] = {1024, 768}; - uint32 game_window4_pos[2]; - - byte game_window5_type = SETTING_TYPE_DISABLED; - bool game_window5_visible = false; - uint32 game_window5_dim[2] = {1024, 768}; - uint32 game_window5_pos[2]; - - // @todo Consider to allow settings for chat tabs - // define which messags go to which tab - // define custom chat tabs - - // UI settings - // Themes - char game_language[2]; - - char game_theme[32]; - - v4_f32 game_ui_dim[50]; - - // @todo replace settings below with bit flag - // UI - uint64 ui_visibility_flags = 0; - uint64 game_visibility_flags = 0; - uint64 debug_visibility_flags = 0; - - // HUD - bool game_hud_animated; - - bool game_show_buffs = false; - - byte game_minion_visibility_self = 128; - byte game_minion_visibility_player = 128; - - bool game_minimap_show_merchants = false; - bool game_minimap_show_quest = false; - bool game_minimap_show_dungeons = false; - bool game_minimap_show_names = false; - - bool game_map_show_merchants = false; - bool game_map_show_quest = false; - bool game_map_show_dungeons = false; - bool game_map_show_names = false; - - // Mounts - uint32 game_default_mount = 0; - - // Game behavior - bool game_error_audio = true; - bool game_error_text = true; - bool game_block_trade = false; - bool game_block_group_invite = false; - bool game_block_guild_invite = false; - bool game_block_chat_invite = false; - bool game_block_friend_invite = false; - bool game_automatically_track_newest_quest = false; - - byte game_interact_radius = 1; - - // Game pad settings - byte input_device_types = SETTING_INPUT_DEVICE_TYPE_MOUSE_KEYBOARD; - byte input_controller_handler = CONTROLLER_HANDLER_TYPE_AUTO; - byte stick_left_deadzone = 0; - byte stick_right_deadzone = 0; - - f32 input_camera_speed; - f32 input_look_sensitivity; - bool input_invert_mouse = false; - - int32 active_module_count; - Module* active_modules; - - // Hotkey settings - // @todo hotkey combination e.g. alt+1 - byte hotkeys_movement_up = 0x57; // W - byte hotkeys_movement_down = 0x53; // S - byte hotkeys_movement_left = 0x41; // A - byte hotkeys_movement_right = 0x44; // D - - byte hotkeys_cancel_action = 0x44; // X - - byte hotkeys_skill_tab_1 = 0x70; // F1 - byte hotkeys_skill_tab_2 = 0x71; // F2 - byte hotkeys_skill_tab_3 = 0x72; // F3 - - byte hotkeys_skill_1 = 0x31; // 1 - byte hotkeys_skill_2 = 0x32; // 2 - byte hotkeys_skill_3 = 0x33; // 3 - byte hotkeys_skill_4 = 0x34; // 4 - byte hotkeys_skill_5 = 0x35; // 5 - byte hotkeys_skill_6 = 0x36; // 6 - byte hotkeys_skill_7 = 0x37; // 7 - byte hotkeys_skill_8 = 0x38; // 8 - byte hotkeys_skill_9 = 0x39; // 9 - byte hotkeys_skill_10 = 0x30; // 0 - - byte hotkeys_interact = 45; // E - byte hotkeys_jump = 0x20; // SPACE - - byte hotkeys_dodge = 0x20; // SPACE - byte hotkeys_crouch = 0x14; // CAP - byte hotkeys_walk = 0x11; // CTRL (switches to walking speed, one click only) - byte hotkeys_emote = 0x12; // LEFT_ALT - byte hotkeys_vertical_up = 0x14; // CAPS LOCK - byte hotkeys_vertical_down = 0x10; // SHIFT - - byte hotkeys_view_next = 0x09; // TAB - byte hotkeys_view_prv = 0x14; // CAPS LOCK - byte hotkeys_compare_item = 0x11; // CTRL - - byte hotkeys_inventory = 0x49; // I - byte hotkeys_character = 0x43; // C - byte hotkeys_skills = 0x53; // S - byte hotkeys_map = 0x4D; // M - byte hotkeys_quest = 0x51; // Q - byte hotkeys_attack_move = 0x52; // R - byte hotkeys_force_move = 0x46; // F - byte hotkeys_courser_move = 0x58; // X (move to where courser is) - - byte hotkeys_chat = 0x0D; // ENTER - byte hotkeys_toggle_hud = 0x48; // H - byte hotkeys_close_active_window = 0x48; // H - byte hotkeys_toggle_all_windows = 0x48; // H - - byte hotkeys_zoom_in = 0x21; // Page up (@todo make mouse scroll up) - byte hotkeys_zoom_out = 0x22; // page down (@todo make mouse scroll down) - byte hotkeys_camera_look = 0x00; // @todo make right mouse hold - byte hotkeys_camera_fly_mode = 0x00; // @todo make right mouse hold - - byte hotkeys_menu = 0x1B; // ESC - - byte hotkeys_marker_1 = 0x31; - byte hotkeys_marker_2 = 0x32; - byte hotkeys_marker_3 = 0x33; - byte hotkeys_marker_4 = 0x34; - byte hotkeys_marker_5 = 0x35; - byte hotkeys_marker_6 = 0x36; - byte hotkeys_ping = 0x37; - - // Camera settings/positions - // Makes it easy to switch to customizable camera positions - byte hotkeys_camera_1 = 0x0; - byte hotkeys_camera_2 = 0x0; - byte hotkeys_camera_3 = 0x0; - - char modules[MAX_ACTIVE_EXTENSIONS * 32]; }; -void load_settings(CSettings* __restrict client_settings, char* data) -{ - char* pos = data; - char* name; +struct NetworkSettings { + in6_addr network_hostname; + uint16 network_port; +}; - while (*pos != '\0') { - // Skip all whitespaces and new lines - int32 skip; - while ((skip = (int32) is_whitespace(*pos)) || (skip = is_eol(pos))) { - pos += skip; - } +struct ServerInfoSettings { + char server_name[24]; + in6_addr server_hostname; + uint16 server_port; +}; - // Skip comment - if (*pos == '/' && pos[1] == '/') { - while (*pos != '\n' && *pos != '\0') { - ++pos; - } - - continue; - } - - // Get name - name = pos; - while (!is_eol(pos) && *pos != '\0' && !is_whitespace(*pos) && *pos != '[') { - ++pos; - } - - // Move to value - while (is_whitespace(*pos)) { - ++pos; - } - - // Is there a value? - if (is_eol(pos) || *pos == '\0') { - continue; - } - - // Parse value - // We use grouping for faster handling - if (strncmp(name, "gpu", sizeof("gpu") - 1) == 0) { - name += sizeof("gpu") - 1; - - if (strncmp(name, "_ambient_occlusion", sizeof("_ambient_occlusion") - 1) == 0) { - } else if (strncmp(name, "_animation_quality", sizeof("_animation_quality") - 1) == 0) { - } else if (strncmp(name, "_anti_aliasing_detail", sizeof("_anti_aliasing_detail") - 1) == 0) { - client_settings->gpu_anti_aliasing_detail = (int8) atoi(pos); - } else if (strncmp(name, "_anti_aliasing", sizeof("_anti_aliasing") - 1) == 0) { - client_settings->gpu_anti_aliasing = (AntiAliasingType) atoi(pos); - } else if (strncmp(name, "_api", sizeof("_api") - 1) == 0) { - } else if (strncmp(name, "_aspect_ratio", sizeof("_aspect_ratio") - 1) == 0) { - 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) { - } else if (strncmp(name, "_chromatic_aberration", sizeof("_chromatic_aberration") - 1) == 0) { - } else if (strncmp(name, "_contrast", sizeof("_contrast") - 1) == 0) { - } else if (strncmp(name, "_depth_of_field", sizeof("_depth_of_field") - 1) == 0) { - } else if (strncmp(name, "_detail_level", sizeof("_detail_level") - 1) == 0) { - } else if (strncmp(name, "_fog_effect", sizeof("_fog_effect") - 1) == 0) { - } else if (strncmp(name, "_foliage_distance", sizeof("_foliage_distance") - 1) == 0) { - } else if (strncmp(name, "_footprint_quality", sizeof("_footprint_quality") - 1) == 0) { - } else if (strncmp(name, "_fov", sizeof("_fov") - 1) == 0) { - client_settings->gpu_fov = (f32) atof(pos); - } else if (strncmp(name, "_fps", sizeof("_fps") - 1) == 0) { - } else if (strncmp(name, "_gamma_correction", sizeof("_gamma_correction") - 1) == 0) { - } else if (strncmp(name, "_gamma", sizeof("_gamma") - 1) == 0) { - } else if (strncmp(name, "_grass_density", sizeof("_grass_density") - 1) == 0) { - } else if (strncmp(name, "_lense_effect", sizeof("_lense_effect") - 1) == 0) { - } else if (strncmp(name, "_light_bloom", sizeof("_light_bloom") - 1) == 0) { - } else if (strncmp(name, "_light_shafts", sizeof("_light_shafts") - 1) == 0) { - } else if (strncmp(name, "_light_ssao", sizeof("_light_ssao") - 1) == 0) { - } else if (strncmp(name, "_memory", sizeof("_memory") - 1) == 0) { - } else if (strncmp(name, "_model_quality", sizeof("_model_quality") - 1) == 0) { - } else if (strncmp(name, "_motion_blur", sizeof("_motion_blur") - 1) == 0) { - } else if (strncmp(name, "_normal_mapping", sizeof("_normal_mapping") - 1) == 0) { - } else if (strncmp(name, "_parallax_mapping", sizeof("_parallax_mapping") - 1) == 0) { - } else if (strncmp(name, "_particles_environment", sizeof("_particles_environment") - 1) == 0) { - } else if (strncmp(name, "_particles_monster", sizeof("_particles_monster") - 1) == 0) { - } else if (strncmp(name, "_particles_players", sizeof("_particles_players") - 1) == 0) { - } else if (strncmp(name, "_particles_skills", sizeof("_particles_skills") - 1) == 0) { - } else if (strncmp(name, "_particles_ui", sizeof("_particles_ui") - 1) == 0) { - } else if (strncmp(name, "_particles_weapons", sizeof("_particles_weapons") - 1) == 0) { - } else if (strncmp(name, "_raytracing", sizeof("_raytracing") - 1) == 0) { - } else if (strncmp(name, "_reflection_blur", sizeof("_reflection_blur") - 1) == 0) { - } else if (strncmp(name, "_reflection_quality", sizeof("_reflection_quality") - 1) == 0) { - } else if (strncmp(name, "_refraction_quality", sizeof("_refraction_quality") - 1) == 0) { - } else if (strncmp(name, "_render_count_mob", sizeof("_render_count_mob") - 1) == 0) { - } else if (strncmp(name, "_render_distance_models", sizeof("_render_distance_models") - 1) == 0) { - } else if (strncmp(name, "_render_distance_monster", sizeof("_render_distance_monster") - 1) == 0) { - } else if (strncmp(name, "_render_distance_npc", sizeof("_render_distance_npc") - 1) == 0) { - } else if (strncmp(name, "_render_distance_player", sizeof("_render_distance_player") - 1) == 0) { - } else if (strncmp(name, "_render_distance_terrain_secondary", sizeof("_render_distance_terrain_secondary") - 1) == 0) { - } else if (strncmp(name, "_render_distance_terrain_tertiary", sizeof("_render_distance_terrain_tertiary") - 1) == 0) { - } else if (strncmp(name, "_render_distance_terrain", sizeof("_render_distance_terrain") - 1) == 0) { - } else if (strncmp(name, "_screen_effects", sizeof("_screen_effects") - 1) == 0) { - } else if (strncmp(name, "_shadow_quality", sizeof("_shadow_quality") - 1) == 0) { - } else if (strncmp(name, "_shadow_type", sizeof("_shadow_type") - 1) == 0) { - } else if (strncmp(name, "_sharpening", sizeof("_sharpening") - 1) == 0) { - } else if (strncmp(name, "_sync", sizeof("_sync") - 1) == 0) { - client_settings->gpu_sync = (int8) atoi(pos); - } else if (strncmp(name, "_terrain_quality", sizeof("_terrain_quality") - 1) == 0) { - } else if (strncmp(name, "_texture_quality", sizeof("_texture_quality") - 1) == 0) { - } else if (strncmp(name, "_type", sizeof("_type") - 1) == 0) { - } else if (strncmp(name, "_vignetting", sizeof("_vignetting") - 1) == 0) { - } else if (strncmp(name, "_water_quality", sizeof("_water_quality") - 1) == 0) { - } - } else if (strncmp(name, "game", sizeof("game") - 1) == 0) { - name += sizeof("game") - 1; - - if (strncmp(name, "_automatically_track_newest_quest", sizeof("_automatically_track_newest_quest") - 1) == 0) { - } else if (strncmp(name, "_block_chat_invite", sizeof("_block_chat_invite") - 1) == 0) { - } else if (strncmp(name, "_block_friend_invite", sizeof("_block_friend_invite") - 1) == 0) { - } else if (strncmp(name, "_block_group_invite", sizeof("_block_group_invite") - 1) == 0) { - } else if (strncmp(name, "_block_guild_invite", sizeof("_block_guild_invite") - 1) == 0) { - } else if (strncmp(name, "_block_trade", sizeof("_block_trade") - 1) == 0) { - } else if (strncmp(name, "_camera_shake", sizeof("_camera_shake") - 1) == 0) { - } else if (strncmp(name, "_camera_zoom", sizeof("_camera_zoom") - 1) == 0) { - } else if (strncmp(name, "_chat_status", sizeof("_chat_status") - 1) == 0) { - } else if (strncmp(name, "_crosshair", sizeof("_crosshair") - 1) == 0) { - } else if (strncmp(name, "_default_mount", sizeof("_default_mount") - 1) == 0) { - } else if (strncmp(name, "_hud_animated", sizeof("_hud_animated") - 1) == 0) { - } else if (strncmp(name, "_interact_radius", sizeof("_interact_radius") - 1) == 0) { - } else if (strncmp(name, "_language", sizeof("_language") - 1) == 0) { - } else if (strncmp(name, "_map_show_dungeons", sizeof("_map_show_dungeons") - 1) == 0) { - } else if (strncmp(name, "_map_show_merchants", sizeof("_map_show_merchants") - 1) == 0) { - } else if (strncmp(name, "_map_show_names", sizeof("_map_show_names") - 1) == 0) { - } else if (strncmp(name, "_map_show_quest", sizeof("_map_show_quest") - 1) == 0) { - } else if (strncmp(name, "_minimap_show_dungeons", sizeof("_minimap_show_dungeons") - 1) == 0) { - } else if (strncmp(name, "_minimap_show_merchants", sizeof("_minimap_show_merchants") - 1) == 0) { - } else if (strncmp(name, "_minimap_show_names", sizeof("_minimap_show_names") - 1) == 0) { - } else if (strncmp(name, "_minimap_show_quest", sizeof("_minimap_show_quest") - 1) == 0) { - } else if (strncmp(name, "_minion_visibility_player", sizeof("_minion_visibility_player") - 1) == 0) { - } else if (strncmp(name, "_minion_visibility_self", sizeof("_minion_visibility_self") - 1) == 0) { - } else if (strncmp(name, "_player_chat", sizeof("_player_chat") - 1) == 0) { - } else if (strncmp(name, "_show_buffs", sizeof("_show_buffs") - 1) == 0) { - } else if (strncmp(name, "_show_cooldown_times", sizeof("_show_cooldown_times") - 1) == 0) { - } else if (strncmp(name, "_show_dmg_numbers", sizeof("_show_dmg_numbers") - 1) == 0) { - } else if (strncmp(name, "_show_dodge", sizeof("_show_dodge") - 1) == 0) { - } else if (strncmp(name, "_show_effect_gains", sizeof("_show_effect_gains") - 1) == 0) { - } else if (strncmp(name, "_show_health_bar_monster", sizeof("_show_health_bar_monster") - 1) == 0) { - } else if (strncmp(name, "_show_health_bar_player", sizeof("_show_health_bar_player") - 1) == 0) { - } else if (strncmp(name, "_show_health_bar_self", sizeof("_show_health_bar_self") - 1) == 0) { - } else if (strncmp(name, "_show_health_numbers", sizeof("_show_health_numbers") - 1) == 0) { - } else if (strncmp(name, "_show_name_monster", sizeof("_show_name_monster") - 1) == 0) { - } else if (strncmp(name, "_show_name_npc", sizeof("_show_name_npc") - 1) == 0) { - } else if (strncmp(name, "_show_name_player", sizeof("_show_name_player") - 1) == 0) { - } else if (strncmp(name, "_show_name_self", sizeof("_show_name_self") - 1) == 0) { - } else if (strncmp(name, "_show_resource_numbers", sizeof("_show_resource_numbers") - 1) == 0) { - } else if (strncmp(name, "_show_subtitles", sizeof("_show_subtitles") - 1) == 0) { - } 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, "_debug_visibility_flags", sizeof("_debug_visibility_flags") - 1) == 0) { - client_settings->debug_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) { - client_settings->game_window1_dim[0] = (uint16) strtoul(pos, &pos, 10); ++pos; - client_settings->game_window1_dim[1] = (uint16) atoi(pos); - } else if (strncmp(name, "_window1_pos", sizeof("_window1_pos") - 1) == 0) { - } else if (strncmp(name, "_window2_dim", sizeof("_window2_dim") - 1) == 0) { - } else if (strncmp(name, "_window2_pos", sizeof("_window2_pos") - 1) == 0) { - } else if (strncmp(name, "_window3_dim", sizeof("_window3_dim") - 1) == 0) { - } else if (strncmp(name, "_window3_pos", sizeof("_window3_pos") - 1) == 0) { - } else if (strncmp(name, "_window4_dim", sizeof("_window4_dim") - 1) == 0) { - } else if (strncmp(name, "_window4_pos", sizeof("_window4_pos") - 1) == 0) { - } else if (strncmp(name, "_window5_dim", sizeof("_window5_dim") - 1) == 0) { - } else if (strncmp(name, "_window5_pos", sizeof("_window5_pos") - 1) == 0) { - } - } else if (strncmp(name, "hotkeys", sizeof("hotkeys") - 1) == 0) { - name += sizeof("hotkeys") - 1; - - if (strncmp(name, "_camera_fly_mode", sizeof("_camera_fly_mode") - 1) == 0) { - } else if (strncmp(name, "_camera_look", sizeof("_camera_look") - 1) == 0) { - } else if (strncmp(name, "_zoom_in", sizeof("_zoom_in") - 1) == 0) { - } else if (strncmp(name, "_zoom_out", sizeof("_zoom_out") - 1) == 0) { - } else if (strncmp(name, "_attack_move", sizeof("_attack_move") - 1) == 0) { - } else if (strncmp(name, "_auction_house", sizeof("_auction_house") - 1) == 0) { - } else if (strncmp(name, "_bar_active_1", sizeof("_bar_active_1") - 1) == 0) { - } else if (strncmp(name, "_bar_active_2", sizeof("_bar_active_2") - 1) == 0) { - } else if (strncmp(name, "_bar_active_3", sizeof("_bar_active_3") - 1) == 0) { - } else if (strncmp(name, "_bar_active_4", sizeof("_bar_active_4") - 1) == 0) { - } else if (strncmp(name, "_bar_active_5", sizeof("_bar_active_5") - 1) == 0) { - } else if (strncmp(name, "_bar_global_1", sizeof("_bar_global_1") - 1) == 0) { - } else if (strncmp(name, "_bar_global_10", sizeof("_bar_global_10") - 1) == 0) { - } else if (strncmp(name, "_bar_global_11", sizeof("_bar_global_11") - 1) == 0) { - } else if (strncmp(name, "_bar_global_12", sizeof("_bar_global_12") - 1) == 0) { - } else if (strncmp(name, "_bar_global_13", sizeof("_bar_global_13") - 1) == 0) { - } else if (strncmp(name, "_bar_global_14", sizeof("_bar_global_14") - 1) == 0) { - } else if (strncmp(name, "_bar_global_15", sizeof("_bar_global_15") - 1) == 0) { - } else if (strncmp(name, "_bar_global_16", sizeof("_bar_global_16") - 1) == 0) { - } else if (strncmp(name, "_bar_global_17", sizeof("_bar_global_17") - 1) == 0) { - } else if (strncmp(name, "_bar_global_18", sizeof("_bar_global_18") - 1) == 0) { - } else if (strncmp(name, "_bar_global_19", sizeof("_bar_global_19") - 1) == 0) { - } else if (strncmp(name, "_bar_global_2", sizeof("_bar_global_2") - 1) == 0) { - } else if (strncmp(name, "_bar_global_20", sizeof("_bar_global_20") - 1) == 0) { - } else if (strncmp(name, "_bar_global_21", sizeof("_bar_global_21") - 1) == 0) { - } else if (strncmp(name, "_bar_global_22", sizeof("_bar_global_22") - 1) == 0) { - } else if (strncmp(name, "_bar_global_23", sizeof("_bar_global_23") - 1) == 0) { - } else if (strncmp(name, "_bar_global_24", sizeof("_bar_global_24") - 1) == 0) { - } else if (strncmp(name, "_bar_global_25", sizeof("_bar_global_25") - 1) == 0) { - } else if (strncmp(name, "_bar_global_3", sizeof("_bar_global_3") - 1) == 0) { - } else if (strncmp(name, "_bar_global_4", sizeof("_bar_global_4") - 1) == 0) { - } else if (strncmp(name, "_bar_global_5", sizeof("_bar_global_5") - 1) == 0) { - } else if (strncmp(name, "_bar_global_6", sizeof("_bar_global_6") - 1) == 0) { - } else if (strncmp(name, "_bar_global_7", sizeof("_bar_global_7") - 1) == 0) { - } else if (strncmp(name, "_bar_global_8", sizeof("_bar_global_8") - 1) == 0) { - } else if (strncmp(name, "_bar_global_9", sizeof("_bar_global_9") - 1) == 0) { - } else if (strncmp(name, "_bar_tab_1", sizeof("_bar_tab_1") - 1) == 0) { - } else if (strncmp(name, "_bar_tab_2", sizeof("_bar_tab_2") - 1) == 0) { - } else if (strncmp(name, "_bar_tab_3", sizeof("_bar_tab_3") - 1) == 0) { - } else if (strncmp(name, "_bar_tab_4", sizeof("_bar_tab_4") - 1) == 0) { - } else if (strncmp(name, "_bar_tab_5", sizeof("_bar_tab_5") - 1) == 0) { - } else if (strncmp(name, "_camera_1", sizeof("_camera_1") - 1) == 0) { - } else if (strncmp(name, "_camera_2", sizeof("_camera_2") - 1) == 0) { - } else if (strncmp(name, "_camera_3", sizeof("_camera_3") - 1) == 0) { - } else if (strncmp(name, "_cancel_action", sizeof("_cancel_action") - 1) == 0) { - } else if (strncmp(name, "_character", sizeof("_character") - 1) == 0) { - } else if (strncmp(name, "_chat_send", sizeof("_chat_send") - 1) == 0) { - } else if (strncmp(name, "_close_active_window", sizeof("_close_active_window") - 1) == 0) { - } else if (strncmp(name, "_compare_item", sizeof("_compare_item") - 1) == 0) { - } else if (strncmp(name, "_courser_move", sizeof("_courser_move") - 1) == 0) { - } else if (strncmp(name, "_crouch", sizeof("_crouch") - 1) == 0) { - } else if (strncmp(name, "_dodge", sizeof("_dodge") - 1) == 0) { - } else if (strncmp(name, "_element_down", sizeof("_element_down") - 1) == 0) { - } else if (strncmp(name, "_element_left", sizeof("_element_left") - 1) == 0) { - } else if (strncmp(name, "_element_next", sizeof("_element_next") - 1) == 0) { - } else if (strncmp(name, "_element_prev", sizeof("_element_prev") - 1) == 0) { - } else if (strncmp(name, "_element_right", sizeof("_element_right") - 1) == 0) { - } else if (strncmp(name, "_element_up", sizeof("_element_up") - 1) == 0) { - } else if (strncmp(name, "_emote", sizeof("_emote") - 1) == 0) { - } else if (strncmp(name, "_force_move", sizeof("_force_move") - 1) == 0) { - } else if (strncmp(name, "_guild", sizeof("_guild") - 1) == 0) { - } else if (strncmp(name, "_interact", sizeof("_interact") - 1) == 0) { - } else if (strncmp(name, "_inventory", sizeof("_inventory") - 1) == 0) { - } else if (strncmp(name, "_jump", sizeof("_jump") - 1) == 0) { - } else if (strncmp(name, "_map", sizeof("_map") - 1) == 0) { - } else if (strncmp(name, "_marker_1", sizeof("_marker_1") - 1) == 0) { - } else if (strncmp(name, "_marker_2", sizeof("_marker_2") - 1) == 0) { - } else if (strncmp(name, "_marker_3", sizeof("_marker_3") - 1) == 0) { - } else if (strncmp(name, "_marker_4", sizeof("_marker_4") - 1) == 0) { - } else if (strncmp(name, "_marker_5", sizeof("_marker_5") - 1) == 0) { - } else if (strncmp(name, "_marker_6", sizeof("_marker_6") - 1) == 0) { - } else if (strncmp(name, "_menu", sizeof("_menu") - 1) == 0) { - } else if (strncmp(name, "_movement_down", sizeof("_movement_down") - 1) == 0) { - } else if (strncmp(name, "_movement_left", sizeof("_movement_left") - 1) == 0) { - } else if (strncmp(name, "_movement_pitch_down", sizeof("_movement_pitch_down") - 1) == 0) { - } else if (strncmp(name, "_movement_pitch_up", sizeof("_movement_pitch_up") - 1) == 0) { - } else if (strncmp(name, "_movement_right", sizeof("_movement_right") - 1) == 0) { - } else if (strncmp(name, "_movement_roll_left", sizeof("_movement_roll_left") - 1) == 0) { - } else if (strncmp(name, "_movement_roll_right", sizeof("_movement_roll_right") - 1) == 0) { - } else if (strncmp(name, "_movement_up", sizeof("_movement_up") - 1) == 0) { - } else if (strncmp(name, "_movement_vertical_down", sizeof("_movement_vertical_down") - 1) == 0) { - } else if (strncmp(name, "_movement_vertical_up", sizeof("_movement_vertical_up") - 1) == 0) { - } else if (strncmp(name, "_movement_yaw_left", sizeof("_movement_yaw_left") - 1) == 0) { - } else if (strncmp(name, "_movement_yaw_right", sizeof("_movement_yaw_right") - 1) == 0) { - } else if (strncmp(name, "_ping", sizeof("_ping") - 1) == 0) { - } else if (strncmp(name, "_quest", sizeof("_quest") - 1) == 0) { - } else if (strncmp(name, "_skills", sizeof("_skills") - 1) == 0) { - } else if (strncmp(name, "_sneak", sizeof("_sneak") - 1) == 0) { - } else if (strncmp(name, "_toggle_all_windows", sizeof("_toggle_all_windows") - 1) == 0) { - } else if (strncmp(name, "_toggle_hud", sizeof("_toggle_hud") - 1) == 0) { - } else if (strncmp(name, "_view_next", sizeof("_view_next") - 1) == 0) { - } else if (strncmp(name, "_view_prv", sizeof("_view_prv") - 1) == 0) { - } else if (strncmp(name, "_walk", sizeof("_walk") - 1) == 0) { - } - } else if (strncmp(name, "input", sizeof("input") - 1) == 0) { - name += sizeof("input") - 1; - - if (strncmp(name, "_camera_speed", sizeof("_camera_speed") - 1) == 0) { - client_settings->input_camera_speed = (f32) atof(pos); - } else if (strncmp(name, "_controller1_gyro_x_deadzone", sizeof("_controller1_gyro_x_deadzone") - 1) == 0) { - } else if (strncmp(name, "_controller1_gyro_x_zero", sizeof("_controller1_gyro_x_zero") - 1) == 0) { - } else if (strncmp(name, "_controller1_gyro_y_deadzone", sizeof("_controller1_gyro_y_deadzone") - 1) == 0) { - } else if (strncmp(name, "_controller1_gyro_y_zero", sizeof("_controller1_gyro_y_zero") - 1) == 0) { - } else if (strncmp(name, "_controller1_gyro_z_deadzone", sizeof("_controller1_gyro_z_deadzone") - 1) == 0) { - } else if (strncmp(name, "_controller1_gyro_z_zero", sizeof("_controller1_gyro_z_zero") - 1) == 0) { - } else if (strncmp(name, "_controller1_stick_left_deadzone", sizeof("_controller1_stick_left_deadzone") - 1) == 0) { - } else if (strncmp(name, "_controller1_stick_right_deadzone", sizeof("_controller1_stick_right_deadzone") - 1) == 0) { - } else if (strncmp(name, "_controller1_trigger_left_deadzone", sizeof("_controller1_trigger_left_deadzone") - 1) == 0) { - } else if (strncmp(name, "_controller1_trigger_right_deadzone", sizeof("_controller1_trigger_right_deadzone") - 1) == 0) { - } else if (strncmp(name, "_device", sizeof("_device") - 1) == 0) { - } else if (strncmp(name, "_invert_mouse", sizeof("_invert_mouse") - 1) == 0) { - } else if (strncmp(name, "_look_sensitivity", sizeof("_look_sensitivity") - 1) == 0) { - client_settings->input_look_sensitivity = (f32) atof(pos); - } - } else if (strncmp(name, "cache", sizeof("cache") - 1) == 0) { - name += sizeof("cache") - 1; - - if (strncmp(name, "_chat", sizeof("_chat") - 1) == 0) { - } else if (strncmp(name, "_guild", sizeof("_guild") - 1) == 0) { - } else if (strncmp(name, "_log", sizeof("_log") - 1) == 0) { - } else if (strncmp(name, "_monster", sizeof("_monster") - 1) == 0) { - } else if (strncmp(name, "_npc", sizeof("_npc") - 1) == 0) { - } else if (strncmp(name, "_player", sizeof("_player") - 1) == 0) { - } - } else if (strncmp(name, "audio", sizeof("audio") - 1) == 0) { - name += sizeof("audio") - 1; - - if (strncmp(name, "_volume_environment", sizeof("_volume_environment") - 1) == 0) { - } else if (strncmp(name, "_volume_game", sizeof("_volume_game") - 1) == 0) { - } else if (strncmp(name, "_volume_master", sizeof("_volume_master") - 1) == 0) { - client_settings->audio_volume_master = (f32) atof(pos); - } else if (strncmp(name, "_volume_music", sizeof("_volume_music") - 1) == 0) { - } else if (strncmp(name, "_volume_speech", sizeof("_volume_speech") - 1) == 0) { - } - } else if (strncmp(name, "network", sizeof("network") - 1) == 0) { - name += sizeof("network") - 1; - - if (strncmp(name, "_hostname", sizeof("_hostname") - 1) == 0) { - } else if (strncmp(name, "_port", sizeof("_port") - 1) == 0) { - } - } else if (strncmp(name, "system", sizeof("system") - 1) == 0) { - name += sizeof("system") - 1; - - if (strncmp(name, "system_cache", sizeof("system_cache") - 1) == 0) { - } else if (strncmp(name, "system_memory", sizeof("system_memory") - 1) == 0) { - } else if (strncmp(name, "system_threads", sizeof("system_threads") - 1) == 0) { - } - } else { - if (strncmp(name, "extension_active", sizeof("extension_active") - 1) == 0) { - } - } - - // Go to end of line - while (*pos != '\n' && *pos != '\0') { - ++pos; - } - } -} - -#endif \ No newline at end of file +#endif diff --git a/models/settings/setting_types.h b/models/settings/setting_types.h index 51592d2..8cc8f22 100644 --- a/models/settings/setting_types.h +++ b/models/settings/setting_types.h @@ -19,11 +19,6 @@ #define SETTING_TYPE_PERSPECTIVE_THIRD 0x01 #define SETTING_TYPE_PERSPECTIVE_ISOMETRIC 0x02 -#define SETTING_TYPE_ANTI_ALIASING_TAA 0x01 -#define SETTING_TYPE_ANTI_ALIASING_SSAA 0x02 -#define SETTING_TYPE_ANTI_ALIASING_MSAA 0x03 -#define SETTING_TYPE_ANTI_ALIASING_FXAA 0x04 - #define SETTING_TYPE_SYNC_V 0x1 #define SETTING_TYPE_SYNC_ADAPTIVE 0x2 #define SETTING_TYPE_SYNC_FAST 0x3 @@ -67,10 +62,6 @@ #define SETTING_TYPE_WINDOW_MODE_WINDOWED_FULLSCREEN 0x01 #define SETTING_TYPE_WINDOW_MODE_WINDOWED 0x02 -#define SETTING_TYPE_SIMD_128 1 -#define SETTING_TYPE_SIMD_256 2 -#define SETTING_TYPE_SIMD_512 3 - #define SETTING_TYPE_DISABLED 0x00 #define SETTING_TYPE_UNLIMITED 0x00 diff --git a/network/Client.h b/network/Client.h deleted file mode 100644 index a658fcc..0000000 --- a/network/Client.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Jingga - * - * @copyright Jingga - * @license OMS License 2.0 - * @version 1.0.0 - * @link https://jingga.app - */ -#ifndef TOS_NETWORK_CLIENT_H -#define TOS_NETWORK_CLIENT_H - -#include -#include -#include - -#include "SocketConnection.h" -#include "../stdlib/Types.h" -#include "../memory/RingMemory.h" - -#if _WIN32 - #include - #include -#else - #include - #include - #include -#endif - -#include "NetworkOSWrapper.h" - -#ifndef MAX_STATIC_NETWORK_PACKET_SIZE - #define MAX_STATIC_NETWORK_PACKET_SIZE 8192 -#endif - -void socket_client_udb_connect(const char *hostname, SocketConnection* con) { - addrinfo hints, *res, *p; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_DGRAM; - - char port_str[6]; - snprintf(port_str, sizeof(port_str), "%d", con->port); - - if (getaddrinfo(hostname, port_str, &hints, &res) != 0) { - return; - } - - for (p = res; p != NULL; p = p->ai_next) { - if ((con->sd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { - continue; - } - - memcpy((void *) &con->server_addr, p->ai_addr, p->ai_addrlen); - break; - } - - freeaddrinfo(res); -} - -int socket_client_send(SOCKET sd, char *data, size_t length, sockaddr_in6 *server_addr, socklen_t addr_len) { - int sent_bytes = sendto(sd, data, (int) length, 0, (sockaddr *)server_addr, addr_len); - if (sent_bytes == -1) { - return -1; - } - - return 0; -} - -int socket_client_disconnect(SOCKET sd) -{ - close(sd); - - return 0; -} - -#endif \ No newline at end of file diff --git a/network/Server.h b/network/Server.h deleted file mode 100644 index 931624e..0000000 --- a/network/Server.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Jingga - * - * @copyright Jingga - * @license OMS License 2.0 - * @version 1.0.0 - * @link https://jingga.app - */ -#ifndef TOS_NETWORK_SERVER_H -#define TOS_NETWORK_SERVER_H - -#include -#include -#include - -#if _WIN32 - #include - #include -#else - #include - #include - #include - #include - #include - #include - #include -#endif - -#include "NetworkOSWrapper.h" -#include "SocketConnection.h" - -void socket_server_udb_create(const char *hostname, SocketConnection* con) { - con->sd = socket(AF_INET6, SOCK_DGRAM, 0); - - int flags; - if ((flags = fcntl(con->sd, F_GETFL, 0)) < 0) { - close(con->sd); - con->sd = 0; - } - - if (fcntl(con->sd, F_SETFL, flags | O_NONBLOCK) < 0) { - close(con->sd); - con->sd = 0; - } - - con->server_addr.sin6_family = AF_INET6; - con->server_addr.sin6_addr = in6addr_any; - con->server_addr.sin6_port = htons(con->port); - - if (bind(con->sd, (sockaddr *) &con->server_addr, sizeof(sockaddr_in6)) < 0) { - close(con->sd); - con->sd = 0; - } -} - -#endif \ No newline at end of file diff --git a/network/SocketConnection.h b/network/SocketConnection.h index 61bbc8d..31560eb 100644 --- a/network/SocketConnection.h +++ b/network/SocketConnection.h @@ -24,11 +24,10 @@ struct SocketConnection { #if _WIN32 SOCKET sd; #else - int sd; + int32 sd; #endif - sockaddr_in6 server_addr; - socklen_t addr_len; + sockaddr_in6 addr; uint16 port; }; diff --git a/network/packet/OMSPacket.h b/network/packet/OMSPacket.h new file mode 100644 index 0000000..24e5bac --- /dev/null +++ b/network/packet/OMSPacket.h @@ -0,0 +1,42 @@ +#ifndef TOS_NETWORK_PACKET_OMS_H +#define TOS_NETWORK_PACKET_OMS_H + +#include + +#include "../../stdlib/Types.h" +#include "../../compression/LZP.h" +#include "../../utils/EndianUtils.h" + +#include "PacketHeader.h" + +#if _WIN32 + #include +#elif __linux__ + #include + #include +#endif + +// WARNING: Since this requires admin priviledges, this can only be used for server-server communication +inline +uint16 packet_oms_create_raw( + byte* __restrict packet, + in6_addr* __restrict ipv6_src, in6_addr* __restrict ipv6_dst, + uint16 flow, + byte* __restrict data, uint16 data_length +) { + // create ipv6 header + HeaderIPv6Unpacked* ip6_header = (HeaderIPv6Unpacked *) packet; + ip6_header->ip6_flow = SWAP_ENDIAN_BIG((6 << 28) | (0 << 20) | flow); + ip6_header->ip6_plen = SWAP_ENDIAN_BIG(sizeof(UDPHeaderIPv6Unpacked) + data_length); + ip6_header->ip6_nxt = 255; + ip6_header->ip6_hops = 64; + memcpy(&ip6_header->ip6_src, ipv6_src, sizeof(in6_addr)); + memcpy(&ip6_header->ip6_dst, ipv6_dst, sizeof(in6_addr)); + + // create payload + memcpy(packet + sizeof(HeaderIPv6Unpacked), data, data_length); + + return sizeof(HeaderIPv6Unpacked) + data_length; +} + +#endif \ No newline at end of file diff --git a/network/packet/PacketCache.h b/network/packet/PacketCache.h index 2fc391c..9717100 100644 --- a/network/packet/PacketCache.h +++ b/network/packet/PacketCache.h @@ -10,7 +10,7 @@ #define TOS_NETWORK_PACKET_CACHE_H #include "../../memory/RingMemory.h" -#include "../../utils/BufferMemory.h" +#include "../../memory/BufferMemory.h" #if _WIN32 #include diff --git a/network/packet/PacketHeader.h b/network/packet/PacketHeader.h index f28ce02..c7f2635 100644 --- a/network/packet/PacketHeader.h +++ b/network/packet/PacketHeader.h @@ -5,56 +5,33 @@ #include "../../stdlib/Types.h" +#if _WIN32 + #include + #include + #include +#elif __linux__ + #include + #include +#endif + #define HEADER_IPV6_SIZE 40 // Size 40 bytes struct HeaderIPv6 { byte data[HEADER_IPV6_SIZE]; }; -// Size 42 bytes -struct HeaderIPv6Unpacked { - byte version; - byte traffic_class; - uint32 flow_label; +// Size 40 bytes +struct PACKED_STRUCT HeaderIPv6Unpacked { + uint32 ip6_flow; // also contains version and traffic class - uint16 length; - byte next_header; - byte hop_limit; + uint16 ip6_plen; + byte ip6_nxt; + byte ip6_hops; - byte src[16]; - byte dst[16]; + in6_addr ip6_src; + in6_addr ip6_dst; }; - -inline -void unpack_ipv6_header(const HeaderIPv6* ipv6, HeaderIPv6Unpacked* ipv6_unpacked) -{ - ipv6_unpacked->version = (ipv6->data[0] >> 4) & 0x0F; - ipv6_unpacked->traffic_class = ((ipv6->data[0] & 0x0F) << 4) | (ipv6->data[1] >> 4); - ipv6_unpacked->flow_label = ((ipv6->data[1] & 0x0F) << 16) | (ipv6->data[2] << 8) | ipv6->data[3]; - ipv6_unpacked->length = (ipv6->data[4] << 8) | ipv6->data[5]; - ipv6_unpacked->next_header = ipv6->data[6]; - ipv6_unpacked->hop_limit = ipv6->data[7]; - - memcpy(ipv6_unpacked->src, &ipv6->data[8], 16); - memcpy(ipv6_unpacked->dst, &ipv6->data[24], 16); -} - -inline -void pack_ipv6_header(const HeaderIPv6Unpacked* ipv6_unpacked, HeaderIPv6* ipv6) -{ - ipv6->data[0] = (ipv6_unpacked->version << 4) | (ipv6_unpacked->traffic_class >> 4); - ipv6->data[1] = (ipv6_unpacked->traffic_class << 4) | ((ipv6_unpacked->flow_label >> 16) & 0x0F); - ipv6->data[1] |= (ipv6_unpacked->flow_label >> 16) & 0x0F; - ipv6->data[2] = (ipv6_unpacked->flow_label >> 8) & 0xFF; - ipv6->data[3] = ipv6_unpacked->flow_label & 0xFF; - ipv6->data[4] = (ipv6_unpacked->length >> 8) & 0xFF; - ipv6->data[5] = ipv6_unpacked->length & 0xFF; - ipv6->data[6] = ipv6_unpacked->next_header; - ipv6->data[7] = ipv6_unpacked->hop_limit; - - memcpy(&ipv6->data[8], ipv6_unpacked->src, 16); - memcpy(&ipv6->data[24], ipv6_unpacked->dst, 16); -} +UNPACKED_STRUCT #define HEADER_UDP_SIZE 8 // Size 8 bytes @@ -63,41 +40,38 @@ struct UDPHeaderIPv6 { }; // Size 8 bytes -struct UDPHeaderIPv6Unpacked { - uint16 src_port; - uint16 dst_port; - uint16 length; - uint16 checksum; +struct PACKED_STRUCT UDPHeaderIPv6Unpacked { + uint16 source; + uint16 dest; + uint16 len; + uint16 check; }; +UNPACKED_STRUCT + +struct PACKED_STRUCT UDPPseudoHeaderIPv6 { + in6_addr src; + in6_addr dst; + uint32 length; + byte zero[3]; + byte next_header; +}; +UNPACKED_STRUCT inline -void unpack_udp_header_ipv6(const UDPHeaderIPv6* ipv6, UDPHeaderIPv6Unpacked* udp_unpacked) +void packet_create_destination_addr(sockaddr_in6* dest_addr, const char* ipv6, uint16 port) { - udp_unpacked->src_port = (ipv6->data[0] << 8) | ipv6->data[1]; - udp_unpacked->dst_port = (ipv6->data[2] << 8) | ipv6->data[3]; - udp_unpacked->length = (ipv6->data[4] << 8) | ipv6->data[5]; - udp_unpacked->checksum = (ipv6->data[6] << 8) | ipv6->data[7]; + memset(dest_addr, 0, sizeof(sockaddr_in6)); + dest_addr->sin6_family = AF_INET6; + dest_addr->sin6_port = SWAP_ENDIAN_BIG(port); + inet_pton(AF_INET6, ipv6, &dest_addr->sin6_addr); } inline -void pack_udp_header_ipv6(const UDPHeaderIPv6Unpacked* udp_unpacked, UDPHeaderIPv6* ipv6) +void packet_create_destination_addr(sockaddr_in6* dest_addr, in6_addr* ipv6, uint16 port) { - ipv6->data[0] = (udp_unpacked->src_port >> 8) & 0xFF; - ipv6->data[1] = udp_unpacked->src_port & 0xFF; - ipv6->data[2] = (udp_unpacked->dst_port >> 8) & 0xFF; - ipv6->data[3] = udp_unpacked->dst_port & 0xFF; - ipv6->data[4] = (udp_unpacked->length >> 8) & 0xFF; - ipv6->data[5] = udp_unpacked->length & 0xFF; - ipv6->data[6] = (udp_unpacked->checksum >> 8) & 0xFF; - ipv6->data[7] = udp_unpacked->checksum & 0xFF; + dest_addr->sin6_family = AF_INET6; + dest_addr->sin6_port = SWAP_ENDIAN_BIG(port); + memcpy(&dest_addr->sin6_addr, ipv6, sizeof(in6_addr)); } -// Size 7 bytes -struct CustomHeaderUnpacked { - uint16 msg_sequence; - uint16 msg_ack_sequence; - uint16 msg_ack; - byte msg_type; -}; - #endif \ No newline at end of file diff --git a/network/packet/UDPPacket.h b/network/packet/UDPPacket.h index 5c8f6f5..aecc2e2 100644 --- a/network/packet/UDPPacket.h +++ b/network/packet/UDPPacket.h @@ -1,13 +1,21 @@ -#ifndef TOS_NETWORK_PACKET_H -#define TOS_NETWORK_PACKET_H +#ifndef TOS_NETWORK_PACKET_UDP_H +#define TOS_NETWORK_PACKET_UDP_H #include #include "../../stdlib/Types.h" #include "../../compression/LZP.h" +#include "../../utils/EndianUtils.h" #include "PacketHeader.h" +#if _WIN32 + #include +#elif __linux__ + #include + #include +#endif + // The message loop is as follows: // Game Data -> pack data // Game Message (packed) -> compress data @@ -32,52 +40,116 @@ struct UDPPacketIPv6 { struct UDPMessageIPv6 { HeaderIPv6Unpacked header_ipv6; UDPHeaderIPv6Unpacked header_udp; - CustomHeaderUnpacked header_custom; - size_t length; byte* data; }; -/** - * WARNING: This requires the original message to remain in memory since we are only referencing the data - */ -inline -void udp_packet_to_message(const UDPPacketIPv6* packet, UDPMessageIPv6* message) -{ - unpack_ipv6_header((const HeaderIPv6*) packet->data, &message->header_ipv6); - unpack_udp_header_ipv6((const UDPHeaderIPv6*) (packet->data + HEADER_IPV6_SIZE), &message->header_udp); - message->data = (byte *) (packet->data + HEADER_IPV6_SIZE + HEADER_UDP_SIZE); +uint16 packet_udp_calculate_checksum(uint16* buf, int32 count) { + uint32 sum = 0; - // @todo transform packet data to appropriate packet type + // First we create the checksum from the ipv6 header (not all of the data is required) + // Alternatively we would have had to create a pseudo_header and do a bunch of memcpy which we didn't want to do + HeaderIPv6Unpacked* ipv6_header = (HeaderIPv6Unpacked *) buf; + const byte* temp_data = ((byte *) (&ipv6_header->ip6_src)); + for (uint32 i = 0; i < sizeof(ipv6_header->ip6_src) / 2; ++i) { + uint16 word = (uint16) temp_data[i] << 8 | (uint16) temp_data[i + 1]; + sum += word; + } + + temp_data = ((byte *) (&ipv6_header->ip6_dst)); + for (uint32 i = 0; i < sizeof(ipv6_header->ip6_dst) / 2; ++i) { + uint16 word = (uint16) temp_data[i] << 8 | (uint16) temp_data[i + 1]; + sum += word; + } + + temp_data = ((byte *) (&ipv6_header->ip6_plen)); + for (uint32 i = 0; i < sizeof(ipv6_header->ip6_plen) / 2; ++i) { + uint16 word = (uint16) temp_data[i] << 8 | (uint16) temp_data[i + 1]; + sum += word; + } + + // The next header has some 0s prefixed, this is required since the checksum works on uint16 + byte next_header[] = {0, 0, 0, ipv6_header->ip6_nxt}; + for (uint32 i = 0; i < sizeof(ipv6_header->ip6_nxt) / 2; ++i) { + uint16 word = (uint16) next_header[i] << 8 | (uint16) next_header[i + 1]; + sum += word; + } + + // Now create checksum for udp header and payload/body + while (count > 0) { + sum += *buf++; + --count; + } + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + + return (uint16) ~sum; } -/** - * The original message can be deleted since the data is copied over - */ +// WARNING: ports need to be already in big endian inline -void message_to_udp_packet(const UDPMessageIPv6* message, UDPPacketIPv6* packet) -{ - pack_ipv6_header(&message->header_ipv6, (HeaderIPv6 *) packet); +uint16 packet_udp_create_raw( + byte* __restrict packet, + in6_addr* __restrict ipv6_src, uint16 port_src, + in6_addr* __restrict ipv6_dst, uint16 port_dst, + uint16 flow, + byte* __restrict data, uint16 data_length +) { + // create ipv6 header + HeaderIPv6Unpacked* ip6_header = (HeaderIPv6Unpacked *) packet; + ip6_header->ip6_flow = SWAP_ENDIAN_BIG((6 << 28) | (0 << 20) | flow); + ip6_header->ip6_plen = SWAP_ENDIAN_BIG((uint16) (sizeof(UDPHeaderIPv6Unpacked) + data_length)); + ip6_header->ip6_nxt = IPPROTO_UDP; + ip6_header->ip6_hops = 64; + memcpy(&ip6_header->ip6_src, ipv6_src, sizeof(in6_addr)); + memcpy(&ip6_header->ip6_dst, ipv6_dst, sizeof(in6_addr)); - packet->data = packet->data + HEADER_IPV6_SIZE; - pack_udp_header_ipv6(&message->header_udp, (UDPHeaderIPv6 *) packet); - packet->data = packet->data - HEADER_IPV6_SIZE; + // create udp header + UDPHeaderIPv6Unpacked* udp_header = (UDPHeaderIPv6Unpacked *) (packet + sizeof(HeaderIPv6Unpacked)); - memcpy(packet->data + HEADER_IPV6_SIZE + HEADER_UDP_SIZE, message->data, message->length); + udp_header->source = port_src; + udp_header->dest = port_dst; + udp_header->len = ip6_header->ip6_plen; + udp_header->check = 0; + + // create payload + memcpy(packet + sizeof(HeaderIPv6Unpacked) + sizeof(UDPHeaderIPv6Unpacked), data, data_length); + + udp_header->check = SWAP_ENDIAN_BIG(packet_udp_calculate_checksum( + (uint16 *) (packet), + (sizeof(UDPHeaderIPv6Unpacked) + data_length) / 2 + )); + + // Raw sockets must use the entire packet size + return sizeof(HeaderIPv6Unpacked) + sizeof(UDPHeaderIPv6Unpacked) + data_length; +} + +// WARNING: ports need to be already in big endian +inline +uint16 packet_udp_create( + byte* __restrict packet, + uint16 port_src, uint16 port_dst, + byte* __restrict data, uint16 data_length +) { + // create udp header + UDPHeaderIPv6Unpacked* udp_header = (UDPHeaderIPv6Unpacked *) packet; + + udp_header->source = port_src; + udp_header->dest = port_dst; + udp_header->len = SWAP_ENDIAN_BIG((uint16) (sizeof(UDPHeaderIPv6Unpacked) + data_length)); + udp_header->check = 0; + + // create payload + memcpy(packet + sizeof(UDPHeaderIPv6Unpacked), data, data_length); + + return data_length; } inline -void decompress_data(UDPMessageIPv6* message, byte* decompress_buffer) +void packet_flowinfo_set(sockaddr_in6* dest, uint16 flow) { - lzp_decode(message->data, message->length, decompress_buffer); - message->data = decompress_buffer; -} - -inline -void compress_data(UDPMessageIPv6* message, byte* compressed_buffer) -{ - lzp_encode(message->data, message->length, compressed_buffer); - message->data = compressed_buffer; + dest->sin6_flowinfo = SWAP_ENDIAN_BIG((6 << 28) | (0 << 20) | flow); } #endif \ No newline at end of file diff --git a/network/packet/chat/ChatMessagePacket.h b/network/packet/chat/ChatMessagePacket.h index f66f2c4..b3ed801 100644 --- a/network/packet/chat/ChatMessagePacket.h +++ b/network/packet/chat/ChatMessagePacket.h @@ -4,7 +4,6 @@ #include #include "../../../stdlib/Types.h" -#include "../../../config.h" struct ChatMessagePacket { byte* data; // fixed 8+2+? @@ -14,7 +13,7 @@ struct ChatMessagePacketUnpacked { uint32 from; uint32 to; - byte type; // 2^3 Global, Player, Group, Guild, Local + byte type; // 2^3 Global, Server, Player, Group, Guild, Local byte level; // 2^2 Normal, info (grey), important (yellow), critical (red) uint16 length; // 2^9 diff --git a/network/packet/general/AckPacket.h b/network/packet/general/AckPacket.h new file mode 100644 index 0000000..203351c --- /dev/null +++ b/network/packet/general/AckPacket.h @@ -0,0 +1,11 @@ +#ifndef TOS_NETWORK_PACKET_GENERAL_PING_H +#define TOS_NETWORK_PACKET_GENERAL_PING_H + +#include + +#include "../../../stdlib/Types.h" +#include "../PacketHeader.h" + +typedef CustomHeaderUnpacked AckPacket; + +#endif \ No newline at end of file diff --git a/network/packet/general/PingPacket.h b/network/packet/general/PingPacket.h new file mode 100644 index 0000000..345930f --- /dev/null +++ b/network/packet/general/PingPacket.h @@ -0,0 +1,19 @@ +#ifndef TOS_NETWORK_PACKET_GENERAL_PING_H +#define TOS_NETWORK_PACKET_GENERAL_PING_H + +#include + +#include "../../../stdlib/Types.h" + +// The default ping package is an empty package +struct PingPackage {}; + +#pragma pack(push, 1) +struct __attribute__ ((__packed__)) TimedPingPackage { + uint8 msg_type; + uint8 subtype; + uint64 time; +}; +#pragma pack(pop) + +#endif \ No newline at end of file diff --git a/object/Mesh.h b/object/Mesh.h index 9d46d8f..44d48ae 100644 --- a/object/Mesh.h +++ b/object/Mesh.h @@ -21,6 +21,7 @@ #include "../memory/RingMemory.h" #include "../stdlib/simd/SIMD_I32.h" #include "../utils/EndianUtils.h" +#include "../utils/StringUtils.h" #define MESH_VERSION 1 @@ -87,7 +88,6 @@ void mesh_from_file_txt( mesh->vertices = (f32 *) mesh->data; - // @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; @@ -109,9 +109,7 @@ void mesh_from_file_txt( uint32 temp_color_count = 0; while (*pos != '\0') { - while (*pos == ' ' || *pos == '\t' || *pos == '\n') { - ++pos; - } + char_skip_empty(&pos); if (*pos == '\0') { break; @@ -154,15 +152,11 @@ void mesh_from_file_txt( state = 15; } else { // not supported or comment - while (*pos != '\n' && *pos != '\0') { - ++pos; - } + char_move_to(&pos, '\n'); } // move past keyword - while (*pos != ' ' && *pos != '\n' && *pos != '\0') { - ++pos; - } + char_skip_non_empty(&pos); // move past whitespaces and newline bool is_next_line = false; diff --git a/platform/Library.h b/platform/Library.h new file mode 100644 index 0000000..a78f0df --- /dev/null +++ b/platform/Library.h @@ -0,0 +1,39 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_LIBRARY_H +#define TOS_PLATFORM_LIBRARY_H + +#include "../stdlib/Types.h" + +#if _WIN32 + #include +#endif + +struct Library { + #if _WIN32 + HMODULE handle; + #elif __linux__ + void* handle; + #endif + + bool is_valid; + + char dir[MAX_PATH]; + char dst[64]; + + #if DEBUG + uint64 last_load; + #endif + + int32 function_count; + const char** function_names; + void** functions; +}; + +#endif \ No newline at end of file diff --git a/platform/SystemInfo.h b/platform/SystemInfo.h new file mode 100644 index 0000000..3459bdc --- /dev/null +++ b/platform/SystemInfo.h @@ -0,0 +1,92 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_SYSTEM_INFO_H +#define TOS_PLATFORM_SYSTEM_INFO_H + +#include "../stdlib/Types.h" + +struct CpuCacheInfo { + int32 level; + int32 size; + int32 ways; + int32 partitions; + int32 sets; + int32 line_size; +}; + +// @todo add vendor name +struct MainboardInfo { + char name[64]; + char serial_number[64]; +}; + +// @todo add ipv6 +struct NetworkInfo { + char slot[64]; + byte mac[8]; +}; + +struct SIMDInfo { + f32 sse; + int32 avx256; + int32 avx512; +}; + +struct CpuInfo { + char vendor[13]; + char brand[49]; + int32 model; + int32 family; + int32 mhz; + CpuCacheInfo cache[4]; + int32 page_size; + SIMDInfo simd; +}; + +struct OSInfo { + char vendor[16]; + char name[64]; + int32 major; + int32 minor; +}; + +struct RamInfo { + int32 memory; +}; + +struct GpuInfo { + char name[64]; + int32 vram; +}; + +struct DisplayInfo { + char name[64]; + int32 width; + int32 height; + int32 hz; +}; + +struct SystemInfo { + OSInfo os; + MainboardInfo mainboard; + + NetworkInfo network[4]; + int32 network_count; + + CpuInfo cpu; + RamInfo ram; + + GpuInfo gpu[2]; + int32 gpu_count; + + DisplayInfo display[6]; + int32 display_count; +}; + +#endif \ No newline at end of file diff --git a/platform/linux/Allocation.h b/platform/linux/Allocation.h new file mode 100644 index 0000000..4ce2f50 --- /dev/null +++ b/platform/linux/Allocation.h @@ -0,0 +1,61 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_LINUX_ALLOCATION_H +#define TOS_PLATFORM_LINUX_ALLOCATION_H + +#include +#include + +inline +void aligned_free(void** ptr) { + free(*ptr); + *ptr = NULL; +} + +inline +void* platform_alloc(size_t size) +{ + ssize_t page_size = sysconf(_SC_PAGESIZE); + + size = (size + page_size - 1) & ~(page_size - 1); + + return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +} + +inline +void* platform_alloc_aligned(size_t size, int32 alignment) +{ + ssize_t page_size = sysconf(_SC_PAGESIZE); + if (alignment < page_size) { + alignment = page_size; + } + + size = (size + alignment - 1) & ~(alignment - 1); + + void* ptr = mmap(NULL, size + alignment + sizeof(void*), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + void* aligned_ptr = (void*)(((uintptr_t)ptr + alignment + sizeof(void*) - 1) & ~(alignment - 1)); + ((void**) aligned_ptr)[-1] = ptr; + + return aligned_ptr; +} + +inline +void platform_free(void** ptr, size_t size) { + munmap(*ptr, size); + *ptr = NULL; +} + +inline +void platform_aligned_free(void** aligned_ptr, size_t size) { + void* ptr = ((void**) *aligned_ptr)[-1]; + munmap(ptr, size + ((uintptr_t) *aligned_ptr - (uintptr_t)ptr)); + *aligned_ptr = NULL; +} +#endif \ No newline at end of file diff --git a/platform/linux/Library.h b/platform/linux/Library.h new file mode 100644 index 0000000..a1f3c4c --- /dev/null +++ b/platform/linux/Library.h @@ -0,0 +1,90 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_LINUX_LIBRARY_H +#define TOS_PLATFORM_LINUX_LIBRARY_H + +#include +#include +#include +#include +#include + +#include "../../stdlib/Types.h" +#include "../../utils/StringUtils.h" +#include "UtilsLinux.h" +#include "../Library.h" + +// @todo Rename file to Library.cpp + +inline +bool library_load(Library* lib) +{ + size_t path_length = strlen(lib->dir); + + char dst[PATH_MAX]; + str_concat( + lib->dir, path_length, + lib->dst, strlen(lib->dst), + dst + ); + + #if DEBUG + char src[PATH_MAX]; + size_t dst_len = strlen(dst); + + memcpy(src, dst, dst_len + 1); + + memcpy(dst + dst_len - (sizeof(".so") - 1), "_temp", sizeof("_temp") - 1); + memcpy(dst + dst_len - (sizeof(".so") - 1) + (sizeof("_temp") - 1), ".so", sizeof(".so")); + + lib->last_load = last_modified(src); + file_copy(src, dst); + #endif + + // Unload any previous instance of the library if it’s already loaded + if (lib->handle) { + dlclose(lib->handle); + lib->handle = NULL; + usleep(100000); // 100 ms + } + + // @question we might want RTLD_NOW? + lib->handle = dlopen(dst, RTLD_LAZY); + if (!lib->handle) { + lib->is_valid = false; + return lib->is_valid; + } + + lib->is_valid = true; + for (int32_t c = 0; c < lib->function_count; ++c) { + void* function = dlsym(lib->handle, lib->function_names[c]); + if (function) { + lib->functions[c] = function; + } else { + lib->is_valid = false; + } + } + + return lib->is_valid; +} + +inline +void library_unload(Library* lib) +{ + if (lib->handle) { + dlclose(lib->handle); + lib->handle = NULL; + } + + for (int32_t c = 0; c < lib->function_count; ++c) { + lib->functions[c] = NULL; + } +} + +#endif diff --git a/platform/linux/Server.h b/platform/linux/Server.h new file mode 100644 index 0000000..ebc175b --- /dev/null +++ b/platform/linux/Server.h @@ -0,0 +1,102 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_LINUX_SERVER_H +#define TOS_PLATFORM_LINUX_SERVER_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../../stdlib/Types.h" +#include "../../network/SocketConnection.h" +#include "../../utils/EndianUtils.h" + +// WARNING: requires `sudo setcap cap_net_raw=eip /path/to/your_program` +void socket_server_raw_create(const char* hostname, SocketConnection* con) { + con->sd = socket(AF_INET6, SOCK_RAW, 255); + + int32 flags; + if ((flags = fcntl(con->sd, F_GETFL, 0)) < 0) { + close(con->sd); + con->sd = 0; + } + + if (fcntl(con->sd, F_SETFL, flags | O_NONBLOCK) < 0) { + close(con->sd); + con->sd = 0; + } + + con->addr.sin6_family = AF_INET6; + con->addr.sin6_addr = in6addr_any; + con->addr.sin6_port = SWAP_ENDIAN_BIG(con->port); + + if (bind(con->sd, (sockaddr *) &con->addr, sizeof(con->addr)) < 0) { + close(con->sd); + con->sd = 0; + } +} + +// WARNING: requires `sudo setcap cap_net_raw=eip /path/to/your_program` +void socket_server_udp_raw_create(const char* hostname, SocketConnection* con) { + con->sd = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP); + + int32 flags; + if ((flags = fcntl(con->sd, F_GETFL, 0)) < 0) { + close(con->sd); + con->sd = 0; + } + + if (fcntl(con->sd, F_SETFL, flags | O_NONBLOCK) < 0) { + close(con->sd); + con->sd = 0; + } + + con->addr.sin6_family = AF_INET6; + con->addr.sin6_addr = in6addr_any; + con->addr.sin6_port = SWAP_ENDIAN_BIG(con->port); + + if (bind(con->sd, (sockaddr *) &con->addr, sizeof(con->addr)) < 0) { + close(con->sd); + con->sd = 0; + } +} + +void socket_server_udp_create(const char* hostname, SocketConnection* con) { + con->sd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + + int32 flags; + if ((flags = fcntl(con->sd, F_GETFL, 0)) < 0) { + close(con->sd); + con->sd = 0; + } + + if (fcntl(con->sd, F_SETFL, flags | O_NONBLOCK) < 0) { + close(con->sd); + con->sd = 0; + } + + con->addr.sin6_family = AF_INET6; + con->addr.sin6_addr = in6addr_any; + con->addr.sin6_port = SWAP_ENDIAN_BIG(con->port); + + if (bind(con->sd, (sockaddr *) &con->addr, sizeof(con->addr)) < 0) { + close(con->sd); + con->sd = 0; + } +} + +#endif \ No newline at end of file diff --git a/platform/linux/SystemInfo.h b/platform/linux/SystemInfo.h index 9c6dde2..7f2b288 100644 --- a/platform/linux/SystemInfo.h +++ b/platform/linux/SystemInfo.h @@ -6,81 +6,36 @@ * @version 1.0.0 * @link https://jingga.app */ -#ifndef TOS_UTILS_SYSTEM_INFO_H -#define TOS_UTILS_SYSTEM_INFO_H +#ifndef TOS_PLATFORM_LINUX_SYSTEM_INFO_C +#define TOS_PLATFORM_LINUX_SYSTEM_INFO_C #include #include -#include "../stdlib/Types.h" -#include "../stdlib/simd/SIMD_Helper.h" -#include "StringUtils.h" +#include "../../stdlib/Types.h" +#include "../../stdlib/simd/SIMD_Helper.h" +#include "../../utils/StringUtils.h" +#include "../SystemInfo.h" -#if _WIN32 - #include - #include - #include - #include - #include - #include - #include - #include - #include -#else - #include -#endif +#include +#include -#ifdef _MSC_VER - #include -#endif - -#if __linux__ && (__i386__ || __x86_64__) - #include -#endif // @todo implement for arm? -// @todo implement for linux? uint16 system_language_code() { - #if _WIN32 - LANGID langID = GetUserDefaultUILanguage(); - wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; - - if (!LCIDToLocaleName(langID, localeName, LOCALE_NAME_MAX_LENGTH, 0)) { - return 0; - } - #else - char *localeName = setlocale(LC_ALL, ""); - #endif + const char* localeName = setlocale(LC_ALL, ""); return (localeName[0] << 8) | localeName[1]; } uint16 system_country_code() { - #if _WIN32 - LANGID langID = GetUserDefaultUILanguage(); - wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; - - if (!LCIDToLocaleName(langID, localeName, LOCALE_NAME_MAX_LENGTH, 0)) { - return 0; - } - #else - char *localeName = setlocale(LC_ALL, ""); - #endif + const char* localeName = setlocale(LC_ALL, ""); return (localeName[3] << 8) | localeName[4]; } -struct CpuCacheInfo { - int32 level; - int32 size; - int32 ways; - int32 partitions; - int32 sets; - int32 line_size; -}; - void cache_info_get(int32 level, CpuCacheInfo* cache) { uint32 eax, ebx, ecx, edx; int32 type; @@ -92,20 +47,9 @@ void cache_info_get(int32 level, CpuCacheInfo* cache) { cache->sets = 0; cache->line_size = 0; - #if _WIN32 - int32 regs[4]; - __cpuidex(regs, 4, level); - eax = regs[0]; - ebx = regs[1]; - ecx = regs[2]; - edx = regs[3]; + __cpuid_count(4, level, eax, ebx, ecx, edx); - type = (eax & 0x1F); - #else - __cpuid_count(4, level, eax, ebx, ecx, edx); - - type = (eax & 0x1F); - #endif + type = (eax & 0x1F); if (type == 0) { return; @@ -118,12 +62,6 @@ void cache_info_get(int32 level, CpuCacheInfo* cache) { cache->size = cache->ways * cache->partitions * cache->line_size * cache->sets; } -// @todo add vendor name -struct MainboardInfo { - char name[64]; - char serial_number[64]; -}; - void mainboard_info_get(MainboardInfo* info) { info->name[63] = '\0'; info->serial_number[63] = '\0'; @@ -253,12 +191,6 @@ void mainboard_info_get(MainboardInfo* info) { CoUninitialize(); } -// @todo add ipv6 -struct NetworkInfo { - char slot[64]; - byte mac[8]; -}; - int network_info_get(NetworkInfo* info) { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { @@ -312,23 +244,6 @@ int network_info_get(NetworkInfo* info) { return i; } -struct SIMDInfo { - f32 sse; - int32 avx256; - int32 avx512; -}; - -struct CpuInfo { - char vendor[13]; - char brand[49]; - int32 model; - int32 family; - int32 mhz; - CpuCacheInfo cache[4]; - int32 page_size; - SIMDInfo simd; -}; - void cpu_info_get(CpuInfo* info) { int32 temp; info->simd.sse = (temp = max_sse_supported()) > 9 ? temp / 10.0f : temp; @@ -380,42 +295,16 @@ void cpu_info_get(CpuInfo* info) { RegCloseKey(hKey); } -struct OSInfo { - char vendor[16]; - char name[64]; - int32 major; - int32 minor; -}; - void os_info_get(OSInfo* info) { - info->vendor[15] = '\0'; - info->name[63] = '\0'; + memcpy(info->vendor, "Linux", sizeof("Linux")); + memcpy(info->name, "Linux", sizeof("Linux")); + info->major = 0; + info->minor = 0; - #if defined(_WIN32) || defined(_WIN64) - OSVERSIONINFOEXW version_info; - memset(&version_info, 0, sizeof(OSVERSIONINFOEXW)); - version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); - NTSTATUS(WINAPI *RtlGetVersion)(OSVERSIONINFOEXW*) = (NTSTATUS(WINAPI *)(OSVERSIONINFOEXW*))GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion"); - if (RtlGetVersion != nullptr) { - RtlGetVersion(&version_info); - } - - memcpy(info->vendor, "Microsoft", sizeof("Microsoft")); - memcpy(info->name, "Windows", sizeof("Windows")); - info->major = version_info.dwMajorVersion; - info->minor = version_info.dwMinorVersion; - #else - memcpy(info->vendor, "Linux", sizeof("Linux")); - memcpy(info->name, "Linux", sizeof("Linux")); - info->major = 0; - info->minor = 0; - #endif + info->vendor[sizeof("Linux")] = '\0'; + info->name[sizeof("Linux")] = '\0'; } -struct RamInfo { - int32 memory; -}; - void ram_info_get(RamInfo* info) { MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); @@ -423,11 +312,6 @@ void ram_info_get(RamInfo* info) { info->memory = (int) (statex.ullTotalPhys / (1024 * 1024)); } -struct GpuInfo { - char name[64]; - int32 vram; -}; - uint32 gpu_info_get(GpuInfo* info) { IDXGIFactory *pFactory = NULL; IDXGIAdapter *pAdapter = NULL; @@ -459,13 +343,6 @@ uint32 gpu_info_get(GpuInfo* info) { return i; } -struct DisplayInfo { - char name[64]; - int32 width; - int32 height; - int32 hz; -}; - uint32 display_info_get(DisplayInfo* info) { DISPLAY_DEVICEA device; DEVMODEA mode; @@ -490,23 +367,6 @@ uint32 display_info_get(DisplayInfo* info) { return i; } -struct SystemInfo { - OSInfo os; - MainboardInfo mainboard; - - NetworkInfo network[4]; - int32 network_count; - - CpuInfo cpu; - RamInfo ram; - - GpuInfo gpu[2]; - int32 gpu_count; - - DisplayInfo display[6]; - int32 display_count; -}; - void system_info_render(char* buf, const SystemInfo* info) { const char avx512[8][12] = { "AVX-512F", @@ -521,7 +381,6 @@ void system_info_render(char* buf, const SystemInfo* info) { sprintf_s( buf, - 4096, "OS:\n" "==============\n" "Vendor: %s\n" "Name: %s\n" "Major: %d\n" "Minor: %d\n" diff --git a/platform/linux/Thread.h b/platform/linux/Thread.h new file mode 100644 index 0000000..571e4a7 --- /dev/null +++ b/platform/linux/Thread.h @@ -0,0 +1,14 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_LINUX_THREAD_H +#define TOS_PLATFORM_LINUX_THREAD_H + +#include "ThreadDefines.h" + +#endif \ No newline at end of file diff --git a/platform/linux/ThreadDefines.h b/platform/linux/ThreadDefines.h new file mode 100644 index 0000000..3419b3c --- /dev/null +++ b/platform/linux/ThreadDefines.h @@ -0,0 +1,18 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_LINUX_THREAD_DEFINES_H +#define TOS_PLATFORM_LINUX_THREAD_DEFINES_H + +#include +#include +typedef void* (*ThreadJobFunc)(void*); + +#define THREAD_RETURN void* + +#endif \ No newline at end of file diff --git a/platform/linux/UtilsLinux.h b/platform/linux/UtilsLinux.h index a08b819..5e16392 100644 --- a/platform/linux/UtilsLinux.h +++ b/platform/linux/UtilsLinux.h @@ -16,12 +16,14 @@ #include #include #include -#include #include +#include +#include #include "../../stdlib/Types.h" #include "../../utils/Utils.h" #include "../../utils/TestUtils.h" +#include "../../memory/RingMemory.h" #ifndef MAX_PATH #define MAX_PATH PATH_MAX @@ -32,7 +34,6 @@ int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...) { va_list args; if (buffer == NULL || format == NULL || sizeOfBuffer == 0) { - errno = EINVAL; return -1; } @@ -44,7 +45,6 @@ int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...) { if (result >= 0 && (size_t)result >= sizeOfBuffer) { buffer[sizeOfBuffer - 1] = '\0'; - errno = 80; return 80; } @@ -52,37 +52,41 @@ int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...) { return result; } -inline void relative_to_absolute(const char* rel, char* path) +inline +void relative_to_absolute(const char* rel, char* path) { + char self_path[MAX_PATH]; + int32 self_path_length = readlink("/proc/self/exe", self_path, MAX_PATH - 1); + if (self_path_length == -1) { + return; + } + const char* temp = rel; if (temp[0] == '.' && temp[1] == '/') { temp += 2; } - char self_path[MAX_PATH]; - ssize_t count = readlink("/proc/self/exe", self_path, MAX_PATH - 1); - if (count == -1) { - return; - } - self_path[count] = '\0'; - - char* last = strrchr(self_path, '/'); - if (last != NULL) { - *(last + 1) = '\0'; + char* last = self_path + self_path_length; + while (*last != '/' && self_path_length > 0) { + --last; + --self_path_length; } - snprintf(path, MAX_PATH, "%s%s", self_path, temp); + ++self_path_length; + + memcpy(path, self_path, self_path_length); + strcpy(path + self_path_length, temp); } // @todo implement relative path support, similar to UtilsWin32 inline uint64 file_size(const char* filename) { - struct stat st; - if (stat(filename, &st) != 0) { + struct stat buffer; + if (stat(filename, &buffer) != 0) { return 0; } - return st.st_size; + return buffer.st_size; } inline @@ -95,131 +99,171 @@ uint64 last_modified(const char* filename) } inline -void file_read(const char* filename, FileBody* file, RingMemory* ring = NULL) -{ - FILE *fp = fopen(filename, "rb"); - fseek(fp, 0, SEEK_END); +int32 get_append_handle(const char* path) { + int32 fp; + if (*path == '.') { + char full_path[MAX_PATH]; + relative_to_absolute(path, full_path); - file->size = ftell(fp); - rewind(fp); - - if (ring != NULL) { - file->content = ring_get_memory(ring, file->size); + fp = open(full_path, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); + } else { + fp = open(path, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); } - fread(file->content, 1, file->size, fp); - - fclose(fp); -} - -inline -uint64_t file_read_struct(const char* filename, void* file, uint32 size) { - FILE *fp = fopen(filename, "rb"); - if (!fp) { - return 0; - } - - size_t read_bytes = fread(file, 1, size, fp); - fclose(fp); - - return read_bytes; -} - -inline -bool file_write(const char* filename, const FileBody* file) { - FILE *fp = fopen(filename, "wb"); - if (!fp) { - return false; - } - - size_t written = fwrite(file->content, 1, file->size, fp); - fclose(fp); - - return written == file->size; -} - -inline -bool file_write_struct(const char* filename, const void* file, uint32_t size) { - FILE *fp = fopen(filename, "wb"); - if (!fp) { - return false; - } - - size_t written = fwrite(file, 1, size, fp); - fclose(fp); - - return written == size; -} - -inline -void file_copy(const char* src, const char* dst) { - FILE *src_fp = fopen(src, "rb"); - FILE *dst_fp = fopen(dst, "wb"); - - if (!src_fp || !dst_fp) { - if (src_fp) fclose(src_fp); - if (dst_fp) fclose(dst_fp); - return; - } - - char buffer[4096]; - size_t bytes; - while ((bytes = fread(buffer, 1, sizeof(buffer), src_fp)) > 0) { - fwrite(buffer, 1, bytes, dst_fp); - } - - fclose(src_fp); - fclose(dst_fp); -} - -inline -FILE* get_append_handle(const char* filename) { - FILE *fp = fopen(filename, "ab"); - if (!fp) { - return NULL; - } return fp; } -inline bool file_append(const char* filename, const char* file) { - FILE *fp = get_append_handle(filename); - if (!fp) { - return false; +inline +bool file_exists(const char* path) { + struct stat buffer; + const char* full_path = path; + char abs_path[MAX_PATH]; + + if (*path == '.') { + relative_to_absolute(path, abs_path); + full_path = abs_path; } - size_t length = strlen(file); - ASSERT_SIMPLE(length < INT32_MAX); - size_t written = fwrite(file, 1, length, fp); - fclose(fp); - - return written == length; + return stat(full_path, &buffer) == 0; } -inline bool file_append(FILE* fp, const char* file) { - if (!fp) { +inline +bool file_copy(const char* src, const char* dst) { + char src_full_path[MAX_PATH]; + char dst_full_path[MAX_PATH]; + + if (*src == '.') { + relative_to_absolute(src, src_full_path); + src = src_full_path; + } + + if (*dst == '.') { + relative_to_absolute(dst, dst_full_path); + dst = dst_full_path; + } + + int32 src_fd = open(src, O_RDONLY); + if (src_fd < 0) { return false; } - size_t length = strlen(file); - ASSERT_SIMPLE(length < INT32_MAX); - size_t written = fwrite(file, 1, length, fp); - fclose(fp); + int32 dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (dst_fd < 0) { + close(src_fd); - return written == length; + return false; + } + + char buffer[8192]; + ssize_t bytes_read, bytes_written; + bool success = true; + + while ((bytes_read = read(src_fd, buffer, sizeof(buffer))) > 0) { + bytes_written = write(dst_fd, buffer, bytes_read); + if (bytes_written != bytes_read) { + success = false; + break; + } + } + + if (bytes_read < 0) { + success = false; + } + + close(src_fd); + close(dst_fd); + + return success; } -inline bool file_append(const char* filename, const FileBody* file) { - FILE *fp = get_append_handle(filename); - if (!fp) { +inline +void file_read(const char* path, FileBody* file, RingMemory* ring) { + char full_path[MAX_PATH]; + const char* abs_path = path; + + if (*path == '.') { + relative_to_absolute(path, full_path); + abs_path = full_path; + } + + int32 fp = open(abs_path, O_RDONLY); + if (fp < 0) { + file->size = 0; + file->content = NULL; + + return; + } + + struct stat file_stat; + if (fstat(fp, &file_stat) == -1) { + close(fp); + file->size = 0; + file->content = NULL; + + return; + } + + if (file_stat.st_size > MAX_INT32) { + close(fp); + file->size = 0; + file->content = NULL; + + return; + } + + if (ring != NULL) { + file->content = ring_get_memory(ring, file_stat.st_size); + } + + ssize_t bytes_read = read(fp, file->content, file_stat.st_size); + if (bytes_read != file_stat.st_size) { + close(fp); + file->content = NULL; + file->size = 0; + + return; + } + + file->content[bytes_read] = '\0'; + file->size = bytes_read; + + close(fp); +} + +inline +bool file_write(const char* path, const FileBody* file) { + int32 fd; + char full_path[PATH_MAX]; + + if (*path == '.') { + relative_to_absolute(path, full_path); + path = full_path; + } + + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { return false; } - size_t length = file->size; - ASSERT_SIMPLE(length < INT32_MAX); - size_t written = fwrite(file->content, 1, length, fp); - fclose(fp); + ASSERT_SIMPLE(file->size < MAX_INT32); - return written == length; + ssize_t written = write(fd, file->content, file->size); + if (written < 0 || (size_t) written != file->size) { + close(fd); + return false; + } + + if (close(fd) < 0) { + return false; + } + + return true; +} + +inline +void close_handle(int32 fp) +{ + close(fp); } inline @@ -232,14 +276,4 @@ void self_path(char* path) { } } -inline -void strncpy_s(char *dest, size_t destsz, const char *src, size_t count) { - size_t i; - - for (i = 0; i < count && i < destsz - 1 && src[i] != '\0'; ++i) { - dest[i] = src[i]; - } - - dest[i] = '\0'; -} #endif \ No newline at end of file diff --git a/platform/win32/Allocation.h b/platform/win32/Allocation.h new file mode 100644 index 0000000..5bbe70f --- /dev/null +++ b/platform/win32/Allocation.h @@ -0,0 +1,56 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_ALLOCATION_H +#define TOS_PLATFORM_WIN32_ALLOCATION_H + +#include +#include +#include "../../stdlib/Types.h" + +inline +void* aligned_alloc(size_t alignment, size_t size) { + return _aligned_malloc(size, alignment); +} + +inline +void aligned_free(void** ptr) { + _aligned_free(*ptr); + *ptr = NULL; +} + +inline +void* platform_alloc(size_t size) +{ + return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +} + +inline +void* platform_alloc_aligned(size_t size, int32 alignment) +{ + void* ptr = VirtualAlloc(NULL, size + alignment + sizeof(void*), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + + void* aligned_ptr = (void*)(((uintptr_t)ptr + alignment + sizeof(void*) - 1) & ~(alignment - 1)); + ((void**) aligned_ptr)[-1] = ptr; + + return aligned_ptr; +} + +inline +void platform_free(void** ptr, size_t) { + VirtualFree(*ptr, 0, MEM_RELEASE); + *ptr = NULL; +} + +inline +void platform_aligned_free(void** aligned_ptr, size_t) { + void* ptr = ((void**) *aligned_ptr)[-1]; + VirtualFree(ptr, 0, MEM_RELEASE); + *aligned_ptr = NULL; +} +#endif \ No newline at end of file diff --git a/platform/win32/Client.h b/platform/win32/Client.h new file mode 100644 index 0000000..4348db3 --- /dev/null +++ b/platform/win32/Client.h @@ -0,0 +1,60 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_SERVER_H +#define TOS_PLATFORM_WIN32_SERVER_H + +#include +#include +#include + +#include +#include + +#include "../../stdlib/Types.h" +#include "../../network/SocketConnection.h" +#include "../../utils/EndianUtils.h" + +#pragma comment(lib, "Ws2_32.lib") + +void socket_client_udp_create(SocketConnection* con, uint16 port = 0) { + WSADATA wsaData; + + // Initialize Winsock + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + return; + } + + // Create socket + con->sd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (con->sd == INVALID_SOCKET) { + WSACleanup(); + return; + } + + // Set socket to non-blocking mode + u_long mode = 1; + if (ioctlsocket(con->sd, FIONBIO, &mode) != NO_ERROR) { + closesocket(con->sd); + WSACleanup(); + return; + } + + // Bind socket + con->addr.sin6_family = AF_INET6; + con->addr.sin6_addr = in6addr_any; + con->addr.sin6_port = port; // 0 = OS decides the port + + if (bind(con->sd, (struct sockaddr*) &con->addr, sizeof(con->addr)) == SOCKET_ERROR) { + closesocket(con->sd); + WSACleanup(); + return; + } +} + +#endif \ No newline at end of file diff --git a/platform/win32/Library.h b/platform/win32/Library.h index 394d879..f05eca9 100644 --- a/platform/win32/Library.h +++ b/platform/win32/Library.h @@ -16,22 +16,9 @@ #include "../../stdlib/Types.h" #include "UtilsWin32.h" #include "../../utils/StringUtils.h" +#include "../Library.h" -struct Library { - HMODULE handle; - bool is_valid; - - char dir[MAX_PATH]; - char dst[64]; - - #if DEBUG - uint64 last_load; - #endif - - int32 function_count; - const char** function_names; - void** functions; -}; +// @todo Rename file to Library.cpp inline bool library_load(Library* lib) diff --git a/platform/win32/Server.h b/platform/win32/Server.h new file mode 100644 index 0000000..9ad4e1a --- /dev/null +++ b/platform/win32/Server.h @@ -0,0 +1,60 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_SERVER_H +#define TOS_PLATFORM_WIN32_SERVER_H + +#include +#include +#include + +#include +#include + +#include "../../stdlib/Types.h" +#include "../../network/SocketConnection.h" +#include "../../utils/EndianUtils.h" + +#pragma comment(lib, "Ws2_32.lib") + +void socket_server_udp_create(const char* hostname, SocketConnection* con) { + WSADATA wsaData; + + // Initialize Winsock + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + return; + } + + // Create socket + con->sd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (con->sd == INVALID_SOCKET) { + WSACleanup(); + return; + } + + // Set socket to non-blocking mode + u_long mode = 1; + if (ioctlsocket(con->sd, FIONBIO, &mode) != NO_ERROR) { + closesocket(con->sd); + WSACleanup(); + return; + } + + // Bind socket + con->addr.sin6_family = AF_INET6; + con->addr.sin6_addr = in6addr_any; + con->addr.sin6_port = SWAP_ENDIAN_BIG(con->port); + + if (bind(con->sd, (struct sockaddr *) &con->addr, sizeof(con->addr)) == SOCKET_ERROR) { + closesocket(con->sd); + WSACleanup(); + return; + } +} + +#endif \ No newline at end of file diff --git a/platform/win32/SystemInfo.h b/platform/win32/SystemInfo.cpp similarity index 93% rename from platform/win32/SystemInfo.h rename to platform/win32/SystemInfo.cpp index c16b723..ce0f986 100644 --- a/platform/win32/SystemInfo.h +++ b/platform/win32/SystemInfo.cpp @@ -6,14 +6,15 @@ * @version 1.0.0 * @link https://jingga.app */ -#ifndef TOS_UTILS_SYSTEM_INFO_H -#define TOS_UTILS_SYSTEM_INFO_H +#ifndef TOS_PLATFORM_WIN32_SYSTEM_INFO_C +#define TOS_PLATFORM_WIN32_SYSTEM_INFO_C #include #include #include "../../stdlib/Types.h" #include "../../stdlib/simd/SIMD_Helper.h" #include "../../utils/StringUtils.h" +#include "../SystemInfo.h" #include #include @@ -93,15 +94,6 @@ uint16 system_country_code() return (local_name[3] << 8) | local_name[4]; } -struct CpuCacheInfo { - int32 level; - int32 size; - int32 ways; - int32 partitions; - int32 sets; - int32 line_size; -}; - void cache_info_get(int32 level, CpuCacheInfo* cache) { uint32 eax, ebx, ecx, edx; int32 type; @@ -133,12 +125,6 @@ void cache_info_get(int32 level, CpuCacheInfo* cache) { cache->size = cache->ways * cache->partitions * cache->line_size * cache->sets; } -// @todo add vendor name -struct MainboardInfo { - char name[64]; - char serial_number[64]; -}; - void mainboard_info_get(MainboardInfo* info) { info->name[63] = '\0'; info->serial_number[63] = '\0'; @@ -273,12 +259,6 @@ void mainboard_info_get(MainboardInfo* info) { CoUninitialize(); } -// @todo add ipv6 -struct NetworkInfo { - char slot[64]; - byte mac[8]; -}; - int network_info_get(NetworkInfo* info) { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { @@ -332,23 +312,6 @@ int network_info_get(NetworkInfo* info) { return i; } -struct SIMDInfo { - f32 sse; - int32 avx256; - int32 avx512; -}; - -struct CpuInfo { - char vendor[13]; - char brand[49]; - int32 model; - int32 family; - int32 mhz; - CpuCacheInfo cache[4]; - int32 page_size; - SIMDInfo simd; -}; - void cpu_info_get(CpuInfo* info) { int32 temp; info->simd.sse = (temp = max_sse_supported()) > 9 ? temp / 10.0f : temp; @@ -400,13 +363,6 @@ void cpu_info_get(CpuInfo* info) { RegCloseKey(hKey); } -struct OSInfo { - char vendor[16]; - char name[64]; - int32 major; - int32 minor; -}; - void os_info_get(OSInfo* info) { info->vendor[15] = '\0'; info->name[63] = '\0'; @@ -432,10 +388,6 @@ void os_info_get(OSInfo* info) { #endif } -struct RamInfo { - int32 memory; -}; - void ram_info_get(RamInfo* info) { MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); @@ -443,11 +395,6 @@ void ram_info_get(RamInfo* info) { info->memory = (int) (statex.ullTotalPhys / (1024 * 1024)); } -struct GpuInfo { - char name[64]; - int32 vram; -}; - uint32 gpu_info_get(GpuInfo* info) { IDXGIFactory *pFactory = NULL; IDXGIAdapter *pAdapter = NULL; @@ -479,13 +426,6 @@ uint32 gpu_info_get(GpuInfo* info) { return i; } -struct DisplayInfo { - char name[64]; - int32 width; - int32 height; - int32 hz; -}; - void display_info_get_primary(DisplayInfo* info) { DISPLAY_DEVICEA device; DEVMODEA mode; @@ -537,23 +477,6 @@ uint32 display_info_get(DisplayInfo* info) { return i; } -struct SystemInfo { - OSInfo os; - MainboardInfo mainboard; - - NetworkInfo network[4]; - int32 network_count; - - CpuInfo cpu; - RamInfo ram; - - GpuInfo gpu[2]; - int32 gpu_count; - - DisplayInfo display[6]; - int32 display_count; -}; - void system_info_render(char* buf, const SystemInfo* info) { const char avx512[8][12] = { "AVX-512F", diff --git a/thread/ThreadOSWrapper.h b/platform/win32/Thread.h similarity index 70% rename from thread/ThreadOSWrapper.h rename to platform/win32/Thread.h index d7d7909..cfaa262 100644 --- a/thread/ThreadOSWrapper.h +++ b/platform/win32/Thread.h @@ -6,22 +6,15 @@ * @version 1.0.0 * @link https://jingga.app */ -#ifndef TOS_THREADS_OS_WRAPPER_H -#define TOS_THREADS_OS_WRAPPER_H +#ifndef TOS_PLATFORM_WIN32_THREAD_H +#define TOS_PLATFORM_WIN32_THREAD_H #include #include "../stdlib/Types.h" -#include "ThreadOSDefines.h" +#include "ThreadDefines.h" -#ifdef _WIN32 - #include -#else - #include - #include -#endif - -#include "ThreadJob.h" +#include void ms_to_timespec(timespec *ts, uint32 ms) { @@ -29,12 +22,13 @@ void ms_to_timespec(timespec *ts, uint32 ms) return; } + // @todo replace time() with os specifc solution ts->tv_sec = (ms / 1000) + time(0); ts->tv_nsec = (ms % 1000) * 1000000; } #ifdef _WIN32 - int pthread_create(pthread_t* thread, void*, ThreadJobFunc start_routine, void* arg) + int32 pthread_create(pthread_t* thread, void*, ThreadJobFunc start_routine, void* arg) { if (thread == NULL || start_routine == NULL) { return 1; @@ -48,7 +42,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_join(pthread_t thread, void**) + int32 pthread_join(pthread_t thread, void**) { WaitForSingleObject(thread, INFINITE); CloseHandle(thread); @@ -56,14 +50,14 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_detach(pthread_t thread) + int32 pthread_detach(pthread_t thread) { CloseHandle(thread); return 0; } - int pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t*) + int32 pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t*) { if (mutex == NULL) { return 1; @@ -74,7 +68,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_mutex_destroy(pthread_mutex_t* mutex) + int32 pthread_mutex_destroy(pthread_mutex_t* mutex) { if (mutex == NULL) { return 1; @@ -85,7 +79,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_mutex_lock(pthread_mutex_t* mutex) + int32 pthread_mutex_lock(pthread_mutex_t* mutex) { if (mutex == NULL) { return 1; @@ -96,7 +90,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_mutex_unlock(pthread_mutex_t* mutex) + int32 pthread_mutex_unlock(pthread_mutex_t* mutex) { if (mutex == NULL) { return 1; @@ -107,7 +101,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t*) + int32 pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t*) { if (cond == NULL) { return 1; @@ -118,7 +112,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_cond_destroy(pthread_cond_t*) + int32 pthread_cond_destroy(pthread_cond_t*) { /* Windows does not have a destroy for conditionals */ return 0; @@ -135,7 +129,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return t < 0 ? 1 : t; } - int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* abstime) + int32 pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* abstime) { if (cond == NULL || mutex == NULL) { return 1; @@ -148,7 +142,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) + int32 pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) { if (cond == NULL || mutex == NULL) { return 1; @@ -157,7 +151,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return pthread_cond_timedwait(cond, mutex, NULL); } - int pthread_cond_signal(pthread_cond_t* cond) + int32 pthread_cond_signal(pthread_cond_t* cond) { if (cond == NULL) { return 1; @@ -168,7 +162,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_cond_broadcast(pthread_cond_t* cond) + int32 pthread_cond_broadcast(pthread_cond_t* cond) { if (cond == NULL) { return 1; @@ -179,7 +173,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t*) + int32 pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t*) { if (rwlock == NULL) { return 1; @@ -191,12 +185,12 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_rwlock_destroy(pthread_rwlock_t*) + int32 pthread_rwlock_destroy(pthread_rwlock_t*) { return 0; } - int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) + int32 pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) { if (rwlock == NULL) { return 1; @@ -207,7 +201,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) + int32 pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) { if (rwlock == NULL) { return 1; @@ -216,7 +210,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return !TryAcquireSRWLockShared(&rwlock->lock); } - int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) + int32 pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) { if (rwlock == NULL) { return 1; @@ -228,7 +222,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) + int32 pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) { if (rwlock == NULL) { return 1; @@ -242,7 +236,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return ret; } - int pthread_rwlock_unlock(pthread_rwlock_t* rwlock) + int32 pthread_rwlock_unlock(pthread_rwlock_t* rwlock) { if (rwlock == NULL) { return 1; @@ -258,7 +252,7 @@ void ms_to_timespec(timespec *ts, uint32 ms) return 0; } - unsigned int pcthread_get_num_procs() + uint32 pcthread_get_num_procs() { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); @@ -268,9 +262,9 @@ void ms_to_timespec(timespec *ts, uint32 ms) #define pthread_exit(a) {return (a);} #else - unsigned int pcthread_get_num_procs() + uint32 pcthread_get_num_procs() { - return (unsigned int) sysconf(_SC_NPROCESSORS_ONLN); + return (uint32) sysconf(_SC_NPROCESSORS_ONLN); } #endif diff --git a/platform/win32/ThreadDefines.h b/platform/win32/ThreadDefines.h new file mode 100644 index 0000000..6b00030 --- /dev/null +++ b/platform/win32/ThreadDefines.h @@ -0,0 +1,29 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_THREAD_DEFINES_H +#define TOS_PLATFORM_WIN32_THREAD_DEFINES_H + +#include + +typedef DWORD (WINAPI *ThreadJobFunc)(void*); +typedef CRITICAL_SECTION pthread_mutex_t; +typedef void pthread_mutexattr_t; +typedef void pthread_condattr_t; +typedef void pthread_rwlockattr_t; +typedef HANDLE pthread_t; +typedef CONDITION_VARIABLE pthread_cond_t; + +struct pthread_rwlock_t { + SRWLOCK lock; + bool exclusive; +}; + +#define THREAD_RETURN DWORD WINAPI + +#endif \ No newline at end of file diff --git a/platform/win32/UtilsWin32.h b/platform/win32/UtilsWin32.h index 44bf345..9879038 100644 --- a/platform/win32/UtilsWin32.h +++ b/platform/win32/UtilsWin32.h @@ -23,6 +23,7 @@ #include "../../memory/RingMemory.h" #define strtok_r strtok_s +#define usleep Sleep inline time_t system_time() @@ -46,7 +47,8 @@ time_t system_time() inline void relative_to_absolute(const char* rel, char* path) { char self_path[MAX_PATH]; - if (GetModuleFileNameA(NULL, self_path, MAX_PATH) == 0) { + int32 self_path_length = GetModuleFileNameA(NULL, self_path, MAX_PATH); + if (self_path_length == 0) { return; } @@ -55,14 +57,19 @@ inline void relative_to_absolute(const char* rel, char* path) temp += 2; } - char* last = strrchr(self_path, '\\'); - if (last != NULL) { - *(last + 1) = '\0'; + char* last = self_path + self_path_length; + while (*last != '\\' && self_path_length > 0) { + --last; + --self_path_length; } - snprintf(path, MAX_PATH, "%s%s", self_path, temp); + ++self_path_length; + + memcpy(path, self_path, self_path_length); + strcpy(path + self_path_length, temp); } +// @todo Move file code to FileUtils.h inline uint64 file_size(const char* path) { diff --git a/stdlib/HashMap.h b/stdlib/HashMap.h index 86ffd80..15a2e3c 100644 --- a/stdlib/HashMap.h +++ b/stdlib/HashMap.h @@ -336,7 +336,7 @@ void hashmap_insert(HashMap* hm, const char* key, byte* value) { } } -HashEntry* hashmap_get_entry(HashMap* hm, const char* key) { +HashEntry* hashmap_get_entry(const HashMap* hm, const char* key) { // @performance Do we really want to do this check every time? if (hm->buf.count == 0) { return NULL; @@ -358,7 +358,7 @@ HashEntry* hashmap_get_entry(HashMap* hm, const char* key) { // This function only saves one step (omission of the hash function) // The reason for this is in some cases we can use compile time hashing -HashEntry* hashmap_get_entry(HashMap* hm, const char* key, uint64 index) { +HashEntry* hashmap_get_entry(const HashMap* hm, const char* key, uint64 index) { if (hm->buf.count == 0) { return NULL; } diff --git a/stdlib/Intrinsics.h b/stdlib/Intrinsics.h index ee29ced..5e6d4ee 100644 --- a/stdlib/Intrinsics.h +++ b/stdlib/Intrinsics.h @@ -19,18 +19,16 @@ #include "Types.h" -/* -inline f32 sqrt(f32 a) { return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(a))); } -inline f64 sqrt(f64 a) +inline f32 oms_sqrt(f32 a) { return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(a))); } +inline f64 oms_sqrt(f64 a) { __m128d temp =_mm_set_sd(a); return _mm_cvtsd_f64(_mm_sqrt_sd(temp, temp)); } -*/ -inline f32 rsqrt(f32 a) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(a))); } -inline f64 rsqrt(f64 a) +inline f32 oms_rsqrt(f32 a) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(a))); } +inline f64 oms_rsqrt(f64 a) { __m128d temp =_mm_set_sd(a); @@ -42,7 +40,7 @@ inline f64 rsqrt(f64 a) ); } -inline f32 round(f32 a) +inline f32 oms_round(f32 a) { return _mm_cvtss_f32( _mm_round_ss(_mm_setzero_ps(), _mm_set_ss(a), (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC))); @@ -50,9 +48,9 @@ inline f32 round(f32 a) inline uint32 round_to_int(f32 a) { return (uint32) _mm_cvtss_si32(_mm_set_ss(a)); } -inline f32 floor(f32 a) { return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(a))); } +inline f32 oms_floor(f32 a) { return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(a))); } -inline f32 ceil(f32 a) { return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(a))); } +inline f32 oms_ceil(f32 a) { return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(a))); } inline uint32 hash(uint64 a, uint64 b = 0) { @@ -72,7 +70,7 @@ inline void atomic_increment(int32* a, int32 b) { } inline void atomic_increment(int64* a, int64 b) { - _aadd_i64(a, b); + _aadd_i64((long long int *) a, (long long int) b); } inline void atomic_decrement(int32* a, int32 b) { @@ -80,7 +78,7 @@ inline void atomic_decrement(int32* a, int32 b) { } inline void atomic_decrement(int64* a, int64 b) { - _aadd_i64(a, -b); + _aadd_i64((long long int *) a, (long long int) -b); } #endif \ No newline at end of file diff --git a/stdlib/Types.h b/stdlib/Types.h index b6c5c0c..23a4c69 100644 --- a/stdlib/Types.h +++ b/stdlib/Types.h @@ -11,6 +11,14 @@ #include +#ifdef _MSC_VER + #define PACKED_STRUCT __pragma(pack(push, 1)) + #define UNPACKED_STRUCT __pragma(pack(pop)) +#else + #define PACKED_STRUCT __attribute__((__packed__)) + #define UNPACKED_STRUCT +#endif + typedef int8_t int8; typedef int16_t int16; typedef int32_t int32; @@ -158,7 +166,17 @@ struct v3_f32 { struct v4_f32 { union { struct { - f32 x, y, z, w; + f32 x, y; + + union { + struct { + f32 z, w; + }; + + struct { + f32 width, height; + }; + }; }; struct { @@ -169,10 +187,6 @@ struct v4_f32 { f32 r, g, b, a; }; - struct { - f32 x, y, width, height; - }; - f32 vec[4]; }; }; diff --git a/stdlib/simd/SIMD_Helper.h b/stdlib/simd/SIMD_Helper.h index c333edf..7358125 100644 --- a/stdlib/simd/SIMD_Helper.h +++ b/stdlib/simd/SIMD_Helper.h @@ -18,6 +18,13 @@ #include #endif +enum SIMDVersion { + SIMD_VERSION_NONE, + SIMD_VERSION_128, + SIMD_VERSION_256, + SIMD_VERSION_512, +}; + // @todo implement for arm? inline int32 max_sse_supported() diff --git a/thread/Thread.h b/thread/Thread.h index 3faa8d2..3597c41 100644 --- a/thread/Thread.h +++ b/thread/Thread.h @@ -12,14 +12,14 @@ #include #include -#ifdef _WIN32 - #include -#else - #include - #include +#if _WIN32 + #include "../platform/win32/ThreadDefines.h" + #include "../platform/win32/Thread.h" +#elif __linux__ + #include "../platform/linux/ThreadDefines.h" + #include "../platform/linux/Thread.h" #endif -#include "ThreadOSWrapper.h" #include "ThreadJob.h" #include "ThreadPool.h" diff --git a/thread/ThreadJob.h b/thread/ThreadJob.h index 115b8f7..2be89f2 100644 --- a/thread/ThreadJob.h +++ b/thread/ThreadJob.h @@ -12,7 +12,11 @@ #include #include -#include "ThreadOSDefines.h" +#if _WIN32 + #include "../platform/win32/ThreadDefines.h" +#elif __linux__ + #include "../platform/linux/ThreadDefines.h" +#endif struct job_t { ThreadJobFunc func; diff --git a/thread/ThreadOSDefines.h b/thread/ThreadOSDefines.h deleted file mode 100644 index 8836dd6..0000000 --- a/thread/ThreadOSDefines.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Jingga - * - * @copyright Jingga - * @license OMS License 2.0 - * @version 1.0.0 - * @link https://jingga.app - */ -#ifndef TOS_THREADS_OS_DEFINES_H -#define TOS_THREADS_OS_DEFINES_H - -#if _WIN32 - #include - - typedef DWORD (WINAPI *ThreadJobFunc)(void*); - typedef CRITICAL_SECTION pthread_mutex_t; - typedef void pthread_mutexattr_t; - typedef void pthread_condattr_t; - typedef void pthread_rwlockattr_t; - typedef HANDLE pthread_t; - typedef CONDITION_VARIABLE pthread_cond_t; - - struct pthread_rwlock_t { - SRWLOCK lock; - bool exclusive; - }; -#else - #include - #include - typedef void * (*ThreadJobFunc)(void*); -#endif - -#endif \ No newline at end of file diff --git a/thread/ThreadPool.h b/thread/ThreadPool.h index 6247bc9..ff5bcdc 100644 --- a/thread/ThreadPool.h +++ b/thread/ThreadPool.h @@ -13,15 +13,19 @@ #include #ifdef _WIN32 - #include + #include "../platform/win32/Thread.h" #else - #include - #include + #include "../platform/linux/Thread.h" #endif #include "../stdlib/Types.h" #include "ThreadJob.h" -#include "ThreadOSWrapper.h" + +#if _WIN32 + +#elif __linux__ + #include "../platform/linux/Thread.h" +#endif struct ThreadPool { ThreadJob *work_first; diff --git a/ui/UITheme.h b/ui/UITheme.h index 0627b00..f80fc72 100644 --- a/ui/UITheme.h +++ b/ui/UITheme.h @@ -4,6 +4,7 @@ #include "../stdlib/Types.h" #include "../memory/RingMemory.h" #include "../utils/EndianUtils.h" +#include "../utils/StringUtils.h" #include "../stdlib/HashMap.h" #include "../font/Font.h" @@ -126,9 +127,7 @@ void theme_from_file_txt( int32 temp_group_count = 0; while (*pos != '\0') { // Skip all white spaces - while (*pos == ' ' || *pos == '\t' || *pos == '\n') { - ++pos; - } + char_skip_empty(&pos); // Is group name if (*pos == '#' || *pos == '.') { @@ -136,9 +135,7 @@ void theme_from_file_txt( } // Go to the end of the line - while (*pos != '\n' && *pos != '\0') { - ++pos; - } + char_move_to(&pos, '\n'); // Go to next line if (*pos != '\0') { @@ -157,9 +154,7 @@ void theme_from_file_txt( pos += 8; // move past version while (*pos != '\0') { - while (*pos == ' ' || *pos == '\t') { - ++pos; - } + char_skip_empty(&pos); if (*pos == '\n') { ++pos; @@ -178,14 +173,7 @@ void theme_from_file_txt( last_token_newline = false; if (!block_open) { - int32 i = 0; - while (*pos != '\0' && *pos != ' ' && *pos != '\n' && i < 31) { - block_name[i] = *pos; - ++pos; - ++i; - } - - block_name[i] = '\0'; + char_copy_move_until(&pos, block_name, " \n", sizeof(" \n") - 1); // All blocks need to start with #. In the past this wasn't the case and may not be in the future. This is why we keep this if here. if (*block_name == '#' || *block_name == '.') { @@ -210,19 +198,10 @@ void theme_from_file_txt( continue; } - int32 i = 0; - while (*pos != '\0' && *pos != ' ' && *pos != ':' && *pos != '\n' && i < 31) { - attribute_name[i] = *pos; - ++pos; - ++i; - } - - attribute_name[i] = '\0'; + char_copy_move_until(&pos, attribute_name, " :\n", sizeof(" :\n") - 1); // Skip any white spaces or other delimeters - while (*pos == ' ' || *pos == '\t' || *pos == ':') { - ++pos; - } + char_skip_list(&pos, " \t:", sizeof(" \t:") - 1); ASSERT_SIMPLE((*pos != '\0' && *pos != '\n')); @@ -232,12 +211,8 @@ void theme_from_file_txt( attribute.attribute_id = UI_ATTRIBUTE_TYPE_TYPE; char str[32]; - char* temp = str; - while (*pos != '\n' && *pos != '\0') { - *temp++ = *pos++; - } + char_copy_move_until(&pos, str, '\n'); - *temp = '\0'; for (int32 j = 0; j < UI_ELEMENT_TYPE_SIZE; ++j) { if (strcmp(str, ui_element_type_to_string_const((UIElementType) j)) == 0) { @@ -250,22 +225,12 @@ void theme_from_file_txt( } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_STYLE), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_STYLE; - char* temp = attribute.value_str; - while (*pos != '\n' && *pos != '\0') { - *temp++ = *pos++; - } - - *temp = '\0'; + char_copy_move_until(&pos, attribute.value_str, '\n'); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_FONT_COLOR), attribute_name) == 0) { ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_FONT_COLOR; - uint32 value = (uint32) strtoul(pos, &pos, 16); - - attribute.value_v4_f32.r = (f32) ((value >> 24) & 0xFF) / 255.0f; - attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f; - attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f; - attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f; + hexstr_to_rgba(&attribute.value_v4_f32, pos); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_FONT_SIZE), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_FONT_SIZE; attribute.value_float = strtof(pos, &pos); @@ -288,21 +253,11 @@ void theme_from_file_txt( ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR; - uint32 value = (uint32) strtoul(pos, &pos, 16); - - attribute.value_v4_f32.r = (f32) ((value >> 24) & 0xFF) / 255.0f; - attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f; - attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f; - attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f; + hexstr_to_rgba(&attribute.value_v4_f32, pos); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG; - i = 0; - while (*pos != '\0' && *pos != '\n') { - attribute.value_str[i] = *pos++; - } - - attribute.value_str[i] = '\0'; + char_copy_move_until(&pos, attribute.value_str, '\n'); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_OPACITY), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_OPACITY; attribute.value_float = SWAP_ENDIAN_LITTLE(strtof(pos, &pos)); @@ -319,12 +274,7 @@ void theme_from_file_txt( ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_COLOR; - uint32 value = (uint32) strtoul(pos, &pos, 16); - - attribute.value_v4_f32.r = (f32) ((value >> 24) & 0xFF) / 255.0f; - attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f; - attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f; - attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f; + hexstr_to_rgba(&attribute.value_v4_f32, pos); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_WIDTH), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_WIDTH; attribute.value_int = strtoul(pos, &pos, 10); @@ -332,12 +282,7 @@ void theme_from_file_txt( ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_TOP_COLOR; - uint32 value = (uint32) strtoul(pos, &pos, 16); - - attribute.value_v4_f32.r = (f32) ((value >> 24) & 0xFF) / 255.0f; - attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f; - attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f; - attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f; + hexstr_to_rgba(&attribute.value_v4_f32, pos); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_TOP_WIDTH), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_TOP_WIDTH; attribute.value_int = strtoul(pos, &pos, 10); @@ -345,12 +290,7 @@ void theme_from_file_txt( ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_RIGHT_COLOR; - uint32 value = (uint32) strtoul(pos, &pos, 16); - - attribute.value_v4_f32.r = (f32) ((value >> 24) & 0xFF) / 255.0f; - attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f; - attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f; - attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f; + hexstr_to_rgba(&attribute.value_v4_f32, pos); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_RIGHT_WIDTH), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_RIGHT_WIDTH; attribute.value_int = strtoul(pos, &pos, 10); @@ -358,12 +298,7 @@ void theme_from_file_txt( ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_COLOR; - uint32 value = (uint32) strtoul(pos, &pos, 16); - - attribute.value_v4_f32.r = (f32) ((value >> 24) & 0xFF) / 255.0f; - attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f; - attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f; - attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f; + hexstr_to_rgba(&attribute.value_v4_f32, pos); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_WIDTH), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_WIDTH; attribute.value_int = strtoul(pos, &pos, 10); @@ -371,12 +306,7 @@ void theme_from_file_txt( ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_LEFT_COLOR; - uint32 value = (uint32) strtoul(pos, &pos, 16); - - attribute.value_v4_f32.r = (f32) ((value >> 24) & 0xFF) / 255.0f; - attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f; - attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f; - attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f; + hexstr_to_rgba(&attribute.value_v4_f32, pos); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_LEFT_WIDTH), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_LEFT_WIDTH; attribute.value_int = strtoul(pos, &pos, 10); @@ -399,12 +329,7 @@ void theme_from_file_txt( ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_INNER_COLOR; - uint32 value = (uint32) strtoul(pos, &pos, 16); - - attribute.value_v4_f32.r = (f32) ((value >> 24) & 0xFF) / 255.0f; - attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f; - attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f; - attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f; + hexstr_to_rgba(&attribute.value_v4_f32, pos); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_INNER_ANGLE), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_INNER_ANGLE; attribute.value_float = strtof(pos, &pos); @@ -415,12 +340,7 @@ void theme_from_file_txt( ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_OUTER_COLOR; - uint32 value = (uint32) strtoul(pos, &pos, 16); - - attribute.value_v4_f32.r = (f32) ((value >> 24) & 0xFF) / 255.0f; - attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f; - attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f; - attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f; + hexstr_to_rgba(&attribute.value_v4_f32, pos); } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_ANGLE), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_OUTER_ANGLE; attribute.value_float = strtof(pos, &pos); @@ -434,9 +354,7 @@ void theme_from_file_txt( attribute.attribute_id = UI_ATTRIBUTE_TYPE_TRANSITION_DURATION; attribute.value_float = strtof(pos, &pos); } else { - while (*pos != '\n' && *pos != '\0') { - ++pos; - } + char_move_to(&pos, '\n'); continue; } @@ -453,6 +371,8 @@ void theme_from_file_txt( data_offset += sizeof(attribute); ++temp_group->attribute_size; } + + char_move_to(&pos, '\n'); } // We still need to sort the last group diff --git a/utils/BitUtils.h b/utils/BitUtils.h index bac7988..4f595d4 100644 --- a/utils/BitUtils.h +++ b/utils/BitUtils.h @@ -9,7 +9,7 @@ #ifndef TOS_UTILS_BIT_H #define TOS_UTILS_BIT_H -#include +//#include #include "../stdlib/Types.h" // @todo Replace many of these functions with intrinsic functions diff --git a/utils/StringUtils.h b/utils/StringUtils.h index 0fb32e9..616b09f 100644 --- a/utils/StringUtils.h +++ b/utils/StringUtils.h @@ -435,7 +435,7 @@ void print_bytes(const void* ptr, size_t size) for (size_t i = 0; i < size; i++) { ++count; if (count == 1) { - printf("%03lld - %03lld: %02x ", i + 1, i + 8, bytePtr[i]); + printf("%03zd - %03zd: %02x ", i + 1, i + 8, bytePtr[i]); } else if (count < 8) { printf("%02x ", bytePtr[i]); } else { @@ -474,6 +474,177 @@ int32 chars_to_eol(const char* str) return offset; } +inline +int32 chars_to(const char* str, char delim) +{ + int32 offset = 0; + while (*str != delim && *str++ != '\0') { + ++offset; + } + + return offset; +} + +inline +void char_move_to(char** str, const char delim) +{ + while (**str != delim && **str != '\0') { + ++(*str); + } +} + +inline +void char_move_past(char** str, const char delim) +{ + while (**str != delim && **str != '\0') { + ++(*str); + } + + if (**str == delim) { + ++(*str); + } +} + +inline +void char_move_past_alpha_num(char** str) +{ + while ((**str >= 48 && **str <= 57) + || (**str >= 65 && **str <= 90) + || (**str >= 97 && **str <= 122) + || **str == 45 || **str == 95 + ) { + ++(*str); + } +} + +inline +bool str_is_comment(char* str) +{ + return (*str == '/' && str[1] == '/') || (*str == '/' && str[1] == '*'); +} + +inline +void char_skip(char** str, const char delim) +{ + while (**str == delim) { + ++(*str); + } +} + +inline +void char_skip_whitespace(char** str) +{ + while (**str == ' ' || **str == '\t') { + ++(*str); + } +} + +inline +void char_skip_empty(char** str) +{ + while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\r') { + ++(*str); + } +} + +inline +void char_skip_non_empty(char** str) +{ + while (**str != ' ' && **str != '\t' && **str != '\n' && **str != '\0') { + ++(*str); + } +} + +inline +void char_skip_list(char** __restrict str, const char* __restrict delim, int32 len) +{ + bool run = true; + while (run && **str != '\0') { + run = false; + + for (int32 i = 0; i < len; ++i) { + if (**str == delim[i]) { + run = true; + ++(*str); + + break; + } + } + } +} + +inline +void char_skip_until_list(char** __restrict str, const char* __restrict delim, int32 len) +{ + while (**str != '\0') { + for (int32 i = 0; i < len; ++i) { + if (**str == delim[i]) { + return; + } + } + + ++(*str); + } +} + +inline +void char_copy_until(const char* __restrict src, char* __restrict dest, char delim) +{ + while (*src != delim && *src != '\0') { + *dest++ = *src++; + } + + *dest = '\0'; +} + +inline +void char_copy_until(const char* __restrict src, char* __restrict dest, const char* __restrict delim, int32 len) +{ + while (*src != '\0') { + for (int32 i = 0; i < len; ++i) { + if (*src == delim[i]) { + *dest = '\0'; + return; + } + } + + *dest++ = *src++; + } + + *dest = '\0'; +} + +inline +void char_copy_move_until(char** __restrict src, char* __restrict dest, char delim) +{ + while (**src != delim) { + *dest++ = **src; + ++(*src); + } + + *dest = '\0'; +} + +inline +void char_copy_move_until(char** __restrict src, char* __restrict dest, const char* __restrict delim, int32 len) +{ + while (**src != '\0') { + for (int32 i = 0; i < len; ++i) { + if (**src == delim[i]) { + *dest = '\0'; + return; + } + } + + *dest++ = **src; + ++(*src); + } + + *dest = '\0'; +} + +// @question Do we really need this, isn't char_copy_move_until better? +// Maybe create a copy_move_until_eol inline int32 strcpy_to_eol(const char* src, char* dst) { @@ -488,4 +659,18 @@ int32 strcpy_to_eol(const char* src, char* dst) return offset; } +inline +void hexstr_to_rgba(v4_f32* rgba, const char* hex) +{ + if (*hex == '#') { + ++hex; + } + + uint32 value = (uint32) strtoul(hex, NULL, 16); + rgba->r = (f32) ((value >> 24) & 0xFF) / 255.0f; + rgba->g = (f32) ((value >> 16) & 0xFF) / 255.0f; + rgba->b = (f32) ((value >> 8) & 0xFF) / 255.0f; + rgba->a = (f32) (value & 0xFF) / 255.0f; +} + #endif \ No newline at end of file