diff --git a/compression/Huffman.h b/compression/Huffman.h index bb84d0f..a686597 100644 --- a/compression/Huffman.h +++ b/compression/Huffman.h @@ -98,7 +98,7 @@ int64 huffman_code_build(Huffman* hf, HuffmanNode* root, char* code, int32 lengt { if (root->character) { code[length] = 0; - strcpy(&code_buffer[*buffer_position], code); + memcpy(&code_buffer[*buffer_position], code, length + 1); hf->code[root->character] = &code_buffer[*buffer_position]; *buffer_position += length + 1; diff --git a/font/Font.h b/font/Font.h index 879b8f0..e20802f 100644 --- a/font/Font.h +++ b/font/Font.h @@ -7,6 +7,12 @@ #include "../utils/Utils.h" #include "../stdlib/simd/SIMD_I32.h" +#if _WIN32 + #include "../platform/win32/UtilsWin32.h" +#else + #include "../platform/linux/UtilsLinux.h" +#endif + struct GlyphMetrics { f32 width; // Width of the glyph f32 height; // Height of the glyph @@ -57,15 +63,11 @@ Glyph* font_glyph_find(Font* font, uint32 codepoint) } void font_from_file_txt( - RingMemory* ring, - const char* path, - Font* font + Font* font, + byte* data ) { - FileBody file; - file_read(path, &file, ring); - - char* pos = (char *) file.content; + char* pos = (char *) data; bool start = true; char block_name[32]; @@ -87,6 +89,8 @@ void font_from_file_txt( ++i; } + block_name[i] = '\0'; + // Go to value while (*pos == ' ' || *pos == '\t' || *pos == ':') { ++pos; @@ -94,7 +98,7 @@ void font_from_file_txt( if (strcmp(block_name, "texture") == 0) { while (*pos != '\n') { - *texture_pos++ == *pos++; + *texture_pos++ = *pos++; } } else if (strcmp(block_name, "font_size") == 0) { font->size = strtof(pos, &pos); @@ -111,8 +115,7 @@ void font_from_file_txt( } // Go to next line - while (*pos++ != '\n') {}; - ++pos; + while (*pos != '\0' && *pos++ != '\n') {}; } else { // Parsing glyphs // In the text file we don't have to define width and height of the character, we calculate that here diff --git a/gpuapi/RenderUtils.h b/gpuapi/RenderUtils.h index 8cf10cb..52398ad 100644 --- a/gpuapi/RenderUtils.h +++ b/gpuapi/RenderUtils.h @@ -449,7 +449,8 @@ f32 ui_text_create( ) { if (element->vertex_count > 0) { memcpy(vertices + *index, element->vertices, sizeof(Vertex3DTextureColorIndex) * element->vertex_count); - return; + + return vertices[element->vertex_count - 1].position.x; } // @performance see comment for setup_theme() diff --git a/gpuapi/opengl/OpenglWin32.h b/gpuapi/opengl/OpenglWin32.h index b9a5dde..1986c17 100644 --- a/gpuapi/opengl/OpenglWin32.h +++ b/gpuapi/opengl/OpenglWin32.h @@ -13,6 +13,10 @@ #include "../../platform/win32/Window.h" #include "../../stdlib/Types.h" +#ifdef _MSC_VER + #pragma comment(lib, "OpenGL32.Lib") +#endif + typedef unsigned int GLenum; typedef unsigned char GLboolean; typedef unsigned int GLbitfield; diff --git a/localization/Language.h b/localization/Language.h index ccccc6f..4e58997 100644 --- a/localization/Language.h +++ b/localization/Language.h @@ -19,41 +19,37 @@ struct Language { }; void language_from_file_txt( - RingMemory* ring, - const char* path, - Language* language + Language* language, + byte* data ) { - FileBody file; - file.size = file_size(path); - file.content = ring_get_memory(ring, file.size); - - file_read(path, &file); - // count elements language->count = 1; - for (int32 i = 0; i < file.size - 1; ++i) { - if (file.content[i] == '\n' && file.content[i + 1] == '\n') { + int64 len = 0; + + while (data[len] != '\0') { + if (data[len] == '\n' && data[len + 1] == '\n') { ++language->count; - file.content[i] = '\0'; - ++i; + data[len] = '\0'; + ++len; } + + ++len; } language->lang = (char **) language->data; - memcpy(language->data + language->count * sizeof(char *), file.content, file.size); + memcpy(language->data + language->count * sizeof(char *), data, len); // First element = 0 - *language->lang = (char *) file.content; - ++language->lang; + char** pos = language->lang; + *pos++ = (char *) data; - for (int32 i = 1; i < file.size - 1; ++i) { - if (file.content[i] == '\0') { + for (int32 i = 1; i < len - 1; ++i) { + if (data[i] == '\0') { // We have to move by 2 since every text element is separated by 2 \n // 1 \n is a valid char for a single text element // @performance This also means that we have one additional byte for // every text element even in the binary version. - *language->lang = (char *) &file.content[i + 2]; - ++language->lang; + *pos++ = (char *) &data[i + 2]; } } } @@ -62,14 +58,8 @@ void language_from_file_txt( // offsets for start of strings // actual string data void language_from_file( - const char* path, Language* language ) { - FileBody file; - file.content = language->data; - - file_read(path, &file); - byte* pos = language->data; // Count @@ -77,13 +67,13 @@ void language_from_file( pos += sizeof(language->count); language->lang = (char **) pos; + char** pos_lang = language->lang; byte* start = pos; // Load pointers/offsets for (int32 i = 0; i < language->count; ++i) { - *language->lang = (char *) (start + SWAP_ENDIAN_LITTLE(*((uint64 *) pos))); - ++language->lang; + *pos_lang++ = (char *) (start + SWAP_ENDIAN_LITTLE(*((uint64 *) pos))); pos += sizeof(uint64); } @@ -117,10 +107,15 @@ void language_to_file( pos += sizeof(uint64); } + int64 len_total = 0; + // Save actual strings + int64 len; for (int32 i = 0; i < language->count; ++i) { - strcpy((char *) pos, language->lang[i]); - pos += strlen(language->lang[i]); + len = strlen(language->lang[i]); + len_total += len; + memcpy((char *) pos, language->lang[i], len + 1); + pos += len; } file.size = pos - file.content; diff --git a/log/Debug.cpp b/log/Debug.cpp index fbeac26..347d390 100644 --- a/log/Debug.cpp +++ b/log/Debug.cpp @@ -6,6 +6,8 @@ #include "Log.h" #include "TimingStat.h" +global_persist DebugContainer* debug_container = NULL; + #if _WIN32 #include void setup_performance_count() { @@ -63,7 +65,7 @@ DebugMemory* debug_memory_find(uint64 start, uint64 size) void debug_memory_init(uint64 start, uint64 size) { - if (!start) { + if (!start || !debug_container) { return; } @@ -93,7 +95,7 @@ void debug_memory_init(uint64 start, uint64 size) void debug_memory_write(uint64 start, uint64 size, const char* function) { - if (!start) { + if (!start || !debug_container) { return; } @@ -120,7 +122,7 @@ void debug_memory_write(uint64 start, uint64 size, const char* function) void debug_memory_read(uint64 start, uint64 size, const char* function) { - if (!start) { + if (!start || !debug_container) { return; } @@ -146,6 +148,10 @@ void debug_memory_read(uint64 start, uint64 size, const char* function) void debug_memory_delete(uint64 start, uint64 size, const char* function) { + if (!debug_container) { + return; + } + DebugMemory* mem = debug_memory_find(start, size); if (!mem) { return; @@ -170,6 +176,10 @@ void debug_memory_delete(uint64 start, uint64 size, const char* function) inline void debug_memory_reset() { + if (!debug_container) { + return; + } + uint64 time = __rdtsc() - 1000000000; for (int32 i = 0; i < debug_container->dmc.memory_element_idx; ++i) { @@ -183,6 +193,10 @@ void debug_memory_reset() byte* log_get_memory(uint64 size, byte aligned = 1, bool zeroed = false) { + if (!debug_container) { + return 0; + } + ASSERT_SIMPLE(size <= debug_container->log_memory.size); if (aligned > 1) { @@ -214,7 +228,7 @@ byte* log_get_memory(uint64 size, byte aligned = 1, bool zeroed = false) void log_to_file() { // we don't log an empty log pool - if (debug_container->log_memory.pos == 0 || !debug_container->log_fp || debug_container->log_fp == INVALID_HANDLE_VALUE) { + if (!debug_container || debug_container->log_memory.pos == 0 || !debug_container->log_fp || debug_container->log_fp == INVALID_HANDLE_VALUE) { return; } @@ -233,7 +247,7 @@ byte* log_get_memory(uint64 size, byte aligned = 1, bool zeroed = false) // @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) { + if (!should_log || !debug_container) { return; } @@ -241,8 +255,7 @@ byte* log_get_memory(uint64 size, byte aligned = 1, bool zeroed = false) ASSERT_SIMPLE(length < MAX_LOG_LENGTH); char* temp = (char *) log_get_memory(length + 1); - strcpy(temp, str); - temp[length] = '\0'; + memcpy(temp, str, length + 1); if (save || debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) { log_to_file(); @@ -251,7 +264,7 @@ byte* log_get_memory(uint64 size, byte aligned = 1, bool zeroed = 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) { + if (!should_log || !debug_container) { return; } diff --git a/memory/BufferMemory.h b/memory/BufferMemory.h index d1c6d7a..0643d9a 100644 --- a/memory/BufferMemory.h +++ b/memory/BufferMemory.h @@ -39,6 +39,8 @@ void buffer_alloc(BufferMemory* buf, uint64 size, int32 alignment = 64) buf->element_alignment = 0; buf->size = size; + memset(buf->memory, 0, buf->size); + DEBUG_MEMORY_INIT((uint64) buf->memory, size); } diff --git a/memory/ChunkMemory.h b/memory/ChunkMemory.h index 3d49ac6..a8f6291 100644 --- a/memory/ChunkMemory.h +++ b/memory/ChunkMemory.h @@ -46,6 +46,8 @@ void chunk_alloc(ChunkMemory* buf, uint64 count, uint64 chunk_size, int32 alignm // @question Could it be beneficial to have this before the element data? buf->free = (uint64 *) (buf->memory + count * chunk_size); + memset(buf->memory, 0, buf->size); + DEBUG_MEMORY_INIT((uint64) buf->memory, buf->size); } @@ -118,7 +120,7 @@ void chunk_reserve_index(ChunkMemory* buf, int64 index, int64 elements = 1, bool int64 chunk_reserve(ChunkMemory* buf, uint64 elements = 1, bool zeroed = false) { - int64 byte_index = (buf->last_pos + 1) / 64; + int64 free_index = (buf->last_pos + 1) / 64; int32 bit_index; int64 free_element = -1; @@ -130,31 +132,33 @@ int64 chunk_reserve(ChunkMemory* buf, uint64 elements = 1, bool zeroed = false) while (free_element < 0 && i < buf->count) { ++i; - if (byte_index >= max_bytes) { - byte_index = 0; + if (free_index >= max_bytes) { + free_index = 0; } - if (buf->free[byte_index] == 0xFF) { - ++byte_index; + if (buf->free[free_index] == 0xFF) { + ++free_index; continue; } - // @performance There is some redundancy happening down below, we should ++byte_index in certain conditions? + // @performance There is some redundancy happening down below, we should ++free_index in certain conditions? for (bit_index = 0; bit_index < 64; ++bit_index) { int32 consecutive_free_bits = 0; // Check if there are 'elements' consecutive free bits for (int32 j = 0; j < elements; ++j) { - uint64 current_byte_index = byte_index + (bit_index + j) / 64; - int32 current_bit_index = (bit_index + j) % 64; - - if (current_byte_index >= (buf->count + 7) / 64) { + // Check if there is enough space until the end of the buffer. + // Remember, the last free index may only allow only 1 bit if the size is 65 + if (free_index * 64 + (bit_index + j) >= buf->count) { break; } + uint64 current_free_index = free_index + (bit_index + j) / 64; + int32 current_bit_index = (bit_index + j) % 64; + mask = 1 << current_bit_index; - if ((buf->free[current_byte_index] & mask) == 0) { + if ((buf->free[current_free_index] & mask) == 0) { ++consecutive_free_bits; } else { break; @@ -162,13 +166,13 @@ int64 chunk_reserve(ChunkMemory* buf, uint64 elements = 1, bool zeroed = false) } if (consecutive_free_bits == elements) { - free_element = byte_index * 64 + bit_index; + free_element = free_index * 64 + bit_index; // Mark the bits as reserved for (int32 j = 0; j < elements; ++j) { - int64 current_byte_index = byte_index + (bit_index + j) / 64; + int64 current_free_index = free_index + (bit_index + j) / 64; int32 current_bit_index = (bit_index + j) % 64; - buf->free[current_byte_index] |= (1LL << current_bit_index); + buf->free[current_free_index] |= (1LL << current_bit_index); } break; @@ -176,10 +180,11 @@ int64 chunk_reserve(ChunkMemory* buf, uint64 elements = 1, bool zeroed = false) } ++i; - ++byte_index; + ++free_index; } if (free_element < 0) { + ASSERT_SIMPLE(false); return -1; } @@ -309,6 +314,8 @@ int64 chunk_load(ChunkMemory* buf, const byte* data) data += buf->size; buf->free = (uint64 *) (buf->memory + buf->count * buf->chunk_size); + + return buf->size; } #endif \ No newline at end of file diff --git a/memory/RingMemory.h b/memory/RingMemory.h index 34408e6..57a3d7a 100644 --- a/memory/RingMemory.h +++ b/memory/RingMemory.h @@ -54,6 +54,8 @@ void ring_alloc(RingMemory* ring, uint64 size, int32 alignment = 64) ring->start = 0; ring->end = 0; + memset(ring->memory, 0, ring->size); + DEBUG_MEMORY_INIT((uint64) ring->memory, ring->size); } @@ -69,6 +71,8 @@ void ring_init(RingMemory* ring, BufferMemory* buf, uint64 size, int32 alignment ring->start = 0; ring->end = 0; + memset(ring->memory, 0, buf->size); + DEBUG_MEMORY_INIT((uint64) ring->memory, ring->size); } @@ -85,6 +89,8 @@ void ring_init(RingMemory* ring, byte* buf, uint64 size, int32 alignment = 64) ring->start = 0; ring->end = 0; + memset(ring->memory, 0, ring->size); + DEBUG_MEMORY_INIT((uint64) ring->memory, ring->size); } diff --git a/models/settings/Settings.h b/models/settings/Settings.h index 4a9bc08..fe2c52b 100644 --- a/models/settings/Settings.h +++ b/models/settings/Settings.h @@ -243,6 +243,8 @@ struct CSettings { // UI settings // Themes + char game_language[2]; + char game_ui_theme[32]; byte game_ui_size = 128; diff --git a/network/packet/UDPPacket.h b/network/packet/UDPPacket.h index 0822e3f..5c8f6f5 100644 --- a/network/packet/UDPPacket.h +++ b/network/packet/UDPPacket.h @@ -69,14 +69,14 @@ void message_to_udp_packet(const UDPMessageIPv6* message, UDPPacketIPv6* packet) inline void decompress_data(UDPMessageIPv6* message, byte* decompress_buffer) { - decode_lzp(message->data, message->length, decompress_buffer); + lzp_decode(message->data, message->length, decompress_buffer); message->data = decompress_buffer; } inline void compress_data(UDPMessageIPv6* message, byte* compressed_buffer) { - encode_lzp(message->data, message->length, compressed_buffer); + lzp_encode(message->data, message->length, compressed_buffer); message->data = compressed_buffer; } diff --git a/object/Mesh.h b/object/Mesh.h index bc8c222..7fcb7b4 100644 --- a/object/Mesh.h +++ b/object/Mesh.h @@ -13,7 +13,17 @@ #include "FaceType.h" #include "../stdlib/Types.h" +#if _WIN32 + #include "../platform/win32/UtilsWin32.h" +#else + #include "../platform/linux/UtilsLinux.h" +#endif + #include "../memory/RingMemory.h" +#include "../stdlib/simd/SIMD_I32.h" +#include "../utils/EndianUtils.h" + +#define MESH_VERSION 1 // @todo how to handle different objects and groups? // maybe make a mesh hold other meshes? @@ -81,4 +91,933 @@ struct Mesh { Mesh* meshes; }; +// @todo also handle textures etc. +// WARNING: mesh needs to have memory already reserved and asigned to data +void mesh_from_file_txt( + Mesh* mesh, + byte* data +) { + char* pos = (char *) data; + + // move past the version string + pos += 8; + + mesh->version = strtol(pos, &pos, 10); ++pos; + + int32 object_index = 0; + int32 group_index = 0; + + mesh->vertices = (f32 *) mesh->data; + + mesh->vertex_count = 0; + mesh->normal_count = 0; + mesh->tex_coord_count = 0; + mesh->color_count = 0; + + mesh->face_count = 0; + mesh->face_normal_count = 0; + mesh->face_tex_coord_count = 0; + mesh->face_color_count = 0; + + uint32 temp_color_count = 0; + + while (*pos != '\0') { + while (*pos == ' ' || *pos == '\t' || *pos == '\n') { + ++pos; + } + + if (*pos == '\0') { + break; + } + + // Parse type + // WARNING: The code below could fail if [1] is outside of range + // However that should never happen for well formed files + int32 state = 0; + if (*pos == 'v' && pos[1] == ' ') { + state = 1; + } else if (*pos == 'v' && pos[1] == 'n') { + state = 2; + } else if (*pos == 'v' && pos[1] == 't') { + state = 3; + } else if (*pos == 'v' && pos[1] == 'p') { + state = 4; + } else if (*pos == 'o' && pos[1] == ' ') { + state = 5; + } else if (*pos == 's' && pos[1] == ' ') { + state = 6; + } else if (*pos == 'f' && pos[1] == ' ') { + state = 7; + } else if (*pos == 'g' && pos[1] == ' ') { + state = 8; + } else if (*pos == 'l' && pos[1] == ' ') { + state = 9; + } else if (*pos == 'm' && pos[1] == 't') { + state = 10; + } else if (*pos == 'h' && pos[1] == 'i') { + state = 11; + } else if (*pos == 'a' && pos[1] == 'n') { + state = 12; + } else if (*pos == 'u' && pos[3] == 'm') { + state = 13; + } else if (*pos == 'u' && pos[3] == 'h') { + state = 14; + } else { + // not supported or comment + while (*pos != '\n' && *pos != '\0') { + ++pos; + } + } + + // move past keyword + while (*pos != ' ' && *pos != '\n' && *pos != '\0') { + ++pos; + } + + // move past whitespaces and newline + bool is_next_line = false; + while (*pos == ' ' || *pos == '\n') { + is_next_line |= *pos == '\n'; + ++pos; + } + + if (*pos == '\0' || is_next_line) { + continue; + } + + // NOTE: we always load a file in the format: POSITON + NORMAL + TEXTURE + COLOR + // EVEN if some of the data is missing. This is necessary to keep the memory kinda in line. + // The actual binary file later will have the minimized layout. + + // handle data types + switch (state) { + case 0: break; + case 1: { + // 'v' + if (mesh->vertex_count == 0) { + mesh->vertex_type |= VERTEX_TYPE_POSITION; + } + + mesh->vertices[mesh->vertex_count * 3] = strtof(pos, &pos); ++pos; + mesh->vertices[mesh->vertex_count * 3 + 1] = strtof(pos, &pos); ++pos; + mesh->vertices[mesh->vertex_count * 3 + 2] = strtof(pos, &pos); ++pos; + + // has color information + // @todo Move to own case statement // 'co' + if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { + if (mesh->vertex_count == 0) { + mesh->vertex_type |= VERTEX_TYPE_COLOR; + } + + mesh->vertices[mesh->vertex_count * 12 + 8] = strtof(pos, &pos); ++pos; + mesh->vertices[mesh->vertex_count * 12 + 9] = strtof(pos, &pos); ++pos; + mesh->vertices[mesh->vertex_count * 12 + 10] = strtof(pos, &pos); ++pos; + + // handle optional alpha [a] + if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { + mesh->vertices[mesh->vertex_count * 12 + 11] = strtof(pos, &pos); ++pos; + } else { + mesh->vertices[mesh->vertex_count * 12 + 11] = 1.0f; + } + + ++temp_color_count; + } + + ++mesh->vertex_count; + } break; + case 2: { + // 'vn' + // @bug This requires normals to be defined before textures + if (mesh->normal_count == 0) { + mesh->normals = mesh->vertices + mesh->vertex_count * 3; + } + + mesh->normals[mesh->normal_count * 3] = strtof(pos, &pos); ++pos; + mesh->normals[mesh->normal_count * 3 + 1] = strtof(pos, &pos); ++pos; + mesh->normals[mesh->normal_count * 3 + 2] = strtof(pos, &pos); ++pos; + + ++mesh->normal_count; + } break; + case 3: { + // 'vt' + if (mesh->tex_coord_count == 0) { + mesh->tex_coords = mesh->vertices + mesh->vertex_count * 3 + mesh->normal_count * 3; + } + + mesh->tex_coords[mesh->tex_coord_count * 2] = strtof(pos, &pos); ++pos; + mesh->tex_coords[mesh->tex_coord_count * 2 + 1] = strtof(pos, &pos); ++pos; + + ++mesh->tex_coord_count; + } break; + case 4: { + // 'vp' + strtof(pos, &pos); ++pos; + + // handle optional [v] + if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { + strtof(pos, &pos); ++pos; + + // handle optional [w] + if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { + strtof(pos, &pos); ++pos; + } + } + } break; + case 5: { + // 'o' + char text[100]; + int32 i = 0; + while (*pos != '\0' && *pos != ' ') { + text[i++] = *pos++; + } + text[i] = '\0'; + + ++object_index; + } break; + case 6: { + // 's' + strtol(pos, &pos, 10); ++pos; + } break; + case 7: { + // 'f' + if (mesh->face_count == 0) { + mesh->faces = (uint32 *) (mesh->vertices + mesh->vertex_count * 3 + mesh->normal_count * 3 + mesh->tex_coord_count * 2 + mesh->color_count * 4); + } + + int32 ftype = 0; + char* tmp = pos; + while (*tmp != ' ') { + if (*tmp++ == '/') { + ++ftype; + + if (*tmp++ == '/') { + ftype = 3; + break; + } + } + } + + const int32 max_blocks = 3; // @todo this could actually be N. Might have to change in the future + int32 block = 0; + + while (*pos != '\0' && *pos != '\n') { + if (ftype == 0) { + // v1 v2 v3 ... + if (mesh->face_count == 0) { + mesh->face_type = FACE_TYPE_VERTICES; + } + + mesh->faces[(mesh->face_count * max_blocks * 1) + block] = strtol(pos, &pos, 10) - 1; ++pos; + } else if (ftype == 1) { + // v1/vt1 v2/vt2 v3/vt3 ... + if (mesh->face_count == 0) { + mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_TEXTURES; + } + + mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; + mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; + } else if (ftype == 2) { + // v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ... + if (mesh->face_count == 0) { + mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_TEXTURES | FACE_TYPE_NORMALS; + } + + mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3] = strtol(pos, &pos, 10) - 1; ++pos; + mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3 + 1] = strtol(pos, &pos, 10) - 1; ++pos; + mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3 + 2] = strtol(pos, &pos, 10) - 1; ++pos; + } else if (ftype == 3) { + // v1//vn1 v2//vn2 v3//vn3 ... + if (mesh->face_count == 0) { + mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_NORMALS; + } + + mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; + ++pos; + mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; + } + + ++block; + } + + ++mesh->face_count; + } break; + case 8: { + // 'g' + char text[100]; + int32 i = 0; + while (*pos != '\0' && *pos != ' ') { + text[i++] = *pos++; + } + text[i] = '\0'; + + ++group_index; + } break; + case 9: { + //l + while (*pos != '\0' && *pos != '\n') { + strtol(pos, &pos, 10); ++pos; + } + } break; + case 10: { + // 'mtllib' + char text[100]; + int32 i = 0; + while (*pos != '\0' && *pos != ' ') { + text[i++] = *pos++; + } + text[i] = '\0'; + } break; + case 11: { + // 'hitlib' + char text[100]; + int32 i = 0; + while (*pos != '\0' && *pos != ' ') { + text[i++] = *pos++; + } + text[i] = '\0'; + } break; + case 12: { + // 'anilib' + char text[100]; + int32 i = 0; + while (*pos != '\0' && *pos != ' ') { + text[i++] = *pos++; + } + text[i] = '\0'; + } break; + case 13: { + // 'usemtl' + char text[100]; + int32 i = 0; + while (*pos != '\0' && *pos != ' ') { + text[i++] = *pos++; + } + text[i] = '\0'; + } break; + case 14: { + // 'usehit' + char text[100]; + int32 i = 0; + while (*pos != '\0' && *pos != ' ') { + text[i++] = *pos++; + } + text[i] = '\0'; + } break; + } + } +} + +enum ObjectLoadingRestriction { + OBJECT_LOADING_RESTRICTION_POSITION = 1, + OBJECT_LOADING_RESTRICTION_NORMAL = 2, + OBJECT_LOADING_RESTRICTION_TEXTURE = 4, + OBJECT_LOADING_RESTRICTION_COLOR = 8, + OBJECT_LOADING_RESTRICTION_FACES = 16, + OBJECT_LOADING_RESTRICTION_EVERYTHING = 31 +}; + +// @todo sometimes we don't care about some data, we should have an option which defines which data should be loaded +// this can improve performance for algorithms on this. e.g.: +// on the server side we only care about the vertex positions for collision (no normals, no color, ...) +int32 mesh_from_file( + RingMemory* ring, + const char* path, + Mesh* mesh, + const char* group = NULL, + int32 load_format = OBJECT_LOADING_RESTRICTION_EVERYTHING, + int32 size = 8 +) +{ + FileBody file; + file_read(path, &file, ring); + + byte* pos = file.content; + + // Read version + mesh->version = *((int32 *) pos); + pos += sizeof(mesh->version); + + // Read base data + mesh->vertex_type = *((int32 *) pos); + pos += sizeof(mesh->vertex_type); + + mesh->vertex_count = *((int32 *) pos); + pos += sizeof(mesh->vertex_count); + + mesh->normal_count = *((int32 *) pos); + pos += sizeof(mesh->normal_count); + + mesh->tex_coord_count = *((int32 *) pos); + pos += sizeof(mesh->tex_coord_count); + + mesh->color_count = *((int32 *) pos); + pos += sizeof(mesh->color_count); + + #if !_WIN32 && !__LITTLE_ENDIAN + mesh->version = endian_swap(mesh->version); + mesh->vertex_type = endian_swap(mesh->vertex_type); + mesh->verted_count = endian_swap(mesh->verted_count); + mesh->normal_count = endian_swap(mesh->normal_count); + mesh->tex_coord_count = endian_swap(mesh->tex_coord_count); + mesh->color_count = endian_swap(mesh->color_count); + #endif + + int32 vertex_size = 0; + if (mesh->vertex_type & VERTEX_TYPE_POSITION) { + vertex_size += 3; + } + + if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { + vertex_size += 3; + } + + if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { + vertex_size += 2; + } + + if (mesh->vertex_type & VERTEX_TYPE_COLOR) { + vertex_size += 4; + } + + int32 offset = 0; + if (mesh->vertex_count > 0) { + memcpy(mesh->data, pos, sizeof(f32) * vertex_size * mesh->vertex_count); + mesh->vertices = (f32 *) mesh->data; + + pos += sizeof(f32) * vertex_size * mesh->vertex_count; + offset += sizeof(f32) * vertex_size * mesh->vertex_count; + } + + if (mesh->normal_count > 0) { + memcpy(mesh->data + offset, pos, sizeof(f32) * 3 * mesh->normal_count); + mesh->normals = (f32 *) (mesh->data + offset); + + pos += sizeof(f32) * 3 * mesh->normal_count; + offset += sizeof(f32) * 3 * mesh->normal_count; + } + + if (mesh->tex_coord_count > 0) { + memcpy(mesh->data + offset, pos, sizeof(f32) * 3 * mesh->tex_coord_count); + mesh->tex_coords = (f32 *) (mesh->data + offset); + + pos += sizeof(f32) * 2 * mesh->tex_coord_count; + offset += sizeof(f32) * 2 * mesh->tex_coord_count; + } + + if (mesh->color_count > 0) { + memcpy(mesh->data + offset, pos, sizeof(f32) * 4 * mesh->color_count); + mesh->colors = (f32 *) (mesh->data + offset); + + pos += sizeof(f32) * 4 * mesh->color_count; + offset += sizeof(f32) * 4 * mesh->color_count; + } + + // Read face data + mesh->face_type = *((int32 *) pos); + pos += sizeof(mesh->face_type); + + mesh->face_count = *((int32 *) pos); + pos += sizeof(mesh->face_count); + + mesh->face_normal_count = *((int32 *) pos); + pos += sizeof(mesh->face_normal_count); + + mesh->face_tex_coord_count = *((int32 *) pos); + pos += sizeof(mesh->face_tex_coord_count); + + mesh->face_color_count = *((int32 *) pos); + pos += sizeof(mesh->face_color_count); + + #if !_WIN32 && !__LITTLE_ENDIAN + mesh->face_type = endian_swap(mesh->face_type); + mesh->face_count = endian_swap(mesh->face_count); + mesh->face_normal_count = endian_swap(mesh->face_normal_count); + mesh->face_tex_coord_count = endian_swap(mesh->face_tex_coord_count); + mesh->face_color_count = endian_swap(mesh->face_color_count); + #endif + + int32 face_size = 0; + if (mesh->face_type & FACE_TYPE_VERTICES) { + face_size += 3; + } + + if ((mesh->face_type & FACE_TYPE_NORMALS)) { + face_size += 3; + } + + if ((mesh->face_type & FACE_TYPE_TEXTURES)) { + face_size += 3; + } + + if ((mesh->face_type & FACE_TYPE_COLORS)) { + face_size += 3; + } + + // faces can be either in the form + // f: v/vt/vn ... + // or: + // f: v ... + // f: vn ... + // f: vt ... + if (mesh->face_count > 0) { + memcpy(mesh->data + offset, pos, sizeof(uint32) * face_size * mesh->face_count); + mesh->faces = (uint32 *) (mesh->data + offset); + + pos += sizeof(uint32) * face_size * mesh->face_count; + offset += sizeof(uint32) * face_size * mesh->face_count; + } + + if (mesh->face_normal_count > 0) { + memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_normal_count); + mesh->face_normals = (uint32 *) (mesh->data + offset); + + pos += sizeof(uint32) * 3 * mesh->face_normal_count; + offset += sizeof(uint32) * 3 * mesh->face_normal_count; + } + + if (mesh->face_tex_coord_count > 0) { + memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_tex_coord_count); + mesh->face_textures = (uint32 *) (mesh->data + offset); + + pos += sizeof(uint32) * 3 * mesh->face_tex_coord_count; + offset += sizeof(uint32) * 3 * mesh->face_tex_coord_count; + } + + if (mesh->face_color_count > 0) { + memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_color_count); + mesh->face_colors = (uint32 *) (mesh->data + offset); + + pos += sizeof(uint32) * 3 * mesh->face_color_count; + offset += sizeof(uint32) * 3 * mesh->face_color_count; + } + + SWAP_ENDIAN_LITTLE_SIMD( + (int32 *) mesh->data, + (int32 *) mesh->data, + offset / 4, // everything is 4 bytes -> super easy to swap + steps + ); + + return offset; +} + +void mesh_to_file( + RingMemory* ring, + const char* path, + const Mesh* mesh, + int32 vertex_save_format = VERTEX_TYPE_POSITION, + int32 face_save_format = FACE_TYPE_VERTICES, + int32 size = 8 +) +{ + FileBody file; + + // Temporary file size for buffer + // @todo check the actual size, we are currently more or less guessing + file.size = sizeof(mesh) + + sizeof(Vertex3D) * mesh->vertex_count + + sizeof(f32) * 12 * mesh->vertex_count + + 4096; + + file.content = ring_get_memory(ring, file.size, 64); + byte* pos = file.content; + + // version + memcpy(pos, &mesh->version, sizeof(mesh->version)); + pos += sizeof(mesh->version); + + // vertices + memcpy(pos, &vertex_save_format, sizeof(vertex_save_format)); + pos += sizeof(vertex_save_format); + + memcpy(pos, &mesh->vertex_count, sizeof(mesh->vertex_count)); + pos += sizeof(mesh->vertex_count); + + // We are can save the mesh in a different format from the current format -> need to adjust some values + uint32 normal_count = mesh->normal_count == 0 && (mesh->vertex_type & VERTEX_TYPE_NORMAL) + ? mesh->vertex_count + : mesh->normal_count; + + memcpy(pos, &normal_count, sizeof(mesh->normal_count)); + pos += sizeof(mesh->normal_count); + + uint32 tex_coord_count = mesh->tex_coord_count == 0 && (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) + ? mesh->vertex_count + : mesh->tex_coord_count; + + memcpy(pos, &tex_coord_count, sizeof(mesh->tex_coord_count)); + pos += sizeof(mesh->tex_coord_count); + + uint32 color_count = mesh->color_count == 0 && (mesh->vertex_type & VERTEX_TYPE_COLOR) + ? mesh->vertex_count + : mesh->color_count; + + memcpy(pos, &color_count, sizeof(mesh->color_count)); + pos += sizeof(mesh->color_count); + + // verticies + if (mesh->vertex_count > 0) { + int32 vertex_size = 0; + if (mesh->vertex_type & VERTEX_TYPE_POSITION) { + vertex_size += 3; + } + + if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { + vertex_size += 3; + } + + if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { + vertex_size += 2; + } + + if (mesh->vertex_type & VERTEX_TYPE_COLOR) { + vertex_size += 4; + } + + int32 out_vertex_size = 0; + if (vertex_save_format & VERTEX_TYPE_POSITION) { + out_vertex_size += 3; + } + + if (vertex_save_format & VERTEX_TYPE_NORMAL) { + out_vertex_size += 3; + } + + if (vertex_save_format & VERTEX_TYPE_TEXTURE_COORD) { + out_vertex_size += 2; + } + + if (vertex_save_format & VERTEX_TYPE_COLOR) { + out_vertex_size += 4; + } + + if ((mesh->vertex_type == VERTEX_TYPE_ALL && vertex_save_format == VERTEX_TYPE_ALL) + || (mesh->vertex_type == VERTEX_TYPE_POSITION && vertex_save_format == VERTEX_TYPE_POSITION) + ) { + // data is the same as in the array + memcpy(pos, mesh->vertices, vertex_size * sizeof(f32) * mesh->vertex_count); + pos += vertex_size * sizeof(f32) * mesh->vertex_count; + } else { + f32* temp = mesh->vertices; + f32* end = mesh->vertices + mesh->vertex_count * vertex_size; + + int32 offset; + + byte* vertice_start = pos; + + // @bug index gets increased every iteration BUT different groups and objects in the source may have different data + // This comes again down to how to handle hierarchal data with multiple groups and objects + int32 index = 0; + + // iterate over all vertices to create new output format + while (temp < end) { + // @question why do I even need offset? couldn't I just directly manipulate temp? + offset = 0; + + // First we save everything in one large array if that is the setting + if (vertex_save_format & VERTEX_TYPE_POSITION) { + if (mesh->vertex_type & VERTEX_TYPE_POSITION) { + memcpy(pos, temp, sizeof(f32) * 3); + pos += sizeof(f32) * 3; + + offset += 3; + } else { + memset(pos, 0, sizeof(f32) * 3); + pos += sizeof(f32) * 3; + } + } + + // We want separate arrays for some data + if ((mesh->vertex_type & VERTEX_TYPE_NORMAL) && !(vertex_save_format & VERTEX_TYPE_NORMAL)) { + // go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data + memcpy(vertice_start + + sizeof(f32) * out_vertex_size * mesh->vertex_count + + index * sizeof(f32) * 3, temp + offset, sizeof(f32) * 3); + + offset += 3; + } else if (vertex_save_format & VERTEX_TYPE_NORMAL) { + if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { + memcpy(pos, temp + offset, sizeof(f32) * 3); + pos += sizeof(f32) * 3; + + offset += 3; + } else { + memset(pos, 0, sizeof(f32) * 3); + pos += sizeof(f32) * 3; + } + } + + // We want separate arrays for some data + if ((mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) && !(vertex_save_format & VERTEX_TYPE_TEXTURE_COORD)) { + // go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data + memcpy(vertice_start + + sizeof(f32) * out_vertex_size * mesh->vertex_count + + sizeof(f32) * normal_count * 3 + + index * sizeof(f32) * 3, temp + offset, sizeof(f32) * 3); + + offset += 2; + } else if (vertex_save_format & VERTEX_TYPE_TEXTURE_COORD) { + if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { + memcpy(pos, temp + offset, sizeof(f32) * 2); + pos += sizeof(f32) * 2; + + offset += 2; + } else { + memset(pos, 0, sizeof(f32) * 2); + pos += sizeof(f32) * 2; + } + } + + // We want separate arrays for some data + if ((mesh->vertex_type & VERTEX_TYPE_COLOR) && !(vertex_save_format & VERTEX_TYPE_COLOR)) { + // go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data + memcpy(vertice_start + + sizeof(f32) * out_vertex_size * mesh->vertex_count + + sizeof(f32) * normal_count * 3 + + sizeof(f32) * tex_coord_count * 2 + + index * sizeof(f32) * 4, temp + offset, sizeof(f32) * 4); + + offset += 4; + } else if (vertex_save_format & VERTEX_TYPE_COLOR) { + if (mesh->vertex_type & VERTEX_TYPE_COLOR) { + memcpy(pos, temp + offset, sizeof(f32) * 4); + pos += sizeof(f32) * 4; + + offset += 4; + } else { + memset(pos, 0, sizeof(f32) * 4); + pos += sizeof(f32) * 4; + } + } + + temp += offset; + ++index; + } + } + + // check if we have clean array data already -> output this array data directly + if (mesh->normals && mesh->normal_count > 0) { + memcpy(pos, mesh->normals, mesh->normal_count * sizeof(f32) * 3); + pos += mesh->normal_count * sizeof(f32) * 3; + } + + if (mesh->tex_coords && mesh->tex_coord_count > 0) { + memcpy(pos, mesh->tex_coords, mesh->tex_coord_count * sizeof(f32) * 2); + pos += mesh->tex_coord_count * sizeof(f32) * 2; + } + + if (mesh->colors && mesh->color_count > 0) { + memcpy(pos, mesh->colors, mesh->color_count * sizeof(f32) * 4); + pos += mesh->color_count * sizeof(f32) * 4; + } + } + + // faces/indices + memcpy(pos, &face_save_format, sizeof(face_save_format)); + pos += sizeof(face_save_format); + + memcpy(pos, &mesh->face_count, sizeof(mesh->face_count)); + pos += sizeof(mesh->face_count); + + // We are can save the mesh in a different format from the current format -> need to adjust some values + uint32 face_normal_count = mesh->face_normal_count == 0 && (mesh->face_type & FACE_TYPE_NORMALS) + ? mesh->face_count + : mesh->face_normal_count; + + memcpy(pos, &face_normal_count, sizeof(mesh->face_normal_count)); + pos += sizeof(mesh->face_normal_count); + + uint32 face_tex_coord_count = mesh->face_tex_coord_count == 0 && (mesh->face_type & FACE_TYPE_TEXTURES) + ? mesh->face_count + : mesh->face_tex_coord_count; + + memcpy(pos, &face_tex_coord_count, sizeof(mesh->face_tex_coord_count)); + pos += sizeof(mesh->face_tex_coord_count); + + uint32 face_color_count = mesh->face_color_count == 0 && (mesh->face_type & FACE_TYPE_COLORS) + ? mesh->face_count + : mesh->face_color_count; + + memcpy(pos, &face_color_count, sizeof(mesh->face_color_count)); + pos += sizeof(mesh->face_color_count); + + if (mesh->face_count > 0) { + // WARNING: Carefull, we again assume only 3 elements per face + + int32 face_size = 0; + if (mesh->face_type & FACE_TYPE_VERTICES) { + face_size += 3; + } + + if (mesh->face_type & FACE_TYPE_NORMALS) { + face_size += 3; + } + + if (mesh->face_type & FACE_TYPE_TEXTURES) { + face_size += 3; + } + + if (mesh->face_type & FACE_TYPE_COLORS) { + face_size += 3; + } + + int32 out_face_size = 0; + if (face_save_format & FACE_TYPE_VERTICES) { + out_face_size += 3; + } + + if (face_save_format & FACE_TYPE_NORMALS) { + out_face_size += 3; + } + + if (face_save_format & FACE_TYPE_TEXTURES) { + out_face_size += 3; + } + + if (face_save_format & FACE_TYPE_COLORS) { + out_face_size += 3; + } + + if ((mesh->face_type == FACE_TYPE_ALL && face_save_format == FACE_TYPE_ALL) + || (mesh->face_type == FACE_TYPE_VERTICES && face_save_format == FACE_TYPE_VERTICES) + ) { + // data is the same as in the array + memcpy(pos, mesh->faces, face_size * sizeof(uint32) * mesh->face_count); + pos += face_size * sizeof(uint32) * mesh->face_count; + } else { + uint32* temp = mesh->faces; + uint32* end = mesh->faces + mesh->face_count * face_size; + + int32 offset; + + byte* face_start = pos; + + // @bug index gets increased every iteration BUT different groups and objects in the source may have different data + // This comes again down to how to handle hierarchal data with multiple groups and objects + int32 index = 0; + + // iterate over all faces to create new output format + // one iteration represents 1 block (a block could be v/vt/vn or, v, or v//vn, ...) + while (temp < end) { + // @question why do I even need offset? couldn't I just directly manipulate temp? + offset = 0; + + // First we save everything in one large array if that is the setting + if (face_save_format & FACE_TYPE_VERTICES) { + if (mesh->face_type & FACE_TYPE_VERTICES) { + memcpy(pos, temp, sizeof(uint32)); + pos += sizeof(uint32); + + offset += 1; + } else { + memset(pos, 0, sizeof(f32)); + pos += sizeof(f32); + } + } + + // We want separate arrays for some data + if (mesh->face_type & FACE_TYPE_NORMALS && !(face_save_format & FACE_TYPE_NORMALS)) { + // go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data + memcpy(face_start + + sizeof(uint32) * out_face_size * mesh->face_count + + index * sizeof(uint32), temp + offset, sizeof(uint32)); + + offset += 1; + } else if (face_save_format & FACE_TYPE_NORMALS) { + if (mesh->face_type & FACE_TYPE_NORMALS) { + memcpy(pos, temp + offset, sizeof(uint32)); + pos += sizeof(uint32); + + offset += 1; + } else { + memset(pos, 0, sizeof(uint32)); + pos += sizeof(uint32); + } + } + + // We want separate arrays for some data + if (mesh->face_type & FACE_TYPE_TEXTURES && !(face_save_format & FACE_TYPE_TEXTURES)) { + // go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data + memcpy(face_start + + sizeof(uint32) * out_face_size * mesh->face_count + + sizeof(uint32) * 3 * face_normal_count + + index * sizeof(uint32), temp + offset, sizeof(uint32)); + + offset += 1; + } else if (face_save_format & FACE_TYPE_TEXTURES) { + if (mesh->face_type & FACE_TYPE_TEXTURES) { + memcpy(pos, temp + offset, sizeof(uint32)); + pos += sizeof(uint32); + + offset += 1; + } else { + memset(pos, 0, sizeof(uint32)); + pos += sizeof(uint32); + } + } + + // We want separate arrays for some data + if (mesh->face_type & VERTEX_TYPE_COLOR && !(face_save_format & VERTEX_TYPE_COLOR)) { + // go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data + memcpy(face_start + + sizeof(uint32) * out_face_size * mesh->face_count + + sizeof(uint32) * 3 * face_normal_count + + sizeof(uint32) * 3 * face_tex_coord_count + + index * sizeof(uint32), temp + offset, sizeof(uint32)); + + offset += 1; + } else if (face_save_format & VERTEX_TYPE_COLOR) { + if (mesh->face_type & VERTEX_TYPE_COLOR) { + memcpy(pos, temp + offset, sizeof(uint32)); + pos += sizeof(uint32); + + offset += 1; + } else { + memset(pos, 0, sizeof(uint32)); + pos += sizeof(uint32); + } + } + + temp += offset; + ++index; + } + } + + // check if we have clean array data already -> output this array data directly + if (mesh->face_normals && mesh->face_normal_count > 0) { + memcpy(pos, mesh->face_normals, mesh->face_normal_count * sizeof(uint32) * 3); + pos += mesh->face_normal_count * sizeof(uint32) * 3; + } + + if (mesh->face_textures && mesh->face_tex_coord_count > 0) { + memcpy(pos, mesh->face_textures, mesh->face_tex_coord_count * sizeof(uint32) * 3); + pos += mesh->face_tex_coord_count * sizeof(uint32) * 3; + } + + if (mesh->face_colors && mesh->face_color_count > 0) { + memcpy(pos, mesh->face_colors, mesh->face_color_count * sizeof(uint32) * 3); + pos += mesh->face_color_count * sizeof(uint32) * 3; + } + } + + file.size = pos - file.content; + + SWAP_ENDIAN_LITTLE_SIMD( + (int32 *) file.content, + (int32 *) file.content, + file.size / 4, // everything in here is 4 bytes -> super easy to swap + steps + ); + + /* + FileBody file2; + file2.content = ring_get_memory(ring, file.size, 64); + file2.size = encode_lzp(file.content, file.size, file2.content); + + file_write(path, &file2); + */ + + file_write(path, &file); +} + #endif \ No newline at end of file diff --git a/object/Object.h b/object/Object.h deleted file mode 100644 index 64f0d16..0000000 --- a/object/Object.h +++ /dev/null @@ -1,961 +0,0 @@ -/** - * Jingga - * - * @copyright Jingga - * @license OMS License 2.0 - * @version 1.0.0 - * @link https://jingga.app - */ -#ifndef TOS_OBJECT_H -#define TOS_OBJECT_H - -#include "../stdlib/Types.h" -#include "../memory/RingMemory.h" -#include "../utils/EndianUtils.h" - -#include "Vertex.h" - -#if _WIN32 - #include "../platform/win32/UtilsWin32.h" -#else - #include "../platform/linux/UtilsLinux.h" -#endif - -#include "Mesh.h" -#include "../stdlib/simd/SIMD_I32.h" - -#define MESH_VERSION 1 - -// @todo The name Object.h is stupid, copy content to Mesh.h - -// @todo also handle textures etc. -// WARNING: mesh needs to have memory already reserved and asigned to data -void object_from_file_txt( - RingMemory* ring, - const char* path, - Mesh* mesh -) -{ - FileBody file; - file_read(path, &file, ring); - - char* pos = (char *) file.content; - mesh->version = strtol(pos, &pos, 10); ++pos; - - int32 object_index = 0; - int32 group_index = 0; - - mesh->vertices = (f32 *) mesh->data; - - mesh->vertex_count = 0; - mesh->normal_count = 0; - mesh->tex_coord_count = 0; - mesh->color_count = 0; - - mesh->face_count = 0; - mesh->face_normal_count = 0; - mesh->face_tex_coord_count = 0; - mesh->face_color_count = 0; - - uint32 temp_color_count = 0; - - while (*pos != '\0') { - while (*pos == ' ' || *pos == '\t' || *pos == '\n') { - ++pos; - } - - if (*pos == '\0') { - break; - } - - // Parse type - // WARNING: The code below could fail if [1] is outside of range - // However that should never happen for well formed files - int32 state = 0; - if (*pos == 'v' && pos[1] == ' ') { - state = 1; - } else if (*pos == 'v' && pos[1] == 'n') { - state = 2; - } else if (*pos == 'v' && pos[1] == 't') { - state = 3; - } else if (*pos == 'v' && pos[1] == 'p') { - state = 4; - } else if (*pos == 'o' && pos[1] == ' ') { - state = 5; - } else if (*pos == 's' && pos[1] == ' ') { - state = 6; - } else if (*pos == 'f' && pos[1] == ' ') { - state = 7; - } else if (*pos == 'g' && pos[1] == ' ') { - state = 8; - } else if (*pos == 'l' && pos[1] == ' ') { - state = 9; - } else if (*pos == 'm' && pos[1] == 't') { - state = 10; - } else if (*pos == 'h' && pos[1] == 'i') { - state = 11; - } else if (*pos == 'a' && pos[1] == 'n') { - state = 12; - } else if (*pos == 'u' && pos[3] == 'm') { - state = 13; - } else if (*pos == 'u' && pos[3] == 'h') { - state = 14; - } else { - // not supported or comment - while (*pos != '\n' && *pos != '\0') { - ++pos; - } - } - - // move past keyword - while (*pos != ' ' && *pos != '\n' && *pos != '\0') { - ++pos; - } - - // move past whitespaces and newline - bool is_next_line = false; - while (*pos == ' ' || *pos == '\n') { - is_next_line |= *pos == '\n'; - ++pos; - } - - if (*pos == '\0' || is_next_line) { - continue; - } - - // NOTE: we always load a file in the format: POSITON + NORMAL + TEXTURE + COLOR - // EVEN if some of the data is missing. This is necessary to keep the memory kinda in line. - // The actual binary file later will have the minimized layout. - - // handle data types - switch (state) { - case 0: break; - case 1: { - // 'v' - if (mesh->vertex_count == 0) { - mesh->vertex_type |= VERTEX_TYPE_POSITION; - } - - mesh->vertices[mesh->vertex_count * 3] = strtof(pos, &pos); ++pos; - mesh->vertices[mesh->vertex_count * 3 + 1] = strtof(pos, &pos); ++pos; - mesh->vertices[mesh->vertex_count * 3 + 2] = strtof(pos, &pos); ++pos; - - // has color information - // @todo Move to own case statement // 'co' - if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - if (mesh->vertex_count == 0) { - mesh->vertex_type |= VERTEX_TYPE_COLOR; - } - - mesh->vertices[mesh->vertex_count * 12 + 8] = strtof(pos, &pos); ++pos; - mesh->vertices[mesh->vertex_count * 12 + 9] = strtof(pos, &pos); ++pos; - mesh->vertices[mesh->vertex_count * 12 + 10] = strtof(pos, &pos); ++pos; - - // handle optional alpha [a] - if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - mesh->vertices[mesh->vertex_count * 12 + 11] = strtof(pos, &pos); ++pos; - } else { - mesh->vertices[mesh->vertex_count * 12 + 11] = 1.0f; - } - - ++temp_color_count; - } - - ++mesh->vertex_count; - } break; - case 2: { - // 'vn' - // @bug This requires normals to be defined before textures - if (mesh->normal_count == 0) { - mesh->normals = mesh->vertices + mesh->vertex_count * 3; - } - - mesh->normals[mesh->normal_count * 3] = strtof(pos, &pos); ++pos; - mesh->normals[mesh->normal_count * 3 + 1] = strtof(pos, &pos); ++pos; - mesh->normals[mesh->normal_count * 3 + 2] = strtof(pos, &pos); ++pos; - - ++mesh->normal_count; - } break; - case 3: { - // 'vt' - if (mesh->tex_coord_count == 0) { - mesh->tex_coords = mesh->vertices + mesh->vertex_count * 3 + mesh->normal_count * 3; - } - - mesh->tex_coords[mesh->tex_coord_count * 2] = strtof(pos, &pos); ++pos; - mesh->tex_coords[mesh->tex_coord_count * 2 + 1] = strtof(pos, &pos); ++pos; - - ++mesh->tex_coord_count; - } break; - case 4: { - // 'vp' - strtof(pos, &pos); ++pos; - - // handle optional [v] - if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - strtof(pos, &pos); ++pos; - - // handle optional [w] - if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - strtof(pos, &pos); ++pos; - } - } - } break; - case 5: { - // 'o' - char text[100]; - int32 i = 0; - while (*pos != '\0' && *pos != ' ') { - text[i++] = *pos++; - } - text[i] = '\0'; - - ++object_index; - } break; - case 6: { - // 's' - strtol(pos, &pos, 10); ++pos; - } break; - case 7: { - // 'f' - if (mesh->face_count == 0) { - mesh->faces = (uint32 *) (mesh->vertices + mesh->vertex_count * 3 + mesh->normal_count * 3 + mesh->tex_coord_count * 2 + mesh->color_count * 4); - } - - int32 ftype = 0; - char* tmp = pos; - while (*tmp != ' ') { - if (*tmp++ == '/') { - ++ftype; - - if (*tmp++ == '/') { - ftype = 3; - break; - } - } - } - - const int32 max_blocks = 3; // @todo this could actually be N. Might have to change in the future - int32 block = 0; - - while (*pos != '\0' && *pos != '\n') { - if (ftype == 0) { - // v1 v2 v3 ... - if (mesh->face_count == 0) { - mesh->face_type = FACE_TYPE_VERTICES; - } - - mesh->faces[(mesh->face_count * max_blocks * 1) + block] = strtol(pos, &pos, 10) - 1; ++pos; - } else if (ftype == 1) { - // v1/vt1 v2/vt2 v3/vt3 ... - if (mesh->face_count == 0) { - mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_TEXTURES; - } - - mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; - mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; - } else if (ftype == 2) { - // v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ... - if (mesh->face_count == 0) { - mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_TEXTURES | FACE_TYPE_NORMALS; - } - - mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3] = strtol(pos, &pos, 10) - 1; ++pos; - mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3 + 1] = strtol(pos, &pos, 10) - 1; ++pos; - mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3 + 2] = strtol(pos, &pos, 10) - 1; ++pos; - } else if (ftype == 3) { - // v1//vn1 v2//vn2 v3//vn3 ... - if (mesh->face_count == 0) { - mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_NORMALS; - } - - mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos; - ++pos; - mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos; - } - - ++block; - } - - ++mesh->face_count; - } break; - case 8: { - // 'g' - char text[100]; - int32 i = 0; - while (*pos != '\0' && *pos != ' ') { - text[i++] = *pos++; - } - text[i] = '\0'; - - ++group_index; - } break; - case 9: { - //l - while (*pos != '\0' && *pos != '\n') { - strtol(pos, &pos, 10); ++pos; - } - } break; - case 10: { - // 'mtllib' - char text[100]; - int32 i = 0; - while (*pos != '\0' && *pos != ' ') { - text[i++] = *pos++; - } - text[i] = '\0'; - } break; - case 11: { - // 'hitlib' - char text[100]; - int32 i = 0; - while (*pos != '\0' && *pos != ' ') { - text[i++] = *pos++; - } - text[i] = '\0'; - } break; - case 12: { - // 'anilib' - char text[100]; - int32 i = 0; - while (*pos != '\0' && *pos != ' ') { - text[i++] = *pos++; - } - text[i] = '\0'; - } break; - case 13: { - // 'usemtl' - char text[100]; - int32 i = 0; - while (*pos != '\0' && *pos != ' ') { - text[i++] = *pos++; - } - text[i] = '\0'; - } break; - case 14: { - // 'usehit' - char text[100]; - int32 i = 0; - while (*pos != '\0' && *pos != ' ') { - text[i++] = *pos++; - } - text[i] = '\0'; - } break; - } - } -} - -enum ObjectLoadingRestriction { - OBJECT_LOADING_RESTRICTION_POSITION = 1, - OBJECT_LOADING_RESTRICTION_NORMAL = 2, - OBJECT_LOADING_RESTRICTION_TEXTURE = 4, - OBJECT_LOADING_RESTRICTION_COLOR = 8, - OBJECT_LOADING_RESTRICTION_FACES = 16, - OBJECT_LOADING_RESTRICTION_EVERYTHING = 31 -}; - -// @todo sometimes we don't care about some data, we should have an option which defines which data should be loaded -// this can improve performance for algorithms on this. e.g.: -// on the server side we only care about the vertex positions for collision (no normals, no color, ...) -int32 object_from_file( - RingMemory* ring, - const char* path, - Mesh* mesh, - const char* group = NULL, - int32 load_format = OBJECT_LOADING_RESTRICTION_EVERYTHING, - int32 size = 8 -) -{ - FileBody file; - file_read(path, &file, ring); - - byte* pos = file.content; - - // Read version - mesh->version = *((int32 *) pos); - pos += sizeof(mesh->version); - - // Read base data - mesh->vertex_type = *((int32 *) pos); - pos += sizeof(mesh->vertex_type); - - mesh->vertex_count = *((int32 *) pos); - pos += sizeof(mesh->vertex_count); - - mesh->normal_count = *((int32 *) pos); - pos += sizeof(mesh->normal_count); - - mesh->tex_coord_count = *((int32 *) pos); - pos += sizeof(mesh->tex_coord_count); - - mesh->color_count = *((int32 *) pos); - pos += sizeof(mesh->color_count); - - #if !_WIN32 && !__LITTLE_ENDIAN - mesh->version = endian_swap(mesh->version); - mesh->vertex_type = endian_swap(mesh->vertex_type); - mesh->verted_count = endian_swap(mesh->verted_count); - mesh->normal_count = endian_swap(mesh->normal_count); - mesh->tex_coord_count = endian_swap(mesh->tex_coord_count); - mesh->color_count = endian_swap(mesh->color_count); - #endif - - int32 vertex_size = 0; - if (mesh->vertex_type & VERTEX_TYPE_POSITION) { - vertex_size += 3; - } - - if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { - vertex_size += 3; - } - - if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { - vertex_size += 2; - } - - if (mesh->vertex_type & VERTEX_TYPE_COLOR) { - vertex_size += 4; - } - - int32 offset = 0; - if (mesh->vertex_count > 0) { - memcpy(mesh->data, pos, sizeof(f32) * vertex_size * mesh->vertex_count); - mesh->vertices = (f32 *) mesh->data; - - pos += sizeof(f32) * vertex_size * mesh->vertex_count; - offset += sizeof(f32) * vertex_size * mesh->vertex_count; - } - - if (mesh->normal_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(f32) * 3 * mesh->normal_count); - mesh->normals = (f32 *) (mesh->data + offset); - - pos += sizeof(f32) * 3 * mesh->normal_count; - offset += sizeof(f32) * 3 * mesh->normal_count; - } - - if (mesh->tex_coord_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(f32) * 3 * mesh->tex_coord_count); - mesh->tex_coords = (f32 *) (mesh->data + offset); - - pos += sizeof(f32) * 2 * mesh->tex_coord_count; - offset += sizeof(f32) * 2 * mesh->tex_coord_count; - } - - if (mesh->color_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(f32) * 4 * mesh->color_count); - mesh->colors = (f32 *) (mesh->data + offset); - - pos += sizeof(f32) * 4 * mesh->color_count; - offset += sizeof(f32) * 4 * mesh->color_count; - } - - // Read face data - mesh->face_type = *((int32 *) pos); - pos += sizeof(mesh->face_type); - - mesh->face_count = *((int32 *) pos); - pos += sizeof(mesh->face_count); - - mesh->face_normal_count = *((int32 *) pos); - pos += sizeof(mesh->face_normal_count); - - mesh->face_tex_coord_count = *((int32 *) pos); - pos += sizeof(mesh->face_tex_coord_count); - - mesh->face_color_count = *((int32 *) pos); - pos += sizeof(mesh->face_color_count); - - #if !_WIN32 && !__LITTLE_ENDIAN - mesh->face_type = endian_swap(mesh->face_type); - mesh->face_count = endian_swap(mesh->face_count); - mesh->face_normal_count = endian_swap(mesh->face_normal_count); - mesh->face_tex_coord_count = endian_swap(mesh->face_tex_coord_count); - mesh->face_color_count = endian_swap(mesh->face_color_count); - #endif - - int32 face_size = 0; - if (mesh->face_type & FACE_TYPE_VERTICES) { - face_size += 3; - } - - if ((mesh->face_type & FACE_TYPE_NORMALS)) { - face_size += 3; - } - - if ((mesh->face_type & FACE_TYPE_TEXTURES)) { - face_size += 3; - } - - if ((mesh->face_type & FACE_TYPE_COLORS)) { - face_size += 3; - } - - // faces can be either in the form - // f: v/vt/vn ... - // or: - // f: v ... - // f: vn ... - // f: vt ... - if (mesh->face_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(uint32) * face_size * mesh->face_count); - mesh->faces = (uint32 *) (mesh->data + offset); - - pos += sizeof(uint32) * face_size * mesh->face_count; - offset += sizeof(uint32) * face_size * mesh->face_count; - } - - if (mesh->face_normal_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_normal_count); - mesh->face_normals = (uint32 *) (mesh->data + offset); - - pos += sizeof(uint32) * 3 * mesh->face_normal_count; - offset += sizeof(uint32) * 3 * mesh->face_normal_count; - } - - if (mesh->face_tex_coord_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_tex_coord_count); - mesh->face_textures = (uint32 *) (mesh->data + offset); - - pos += sizeof(uint32) * 3 * mesh->face_tex_coord_count; - offset += sizeof(uint32) * 3 * mesh->face_tex_coord_count; - } - - if (mesh->face_color_count > 0) { - memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_color_count); - mesh->face_colors = (uint32 *) (mesh->data + offset); - - pos += sizeof(uint32) * 3 * mesh->face_color_count; - offset += sizeof(uint32) * 3 * mesh->face_color_count; - } - - SWAP_ENDIAN_LITTLE_SIMD( - (int32 *) mesh->data, - (int32 *) mesh->data, - offset / 4, // everything is 4 bytes -> super easy to swap - steps - ); - - return offset; -} - -void object_to_file( - RingMemory* ring, - const char* path, - const Mesh* mesh, - int32 vertex_save_format = VERTEX_TYPE_POSITION, - int32 face_save_format = FACE_TYPE_VERTICES, - int32 size = 8 -) -{ - FileBody file; - - // Temporary file size for buffer - // @todo check the actual size, we are currently more or less guessing - file.size = sizeof(mesh) - + sizeof(Vertex3D) * mesh->vertex_count - + sizeof(f32) * 12 * mesh->vertex_count - + 4096; - - file.content = ring_get_memory(ring, file.size, 64); - byte* pos = file.content; - - // version - memcpy(pos, &mesh->version, sizeof(mesh->version)); - pos += sizeof(mesh->version); - - // vertices - memcpy(pos, &vertex_save_format, sizeof(vertex_save_format)); - pos += sizeof(vertex_save_format); - - memcpy(pos, &mesh->vertex_count, sizeof(mesh->vertex_count)); - pos += sizeof(mesh->vertex_count); - - // We are can save the mesh in a different format from the current format -> need to adjust some values - uint32 normal_count = mesh->normal_count == 0 && (mesh->vertex_type & VERTEX_TYPE_NORMAL) - ? mesh->vertex_count - : mesh->normal_count; - - memcpy(pos, &normal_count, sizeof(mesh->normal_count)); - pos += sizeof(mesh->normal_count); - - uint32 tex_coord_count = mesh->tex_coord_count == 0 && (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) - ? mesh->vertex_count - : mesh->tex_coord_count; - - memcpy(pos, &tex_coord_count, sizeof(mesh->tex_coord_count)); - pos += sizeof(mesh->tex_coord_count); - - uint32 color_count = mesh->color_count == 0 && (mesh->vertex_type & VERTEX_TYPE_COLOR) - ? mesh->vertex_count - : mesh->color_count; - - memcpy(pos, &color_count, sizeof(mesh->color_count)); - pos += sizeof(mesh->color_count); - - // verticies - if (mesh->vertex_count > 0) { - int32 vertex_size = 0; - if (mesh->vertex_type & VERTEX_TYPE_POSITION) { - vertex_size += 3; - } - - if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { - vertex_size += 3; - } - - if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { - vertex_size += 2; - } - - if (mesh->vertex_type & VERTEX_TYPE_COLOR) { - vertex_size += 4; - } - - int32 out_vertex_size = 0; - if (vertex_save_format & VERTEX_TYPE_POSITION) { - out_vertex_size += 3; - } - - if (vertex_save_format & VERTEX_TYPE_NORMAL) { - out_vertex_size += 3; - } - - if (vertex_save_format & VERTEX_TYPE_TEXTURE_COORD) { - out_vertex_size += 2; - } - - if (vertex_save_format & VERTEX_TYPE_COLOR) { - out_vertex_size += 4; - } - - if ((mesh->vertex_type == VERTEX_TYPE_ALL && vertex_save_format == VERTEX_TYPE_ALL) - || (mesh->vertex_type == VERTEX_TYPE_POSITION && vertex_save_format == VERTEX_TYPE_POSITION) - ) { - // data is the same as in the array - memcpy(pos, mesh->vertices, vertex_size * sizeof(f32) * mesh->vertex_count); - pos += vertex_size * sizeof(f32) * mesh->vertex_count; - } else { - f32* temp = mesh->vertices; - f32* end = mesh->vertices + mesh->vertex_count * vertex_size; - - int32 offset; - - byte* vertice_start = pos; - - // @bug index gets increased every iteration BUT different groups and objects in the source may have different data - // This comes again down to how to handle hierarchal data with multiple groups and objects - int32 index = 0; - - // iterate over all vertices to create new output format - while (temp < end) { - // @question why do I even need offset? couldn't I just directly manipulate temp? - offset = 0; - - // First we save everything in one large array if that is the setting - if (vertex_save_format & VERTEX_TYPE_POSITION) { - if (mesh->vertex_type & VERTEX_TYPE_POSITION) { - memcpy(pos, temp, sizeof(f32) * 3); - pos += sizeof(f32) * 3; - - offset += 3; - } else { - memset(pos, 0, sizeof(f32) * 3); - pos += sizeof(f32) * 3; - } - } - - // We want separate arrays for some data - if ((mesh->vertex_type & VERTEX_TYPE_NORMAL) && !(vertex_save_format & VERTEX_TYPE_NORMAL)) { - // go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data - memcpy(vertice_start - + sizeof(f32) * out_vertex_size * mesh->vertex_count - + index * sizeof(f32) * 3, temp + offset, sizeof(f32) * 3); - - offset += 3; - } else if (vertex_save_format & VERTEX_TYPE_NORMAL) { - if (mesh->vertex_type & VERTEX_TYPE_NORMAL) { - memcpy(pos, temp + offset, sizeof(f32) * 3); - pos += sizeof(f32) * 3; - - offset += 3; - } else { - memset(pos, 0, sizeof(f32) * 3); - pos += sizeof(f32) * 3; - } - } - - // We want separate arrays for some data - if ((mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) && !(vertex_save_format & VERTEX_TYPE_TEXTURE_COORD)) { - // go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data - memcpy(vertice_start - + sizeof(f32) * out_vertex_size * mesh->vertex_count - + sizeof(f32) * normal_count * 3 - + index * sizeof(f32) * 3, temp + offset, sizeof(f32) * 3); - - offset += 2; - } else if (vertex_save_format & VERTEX_TYPE_TEXTURE_COORD) { - if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) { - memcpy(pos, temp + offset, sizeof(f32) * 2); - pos += sizeof(f32) * 2; - - offset += 2; - } else { - memset(pos, 0, sizeof(f32) * 2); - pos += sizeof(f32) * 2; - } - } - - // We want separate arrays for some data - if ((mesh->vertex_type & VERTEX_TYPE_COLOR) && !(vertex_save_format & VERTEX_TYPE_COLOR)) { - // go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data - memcpy(vertice_start - + sizeof(f32) * out_vertex_size * mesh->vertex_count - + sizeof(f32) * normal_count * 3 - + sizeof(f32) * tex_coord_count * 2 - + index * sizeof(f32) * 4, temp + offset, sizeof(f32) * 4); - - offset += 4; - } else if (vertex_save_format & VERTEX_TYPE_COLOR) { - if (mesh->vertex_type & VERTEX_TYPE_COLOR) { - memcpy(pos, temp + offset, sizeof(f32) * 4); - pos += sizeof(f32) * 4; - - offset += 4; - } else { - memset(pos, 0, sizeof(f32) * 4); - pos += sizeof(f32) * 4; - } - } - - temp += offset; - ++index; - } - } - - // check if we have clean array data already -> output this array data directly - if (mesh->normals && mesh->normal_count > 0) { - memcpy(pos, mesh->normals, mesh->normal_count * sizeof(f32) * 3); - pos += mesh->normal_count * sizeof(f32) * 3; - } - - if (mesh->tex_coords && mesh->tex_coord_count > 0) { - memcpy(pos, mesh->tex_coords, mesh->tex_coord_count * sizeof(f32) * 2); - pos += mesh->tex_coord_count * sizeof(f32) * 2; - } - - if (mesh->colors && mesh->color_count > 0) { - memcpy(pos, mesh->colors, mesh->color_count * sizeof(f32) * 4); - pos += mesh->color_count * sizeof(f32) * 4; - } - } - - // faces/indices - memcpy(pos, &face_save_format, sizeof(face_save_format)); - pos += sizeof(face_save_format); - - memcpy(pos, &mesh->face_count, sizeof(mesh->face_count)); - pos += sizeof(mesh->face_count); - - // We are can save the mesh in a different format from the current format -> need to adjust some values - uint32 face_normal_count = mesh->face_normal_count == 0 && (mesh->face_type & FACE_TYPE_NORMALS) - ? mesh->face_count - : mesh->face_normal_count; - - memcpy(pos, &face_normal_count, sizeof(mesh->face_normal_count)); - pos += sizeof(mesh->face_normal_count); - - uint32 face_tex_coord_count = mesh->face_tex_coord_count == 0 && (mesh->face_type & FACE_TYPE_TEXTURES) - ? mesh->face_count - : mesh->face_tex_coord_count; - - memcpy(pos, &face_tex_coord_count, sizeof(mesh->face_tex_coord_count)); - pos += sizeof(mesh->face_tex_coord_count); - - uint32 face_color_count = mesh->face_color_count == 0 && (mesh->face_type & FACE_TYPE_COLORS) - ? mesh->face_count - : mesh->face_color_count; - - memcpy(pos, &face_color_count, sizeof(mesh->face_color_count)); - pos += sizeof(mesh->face_color_count); - - if (mesh->face_count > 0) { - // WARNING: Carefull, we again assume only 3 elements per face - - int32 face_size = 0; - if (mesh->face_type & FACE_TYPE_VERTICES) { - face_size += 3; - } - - if (mesh->face_type & FACE_TYPE_NORMALS) { - face_size += 3; - } - - if (mesh->face_type & FACE_TYPE_TEXTURES) { - face_size += 3; - } - - if (mesh->face_type & FACE_TYPE_COLORS) { - face_size += 3; - } - - int32 out_face_size = 0; - if (face_save_format & FACE_TYPE_VERTICES) { - out_face_size += 3; - } - - if (face_save_format & FACE_TYPE_NORMALS) { - out_face_size += 3; - } - - if (face_save_format & FACE_TYPE_TEXTURES) { - out_face_size += 3; - } - - if (face_save_format & FACE_TYPE_COLORS) { - out_face_size += 3; - } - - if ((mesh->face_type == FACE_TYPE_ALL && face_save_format == FACE_TYPE_ALL) - || (mesh->face_type == FACE_TYPE_VERTICES && face_save_format == FACE_TYPE_VERTICES) - ) { - // data is the same as in the array - memcpy(pos, mesh->faces, face_size * sizeof(uint32) * mesh->face_count); - pos += face_size * sizeof(uint32) * mesh->face_count; - } else { - uint32* temp = mesh->faces; - uint32* end = mesh->faces + mesh->face_count * face_size; - - int32 offset; - - byte* face_start = pos; - - // @bug index gets increased every iteration BUT different groups and objects in the source may have different data - // This comes again down to how to handle hierarchal data with multiple groups and objects - int32 index = 0; - - // iterate over all faces to create new output format - // one iteration represents 1 block (a block could be v/vt/vn or, v, or v//vn, ...) - while (temp < end) { - // @question why do I even need offset? couldn't I just directly manipulate temp? - offset = 0; - - // First we save everything in one large array if that is the setting - if (face_save_format & FACE_TYPE_VERTICES) { - if (mesh->face_type & FACE_TYPE_VERTICES) { - memcpy(pos, temp, sizeof(uint32)); - pos += sizeof(uint32); - - offset += 1; - } else { - memset(pos, 0, sizeof(f32)); - pos += sizeof(f32); - } - } - - // We want separate arrays for some data - if (mesh->face_type & FACE_TYPE_NORMALS && !(face_save_format & FACE_TYPE_NORMALS)) { - // go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data - memcpy(face_start - + sizeof(uint32) * out_face_size * mesh->face_count - + index * sizeof(uint32), temp + offset, sizeof(uint32)); - - offset += 1; - } else if (face_save_format & FACE_TYPE_NORMALS) { - if (mesh->face_type & FACE_TYPE_NORMALS) { - memcpy(pos, temp + offset, sizeof(uint32)); - pos += sizeof(uint32); - - offset += 1; - } else { - memset(pos, 0, sizeof(uint32)); - pos += sizeof(uint32); - } - } - - // We want separate arrays for some data - if (mesh->face_type & FACE_TYPE_TEXTURES && !(face_save_format & FACE_TYPE_TEXTURES)) { - // go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data - memcpy(face_start - + sizeof(uint32) * out_face_size * mesh->face_count - + sizeof(uint32) * 3 * face_normal_count - + index * sizeof(uint32), temp + offset, sizeof(uint32)); - - offset += 1; - } else if (face_save_format & FACE_TYPE_TEXTURES) { - if (mesh->face_type & FACE_TYPE_TEXTURES) { - memcpy(pos, temp + offset, sizeof(uint32)); - pos += sizeof(uint32); - - offset += 1; - } else { - memset(pos, 0, sizeof(uint32)); - pos += sizeof(uint32); - } - } - - // We want separate arrays for some data - if (mesh->face_type & VERTEX_TYPE_COLOR && !(face_save_format & VERTEX_TYPE_COLOR)) { - // go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data - memcpy(face_start - + sizeof(uint32) * out_face_size * mesh->face_count - + sizeof(uint32) * 3 * face_normal_count - + sizeof(uint32) * 3 * face_tex_coord_count - + index * sizeof(uint32), temp + offset, sizeof(uint32)); - - offset += 1; - } else if (face_save_format & VERTEX_TYPE_COLOR) { - if (mesh->face_type & VERTEX_TYPE_COLOR) { - memcpy(pos, temp + offset, sizeof(uint32)); - pos += sizeof(uint32); - - offset += 1; - } else { - memset(pos, 0, sizeof(uint32)); - pos += sizeof(uint32); - } - } - - temp += offset; - ++index; - } - } - - // check if we have clean array data already -> output this array data directly - if (mesh->face_normals && mesh->face_normal_count > 0) { - memcpy(pos, mesh->face_normals, mesh->face_normal_count * sizeof(uint32) * 3); - pos += mesh->face_normal_count * sizeof(uint32) * 3; - } - - if (mesh->face_textures && mesh->face_tex_coord_count > 0) { - memcpy(pos, mesh->face_textures, mesh->face_tex_coord_count * sizeof(uint32) * 3); - pos += mesh->face_tex_coord_count * sizeof(uint32) * 3; - } - - if (mesh->face_colors && mesh->face_color_count > 0) { - memcpy(pos, mesh->face_colors, mesh->face_color_count * sizeof(uint32) * 3); - pos += mesh->face_color_count * sizeof(uint32) * 3; - } - } - - file.size = pos - file.content; - - SWAP_ENDIAN_LITTLE_SIMD( - (int32 *) file.content, - (int32 *) file.content, - file.size / 4, // everything in here is 4 bytes -> super easy to swap - steps - ); - - /* - FileBody file2; - file2.content = ring_get_memory(ring, file.size, 64); - file2.size = encode_lzp(file.content, file.size, file2.content); - - file_write(path, &file2); - */ - - file_write(path, &file); -} - -#endif \ No newline at end of file diff --git a/utils/SystemInfo.h b/platform/linux/SystemInfo.h similarity index 93% rename from utils/SystemInfo.h rename to platform/linux/SystemInfo.h index e09c98f..9c6dde2 100644 --- a/utils/SystemInfo.h +++ b/platform/linux/SystemInfo.h @@ -12,8 +12,8 @@ #include #include #include "../stdlib/Types.h" -#include "StringUtils.h" #include "../stdlib/simd/SIMD_Helper.h" +#include "StringUtils.h" #if _WIN32 #include @@ -24,6 +24,9 @@ #include #include #include + #include +#else + #include #endif #ifdef _MSC_VER @@ -36,7 +39,38 @@ // @todo implement for arm? // @todo implement for linux? -// @todo move to platform specifc files + +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 + + 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 + + return (localeName[3] << 8) | localeName[4]; +} struct CpuCacheInfo { int32 level; @@ -366,13 +400,13 @@ void os_info_get(OSInfo* info) { RtlGetVersion(&version_info); } - strcpy(info->vendor, "Microsoft"); - strcpy(info->name, "Windows"); + memcpy(info->vendor, "Microsoft", sizeof("Microsoft")); + memcpy(info->name, "Windows", sizeof("Windows")); info->major = version_info.dwMajorVersion; info->minor = version_info.dwMinorVersion; #else - strcpy(info->vendor, "Linux"); - strcpy(info->name, "Linux"); + memcpy(info->vendor, "Linux", sizeof("Linux")); + memcpy(info->name, "Linux", sizeof("Linux")); info->major = 0; info->minor = 0; #endif @@ -394,7 +428,7 @@ struct GpuInfo { int32 vram; }; -unsigned int32 gpu_info_get(GpuInfo* info) { +uint32 gpu_info_get(GpuInfo* info) { IDXGIFactory *pFactory = NULL; IDXGIAdapter *pAdapter = NULL; DXGI_ADAPTER_DESC adapterDesc; @@ -404,7 +438,7 @@ unsigned int32 gpu_info_get(GpuInfo* info) { return 0; } - UINT i = 0; + uint32 i = 0; while (pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND && i < 2) { hr = pAdapter->GetDesc(&adapterDesc); if (FAILED(hr)) { @@ -432,13 +466,13 @@ struct DisplayInfo { int32 hz; }; -unsigned int32 display_info_get(DisplayInfo* info) { +uint32 display_info_get(DisplayInfo* info) { DISPLAY_DEVICEA device; DEVMODEA mode; device.cb = sizeof(DISPLAY_DEVICEA); - int32 i = 0; + uint32 i = 0; while (EnumDisplayDevicesA(NULL, i, &device, 0)) { mode.dmSize = sizeof(mode); diff --git a/platform/win32/ExceptionHandler.h b/platform/win32/ExceptionHandler.h index f0080c5..e409556 100644 --- a/platform/win32/ExceptionHandler.h +++ b/platform/win32/ExceptionHandler.h @@ -14,6 +14,10 @@ #include #include +#ifdef _MSC_VER + #pragma comment(lib, "dbghelp.lib") +#endif + void create_minidump(EXCEPTION_POINTERS *exception_pointers) { // Open the dump file HANDLE hFile = CreateFileA("crash_dump.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); diff --git a/platform/win32/SystemInfo.h b/platform/win32/SystemInfo.h new file mode 100644 index 0000000..2e84bb6 --- /dev/null +++ b/platform/win32/SystemInfo.h @@ -0,0 +1,595 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_SYSTEM_INFO_H +#define TOS_UTILS_SYSTEM_INFO_H + +#include +#include +#include "../../stdlib/Types.h" +#include "../../stdlib/simd/SIMD_Helper.h" +#include "../../utils/StringUtils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + // @performance Do we really need all these libs, can't we simplify that?! + #include + #pragma comment(lib, "Advapi32.lib") + #pragma comment(lib, "wbemuuid.lib") + #pragma comment(lib, "iphlpapi.lib") + #pragma comment(lib, "d3d12.lib") + #pragma comment(lib, "dxgi.lib") +#endif + +// @todo implement for arm? + +uint16 system_language_code() +{ + LANGID langID = GetUserDefaultUILanguage(); + wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; + + if (!LCIDToLocaleName(langID, localeName, LOCALE_NAME_MAX_LENGTH, 0)) { + return 0; + } + + return (localeName[0] << 8) | localeName[1]; +} + +uint16 system_country_code() +{ + LANGID langID = GetUserDefaultUILanguage(); + wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; + + if (!LCIDToLocaleName(langID, localeName, LOCALE_NAME_MAX_LENGTH, 0)) { + return 0; + } + + 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; + + cache->level = level; + cache->size = 0; + cache->ways = 0; + cache->partitions = 0; + cache->sets = 0; + cache->line_size = 0; + + int32 regs[4]; + __cpuidex(regs, 4, level); + eax = regs[0]; + ebx = regs[1]; + ecx = regs[2]; + edx = regs[3]; + + type = (eax & 0x1F); + + if (type == 0) { + return; + } + + cache->ways = ((ebx >> 22) & 0x3FF) + 1; + cache->line_size = (ebx & 0xFFF) + 1; + cache->partitions = ((ebx >> 12) & 0x3FF) + 1; + cache->sets = ecx + 1; + 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'; + + HRESULT hres; + + // Step 1: Initialize COM library + hres = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(hres)) { + return; + } + + // Step 2: Set general COM security levels + hres = CoInitializeSecurity( + NULL, + -1, + NULL, + NULL, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_NONE, + NULL + ); + + if (FAILED(hres)) { + CoUninitialize(); + return; + } + + // Step 3: Obtain initial locator to WMI + IWbemLocator *pLoc = NULL; + hres = CoCreateInstance( + CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, + (LPVOID *)&pLoc + ); + + if (FAILED(hres)) { + CoUninitialize(); + return; + } + + // Step 4: Connect to WMI through IWbemLocator::ConnectServer + IWbemServices *pSvc = NULL; + hres = pLoc->ConnectServer( + _bstr_t(L"ROOT\\CIMV2"), + NULL, + NULL, + 0, + NULL, + 0, + 0, + &pSvc + ); + + if (FAILED(hres)) { + pLoc->Release(); + CoUninitialize(); + return; + } + + // Step 5: Set security levels on the proxy + hres = CoSetProxyBlanket( + pSvc, + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + NULL, + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_NONE + ); + + if (FAILED(hres)) { + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return; + } + + // Step 6: Use the IWbemServices pointer to make a WMI query + IEnumWbemClassObject* pEnumerator = NULL; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT * FROM Win32_BaseBoard"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator + ); + + if (FAILED(hres)) { + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return; + } + + // Step 7: Retrieve the data + IWbemClassObject *pclsObj = NULL; + ULONG uReturn = 0; + while (pEnumerator) { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); + if (0 == uReturn) { + break; + } + + VARIANT vtProp; + hr = pclsObj->Get(L"Product", 0, &vtProp, 0, 0); + if (SUCCEEDED(hr)) { + snprintf(info->name, 64, "%S", vtProp.bstrVal); + VariantClear(&vtProp); + } + + hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); + if (SUCCEEDED(hr)) { + snprintf(info->serial_number, 63, "%S", vtProp.bstrVal); + info->serial_number[64] = '\0'; + + VariantClear(&vtProp); + } + + pclsObj->Release(); + } + + // Clean up + pSvc->Release(); + pLoc->Release(); + pEnumerator->Release(); + 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) { + return 0; + } + + DWORD dwSize = 0; + PIP_ADAPTER_ADDRESSES pAdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES pAdapter = NULL; + + // Get the size of the adapter addresses buffer + if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &dwSize) == ERROR_BUFFER_OVERFLOW) { + pAdapterAddresses = (PIP_ADAPTER_ADDRESSES) malloc(dwSize); + if (pAdapterAddresses == NULL) { + WSACleanup(); + return 0; + } + } else { + WSACleanup(); + return 0; + } + + // Get the adapter addresses + if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAdapterAddresses, &dwSize) != NO_ERROR) { + free(pAdapterAddresses); + WSACleanup(); + return 0; + } + + int32 i = 0; + + // Iterate over the adapters and print their MAC addresses + pAdapter = pAdapterAddresses; + while (pAdapter && i < 4) { + if (pAdapter->PhysicalAddressLength != 0) { + info[i].slot[63] = '\0'; + info[i].mac[23] = '\0'; + + memcpy(info[i].mac, pAdapter->PhysicalAddress, 8); + wcstombs(info[i].slot, pAdapter->FriendlyName, 63); + + ++i; + } + + pAdapter = pAdapter->Next; + } + + free(pAdapterAddresses); + WSACleanup(); + + 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; + info->simd.avx256 = max_avx256_supported(); + info->simd.avx512 = max_avx512_supported(); + + cache_info_get(1, &info->cache[0]); + cache_info_get(2, &info->cache[1]); + cache_info_get(3, &info->cache[2]); + cache_info_get(4, &info->cache[3]); + + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + info->page_size = sys_info.dwPageSize; + + int32 cpuInfo[4] = { 0 }; + __cpuid(cpuInfo, 0); + + memset(info->vendor, 0, sizeof(info->vendor)); + *((int*)info->vendor) = cpuInfo[1]; + *((int*)(info->vendor + 4)) = cpuInfo[3]; + *((int*)(info->vendor + 8)) = cpuInfo[2]; + info->vendor[12] = '\0'; + + __cpuid(cpuInfo, 0x80000002); + memcpy(info->brand, cpuInfo, sizeof(cpuInfo)); + __cpuid(cpuInfo, 0x80000003); + memcpy(info->brand + 16, cpuInfo, sizeof(cpuInfo)); + __cpuid(cpuInfo, 0x80000004); + memcpy(info->brand + 32, cpuInfo, sizeof(cpuInfo)); + info->brand[48] = '\0'; + + __cpuid(cpuInfo, 1); + info->model = (cpuInfo[0] >> 4) & 0xF; + info->family = (cpuInfo[0] >> 8) & 0xF; + + DWORD bufSize = sizeof(DWORD); + HKEY hKey; + long lError = RegOpenKeyExA( + HKEY_LOCAL_MACHINE, + "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", + 0, KEY_READ, &hKey + ); + + if (lError == ERROR_SUCCESS) { + RegQueryValueExA(hKey, "~MHz", NULL, NULL, (LPBYTE) &(info->mhz), &bufSize); + } + + 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'; + + #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 +} + +struct RamInfo { + int32 memory; +}; + +void ram_info_get(RamInfo* info) { + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + 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; + DXGI_ADAPTER_DESC adapterDesc; + + HRESULT hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory); + if (FAILED(hr)) { + return 0; + } + + uint32 i = 0; + while (pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND && i < 2) { + hr = pAdapter->GetDesc(&adapterDesc); + if (FAILED(hr)) { + pAdapter->Release(); + break; + } + + wcstombs(info[i].name, adapterDesc.Description, 63); + info[i].name[63] = '\0'; + info[i].vram = (int) (adapterDesc.DedicatedVideoMemory / (1024 * 1024)); + + pAdapter->Release(); + i++; + } + + pFactory->Release(); + + return i; +} + +struct DisplayInfo { + char name[64]; + int32 width; + int32 height; + int32 hz; +}; + +uint32 display_info_get(DisplayInfo* info) { + DISPLAY_DEVICEA device; + DEVMODEA mode; + + device.cb = sizeof(DISPLAY_DEVICEA); + + uint32 i = 0; + + while (EnumDisplayDevicesA(NULL, i, &device, 0)) { + mode.dmSize = sizeof(mode); + + if (EnumDisplaySettingsA(device.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) { + strcpy(info[i].name, device.DeviceName); + info[i].width = mode.dmPelsWidth; + info[i].height = mode.dmPelsHeight; + info[i].hz = mode.dmDisplayFrequency; + } + + ++i; + } + + 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", + "AVX-512DQ", + "AVX-512IFMA", + "AVX-512PF", + "AVX-512ER", + "AVX-512CD", + "AVX-512BW", + "AVX-512VL" + }; + + sprintf_s( + buf, + 4096, + "OS:\n" + "==============\n" + "Vendor: %s\n" "Name: %s\n" "Major: %d\n" "Minor: %d\n" + "\n" + "Mainboard:\n" + "==============\n" + "Name: %s\n" "SN: %s\n" + "\n" + "Network:\n" + "==============\n" + "Slot: %s\n" "MAC: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n" + "\n" + "Slot: %s\n" "MAC: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n" + "\n" + "Slot: %s\n" "MAC: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n" + "\n" + "Slot: %s\n" "MAC: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n" + "\n" + "CPU:\n" + "==============\n" + "Hardware\n" "Vendor: %s\n" "Brand: %s\n" "Model: %d\n" "Family: %d\n" "Mhz: %d\n" "Page Size: %d\n" + "\n" + "Cache:\n" + "L1: Size %d Line %d\n" + "L2: Size %d Line %d\n" + "L3: Size %d Line %d\n" + "L4: Size %d Line %d\n" + "\n" + "SIMD:\n" "SSE: %.1f\n" "AVX256: %d\n" "AVX512: %s\n" + "\n" + "GPU:\n" + "==============\n" + "Name: %s\n" "VRAM: %d\n" + "Name: %s\n" "VRAM: %d\n" + "\n" + "Display:\n" + "==============\n" + "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" + "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" + "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" + "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" + "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" + "Name: %s\n" "Width: %d\n" "Height: %d\n" "Hz: %d\n" + "\n" + "RAM:\n" + "==============\n" + "Memory: %d MB", + info->os.vendor, info->os.name, info->os.major, info->os.minor, + info->mainboard.name, info->mainboard.serial_number, + info->network[0].slot, info->network[0].mac[0], info->network[0].mac[1], info->network[0].mac[2], info->network[0].mac[3], info->network[0].mac[4], info->network[0].mac[5], info->network[0].mac[6], info->network[0].mac[7], + info->network_count < 2 ? "" : info->network[1].slot, info->network_count < 2 ? 0 : info->network[1].mac[0], info->network_count < 2 ? 0 : info->network[1].mac[1], info->network_count < 2 ? 0 : info->network[1].mac[2], info->network_count < 2 ? 0 : info->network[1].mac[3], info->network_count < 2 ? 0 : info->network[1].mac[4], info->network_count < 2 ? 0 : info->network[1].mac[5], info->network_count < 2 ? 0 : info->network[1].mac[6], info->network_count < 2 ? 0 : info->network[1].mac[7], + info->network_count < 3 ? "" : info->network[2].slot, info->network_count < 3 ? 0 : info->network[2].mac[0], info->network_count < 3 ? 0 : info->network[2].mac[1], info->network_count < 3 ? 0 : info->network[2].mac[2], info->network_count < 3 ? 0 : info->network[2].mac[3], info->network_count < 3 ? 0 : info->network[2].mac[4], info->network_count < 3 ? 0 : info->network[2].mac[5], info->network_count < 3 ? 0 : info->network[2].mac[6], info->network_count < 3 ? 0 : info->network[2].mac[7], + info->network_count < 4 ? "" : info->network[3].slot, info->network_count < 4 ? 0 : info->network[3].mac[0], info->network_count < 4 ? 0 : info->network[3].mac[1], info->network_count < 4 ? 0 : info->network[3].mac[2], info->network_count < 4 ? 0 : info->network[3].mac[3], info->network_count < 4 ? 0 : info->network[3].mac[4], info->network_count < 4 ? 0 : info->network[3].mac[5], info->network_count < 4 ? 0 : info->network[3].mac[6], info->network_count < 4 ? 0 : info->network[3].mac[7], + info->cpu.vendor, info->cpu.brand, info->cpu.model, info->cpu.family, info->cpu.mhz, info->cpu.page_size, + info->cpu.cache[0].size, info->cpu.cache[0].line_size, + info->cpu.cache[1].size, info->cpu.cache[1].line_size, + info->cpu.cache[2].size, info->cpu.cache[2].line_size, + info->cpu.cache[3].size, info->cpu.cache[3].line_size, + info->cpu.simd.sse, info->cpu.simd.avx256, info->cpu.simd.avx512 > 0 ? avx512[info->cpu.simd.avx512 - 1] : "0", + info->gpu[0].name, info->gpu[0].vram, + info->gpu_count < 2 ? "" : info->gpu[1].name, info->gpu_count < 2 ? 0 : info->gpu[1].vram, + info->display[0].name, info->display[0].width, info->display[0].height, info->display[0].hz, + info->display_count < 2 ? "" : info->display[1].name, info->display_count < 2 ? 0 : info->display[1].width, info->display_count < 2 ? 0 : info->display[1].height, info->display_count < 2 ? 0 : info->display[1].hz, + info->display_count < 3 ? "" : info->display[2].name, info->display_count < 3 ? 0 : info->display[2].width, info->display_count < 3 ? 0 : info->display[2].height, info->display_count < 3 ? 0 : info->display[2].hz, + info->display_count < 4 ? "" : info->display[3].name, info->display_count < 4 ? 0 : info->display[3].width, info->display_count < 4 ? 0 : info->display[3].height, info->display_count < 4 ? 0 : info->display[3].hz, + info->display_count < 5 ? "" : info->display[4].name, info->display_count < 5 ? 0 : info->display[4].width, info->display_count < 5 ? 0 : info->display[4].height, info->display_count < 5 ? 0 : info->display[4].hz, + info->display_count < 6 ? "" : info->display[5].name, info->display_count < 6 ? 0 : info->display[5].width, info->display_count < 6 ? 0 : info->display[5].height, info->display_count < 6 ? 0 : info->display[5].hz, + info->ram.memory + ); +} + +void system_info_get(SystemInfo* info) +{ + os_info_get(&info->os); + mainboard_info_get(&info->mainboard); + info->network_count = network_info_get(info->network); + cpu_info_get(&info->cpu); + ram_info_get(&info->ram); + info->gpu_count = gpu_info_get(info->gpu); + info->display_count = display_info_get(info->display); +} + +#endif \ No newline at end of file diff --git a/platform/win32/input/RawInput.h b/platform/win32/input/RawInput.h index 1ffb6c8..62f9e18 100644 --- a/platform/win32/input/RawInput.h +++ b/platform/win32/input/RawInput.h @@ -155,8 +155,10 @@ void input_mouse_position(HWND hwnd, v2_int32* pos) } } -void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, uint64 time) +int32 input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, uint64 time) { + int32 input_count = 0; + uint32 i = 0; if (raw->header.dwType == RIM_TYPEMOUSE) { // @performance Change so we can directly access the correct state (maybe map handle address to index?) @@ -167,7 +169,7 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, } if (i >= state_count || !states[i].is_connected) { - return; + return 0; } if (raw->data.mouse.usButtonFlags) { @@ -204,7 +206,7 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, key.key_state = KEY_STATE_RELEASED; key.key_id = 5; } else { - return; + return 0; } /* @todo implement @@ -219,6 +221,8 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, // @question is mouse wheel really considered a button change? + ++input_count; + key.key_id |= INPUT_MOUSE_PREFIX; key.value = 0; key.time = time; @@ -270,7 +274,7 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, } if (i >= state_count || !states[i].is_connected) { - return; + return 0; } uint16 new_state; @@ -279,9 +283,11 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, } else if (raw->data.keyboard.Flags == RI_KEY_MAKE) { new_state = KEY_STATE_PRESSED; } else { - return; + return 0; } + ++input_count; + // @todo change to MakeCode instead of VKey InputKey key = {(uint16) (raw->data.keyboard.VKey | INPUT_KEYBOARD_PREFIX), new_state, 0, time}; input_set_state(&states[i].state, &key); @@ -304,7 +310,7 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, if (i >= state_count || !states[i].is_connected || time - states[i].time_last_input_check < 5 ) { - return; + return 0; } ControllerInput controller = {}; @@ -314,6 +320,8 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, states[i].time_last_input_check = time; } } + + return input_count; } void input_handle(LPARAM lParam, Input* __restrict states, int state_count, RingMemory* ring, uint64 time) @@ -333,13 +341,14 @@ void input_handle(LPARAM lParam, Input* __restrict states, int state_count, Ring input_raw_handle((RAWINPUT *) lpb, states, state_count, time); } -void input_handle_buffered(int buffer_size, Input* __restrict states, int state_count, RingMemory* ring, uint64 time) +int32 input_handle_buffered(int buffer_size, Input* __restrict states, int state_count, RingMemory* ring, uint64 time) { + int32 input_count = 0; uint32 cb_size; GetRawInputBuffer(NULL, &cb_size, sizeof(RAWINPUTHEADER)); if (!cb_size) { - return; + return 0; } // Max input messages (e.g. 16) @@ -363,13 +372,15 @@ void input_handle_buffered(int buffer_size, Input* __restrict states, int state_ break; } - input_raw_handle(pri, states, state_count, time); + input_count += input_raw_handle(pri, states, state_count, time); pri = NEXTRAWINPUTBLOCK(pri); } } ASSERT_SIMPLE(input != (uint32) -1); + + return input_count; } #endif \ No newline at end of file diff --git a/stdlib/HashMap.h b/stdlib/HashMap.h index fc7fdb0..1f6a99c 100644 --- a/stdlib/HashMap.h +++ b/stdlib/HashMap.h @@ -14,6 +14,7 @@ #include "../memory/BufferMemory.h" #include "../memory/ChunkMemory.h" #include "Types.h" +#include "../utils/StringUtils.h" #define MAX_KEY_LENGTH 32 @@ -77,7 +78,8 @@ void hashmap_create(HashMap* hm, int32 count, int32 element_size, RingMemory* ri byte* data = ring_get_memory( ring, count * (sizeof(void *) + element_size) - + CEIL_DIV(count, 64) * sizeof(hm->buf.free) + + CEIL_DIV(count, 64) * sizeof(hm->buf.free), + 0, true ); hm->table = (void **) data; @@ -130,8 +132,18 @@ void hashmap_insert(HashMap* hm, const char* key, int32 value) { entry->key[MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = (HashEntryInt32 *) hm->table[index]; - hm->table[index] = entry; + entry->next = NULL; + + if (hm->table[index]) { + HashEntryInt32* tmp = (HashEntryInt32 *) hm->table[index]; + while(tmp->next) { + tmp = tmp->next; + } + + tmp->next = entry; + } else { + hm->table[index] = entry; + } } void hashmap_insert(HashMap* hm, const char* key, int64 value) { @@ -145,8 +157,18 @@ void hashmap_insert(HashMap* hm, const char* key, int64 value) { entry->key[MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = (HashEntryInt64 *) hm->table[index]; - hm->table[index] = entry; + entry->next = NULL; + + if (hm->table[index]) { + HashEntryInt64* tmp = (HashEntryInt64 *) hm->table[index]; + while(tmp->next) { + tmp = tmp->next; + } + + tmp->next = entry; + } else { + hm->table[index] = entry; + } } void hashmap_insert(HashMap* hm, const char* key, uintptr_t value) { @@ -160,8 +182,18 @@ void hashmap_insert(HashMap* hm, const char* key, uintptr_t value) { entry->key[MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = (HashEntryUIntPtr *) hm->table[index]; - hm->table[index] = entry; + entry->next = NULL; + + if (hm->table[index]) { + HashEntryUIntPtr* tmp = (HashEntryUIntPtr *) hm->table[index]; + while(tmp->next) { + tmp = tmp->next; + } + + tmp->next = entry; + } else { + hm->table[index] = entry; + } } void hashmap_insert(HashMap* hm, const char* key, void* value) { @@ -175,8 +207,18 @@ void hashmap_insert(HashMap* hm, const char* key, void* value) { entry->key[MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = (HashEntryVoidP *) hm->table[index]; - hm->table[index] = entry; + entry->next = NULL; + + if (hm->table[index]) { + HashEntryVoidP* tmp = (HashEntryVoidP *) hm->table[index]; + while(tmp->next) { + tmp = tmp->next; + } + + tmp->next = entry; + } else { + hm->table[index] = entry; + } } void hashmap_insert(HashMap* hm, const char* key, f32 value) { @@ -190,8 +232,18 @@ void hashmap_insert(HashMap* hm, const char* key, f32 value) { entry->key[MAX_KEY_LENGTH - 1] = '\0'; entry->value = value; - entry->next = (HashEntryFloat *) hm->table[index]; - hm->table[index] = entry; + entry->next = NULL; + + if (hm->table[index]) { + HashEntryFloat* tmp = (HashEntryFloat *) hm->table[index]; + while(tmp->next) { + tmp = tmp->next; + } + + tmp->next = entry; + } else { + hm->table[index] = entry; + } } void hashmap_insert(HashMap* hm, const char* key, const char* value) { @@ -207,8 +259,18 @@ void hashmap_insert(HashMap* hm, const char* key, const char* value) { strncpy(entry->value, value, MAX_KEY_LENGTH); entry->value[MAX_KEY_LENGTH - 1] = '\0'; - entry->next = (HashEntryStr *) hm->table[index]; - hm->table[index] = entry; + entry->next = NULL; + + if (hm->table[index]) { + HashEntryStr* tmp = (HashEntryStr *) hm->table[index]; + while(tmp->next) { + tmp = tmp->next; + } + + tmp->next = entry; + } else { + hm->table[index] = entry; + } } void hashmap_insert(HashMap* hm, const char* key, byte* value) { @@ -225,8 +287,18 @@ void hashmap_insert(HashMap* hm, const char* key, byte* value) { memcpy(entry->value, value, hm->buf.chunk_size - sizeof(HashEntry)); - entry->next = (HashEntry *) hm->table[index]; - hm->table[index] = entry; + entry->next = NULL; + + if (hm->table[index]) { + HashEntry* tmp = (HashEntry *) hm->table[index]; + while(tmp->next) { + tmp = tmp->next; + } + + tmp->next = entry; + } else { + hm->table[index] = entry; + } } HashEntry* hashmap_get_entry(HashMap* hm, const char* key) { diff --git a/ui/UIAttribute.h b/ui/UIAttribute.h index 66e1066..f99257d 100644 --- a/ui/UIAttribute.h +++ b/ui/UIAttribute.h @@ -24,6 +24,11 @@ enum UIAttributeType { UI_ATTRIBUTE_TYPE_TYPE, UI_ATTRIBUTE_TYPE_STYLE, + UI_ATTRIBUTE_TYPE_DIMENSION_X, + UI_ATTRIBUTE_TYPE_DIMENSION_Y, + UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH, + UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT, + UI_ATTRIBUTE_TYPE_CONTENT, UI_ATTRIBUTE_TYPE_CONTENT_ALIGN_H, UI_ATTRIBUTE_TYPE_CONTENT_ALIGN_V, @@ -44,9 +49,6 @@ enum UIAttributeType { UI_ATTRIBUTE_TYPE_POSITION_Y, UI_ATTRIBUTE_TYPE_PARENT, - UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH, - UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT, - UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR_INDEX, UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR, UI_ATTRIBUTE_TYPE_BACKGROUND_IMG, @@ -103,13 +105,115 @@ UIAttribute* ui_attribute_from_group(UIAttributeGroup* group, UIAttributeType ty return NULL; } -constexpr const char* ui_attribute_type_to_string(int32 e) +constexpr const char* ui_attribute_type_to_string_const(UIAttributeType e) { switch (e) { case UI_ATTRIBUTE_TYPE_TYPE: return "type"; case UI_ATTRIBUTE_TYPE_STYLE: return "style"; + case UI_ATTRIBUTE_TYPE_DIMENSION_X: + return "x"; + case UI_ATTRIBUTE_TYPE_DIMENSION_Y: + return "y"; + case UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH: + return "width"; + case UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT: + return "height"; + case UI_ATTRIBUTE_TYPE_FONT_NAME: + return "font_name"; + case UI_ATTRIBUTE_TYPE_FONT_COLOR: + return "font_color"; + case UI_ATTRIBUTE_TYPE_FONT_SIZE: + return "font_size"; + case UI_ATTRIBUTE_TYPE_FONT_WEIGHT: + return "font_weight"; + case UI_ATTRIBUTE_TYPE_FONT_LINE_HEIGHT: + return "font_line_height"; + case UI_ATTRIBUTE_TYPE_ALIGN_H: + return "align_h"; + case UI_ATTRIBUTE_TYPE_ALIGN_V: + return "align_v"; + case UI_ATTRIBUTE_TYPE_ZINDEX: + return "zindex"; + case UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR: + return "background_color"; + case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG: + return "background_img"; + case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_OPACITY: + return "background_img_opacity"; + case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_V: + return "background_img_position_v"; + case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_H: + return "background_img_position_h"; + case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_STYLE: + return "background_img_style"; + case UI_ATTRIBUTE_TYPE_BORDER_COLOR: + return "border_color"; + case UI_ATTRIBUTE_TYPE_BORDER_WIDTH: + return "border_width"; + case UI_ATTRIBUTE_TYPE_BORDER_TOP_COLOR: + return "border_top_color"; + case UI_ATTRIBUTE_TYPE_BORDER_TOP_WIDTH: + return "border_top_width"; + case UI_ATTRIBUTE_TYPE_BORDER_RIGHT_COLOR: + return "border_right_color"; + case UI_ATTRIBUTE_TYPE_BORDER_RIGHT_WIDTH: + return "border_right_width"; + case UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_COLOR: + return "border_bottom_color"; + case UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_WIDTH: + return "border_bottom_width"; + case UI_ATTRIBUTE_TYPE_BORDER_LEFT_COLOR: + return "border_left_color"; + case UI_ATTRIBUTE_TYPE_BORDER_LEFT_WIDTH: + return "border_left_width"; + case UI_ATTRIBUTE_TYPE_PADDING: + return "padding"; + case UI_ATTRIBUTE_TYPE_PADDING_TOP: + return "padding_top"; + case UI_ATTRIBUTE_TYPE_PADDING_RIGHT: + return "padding_right"; + case UI_ATTRIBUTE_TYPE_PADDING_BOTTOM: + return "padding_bottom"; + case UI_ATTRIBUTE_TYPE_PADDING_LEFT: + return "padding_left"; + case UI_ATTRIBUTE_TYPE_SHADOW_INNER_COLOR: + return "shadow_inner_color"; + case UI_ATTRIBUTE_TYPE_SHADOW_INNER_ANGLE: + return "shadow_inner_angle"; + case UI_ATTRIBUTE_TYPE_SHADOW_INNER_DISTANCE: + return "shadow_inner_distance"; + case UI_ATTRIBUTE_TYPE_SHADOW_OUTER_COLOR: + return "shadow_outer_color"; + case UI_ATTRIBUTE_TYPE_SHADOW_OUTER_ANGLE: + return "shadow_outer_angle"; + case UI_ATTRIBUTE_TYPE_SHADOW_OUTER_DISTANCE: + return "shadow_outer_distance"; + case UI_ATTRIBUTE_TYPE_TRANSITION_ANIMATION: + return "transition_animation"; + case UI_ATTRIBUTE_TYPE_TRANSITION_DURATION: + return "transition_duration"; + } + + return NULL; +} + +const char* ui_attribute_type_to_string(UIAttributeType e) +{ + switch (e) { + case UI_ATTRIBUTE_TYPE_TYPE: + return "type"; + case UI_ATTRIBUTE_TYPE_STYLE: + return "style"; + case UI_ATTRIBUTE_TYPE_DIMENSION_X: + return "x"; + case UI_ATTRIBUTE_TYPE_DIMENSION_Y: + return "y"; + case UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH: + return "width"; + case UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT: + return "height"; case UI_ATTRIBUTE_TYPE_FONT_NAME: return "font_name"; case UI_ATTRIBUTE_TYPE_FONT_COLOR: diff --git a/ui/UIElementType.h b/ui/UIElementType.h index c5d0adf..93eac71 100644 --- a/ui/UIElementType.h +++ b/ui/UIElementType.h @@ -1,6 +1,8 @@ #ifndef TOS_UI_ELEMENT_TYPE_H #define TOS_UI_ELEMENT_TYPE_H +#include + enum UIElementType { UI_ELEMENT_TYPE_BUTTON, UI_ELEMENT_TYPE_SELECT, @@ -19,7 +21,39 @@ enum UIElementType { UI_ELEMENT_TYPE_SIZE, }; -constexpr const char* ui_element_type_to_string(UIElementType e) +constexpr const char* ui_element_type_to_string_const(UIElementType e) +{ + switch (e) { + case UI_ELEMENT_TYPE_BUTTON: + return "button"; + case UI_ELEMENT_TYPE_SELECT: + return "select"; + case UI_ELEMENT_TYPE_DROPDOWN: + return "dropdown"; + case UI_ELEMENT_TYPE_TEXTFIELD: + return "textfield"; + case UI_ELEMENT_TYPE_TEXTAREA: + return "textarea"; + case UI_ELEMENT_TYPE_IMAGE: + return "image"; + case UI_ELEMENT_TYPE_TEXT: + return "text"; + case UI_ELEMENT_TYPE_LINK: + return "link"; + case UI_ELEMENT_TYPE_TABLE: + return "table"; + case UI_ELEMENT_TYPE_VIEW_WINDOW: + return "view_window"; + case UI_ELEMENT_TYPE_VIEW_PANEL: + return "view_panel"; + case UI_ELEMENT_TYPE_VIEW_TAB: + return "view_tab"; + } + + return NULL; +} + +const char* ui_element_type_to_string(UIElementType e) { switch (e) { case UI_ELEMENT_TYPE_BUTTON: diff --git a/ui/UITheme.h b/ui/UITheme.h index 3a10bde..6237de7 100644 --- a/ui/UITheme.h +++ b/ui/UITheme.h @@ -96,14 +96,10 @@ int compare_by_attribute_id(const void* a, const void* b) { // WARNING: theme needs to have memory already reserved and asigned to data void theme_from_file_txt( - RingMemory* ring, - const char* path, - UIThemeStyle* theme + UIThemeStyle* theme, + byte* data ) { - FileBody file; - file_read(path, &file, ring); - - char* pos = (char *) file.content; + char* pos = (char *) data; // move past the version string pos += 8; @@ -147,7 +143,9 @@ void theme_from_file_txt( UIAttributeGroup* temp_group = NULL; - pos = (char *) file.content; + pos = (char *) data; + pos += 8; // move past version + while (*pos != '\0') { while (*pos == ' ' || *pos == '\t') { ++pos; @@ -182,7 +180,9 @@ void theme_from_file_txt( // 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 == '.') { // Named style - if (temp_group != NULL) { + block_open = true; + + if (temp_group) { // Before we insert a new group we have to sort the attributes // since this makes searching them later on more efficient. qsort(temp_group->attributes, temp_group->attribute_size, sizeof(UIAttribute), compare_by_attribute_id); @@ -193,7 +193,8 @@ void theme_from_file_txt( temp_group = (UIAttributeGroup *) (theme->data + data_offset); temp_group->attribute_size = 0; - data_offset += sizeof(temp_group->attribute_size); + temp_group->attributes = (UIAttribute *) (theme->data + data_offset + sizeof(UIAttributeGroup)); + data_offset += sizeof(UIAttributeGroup); } continue; @@ -209,7 +210,7 @@ void theme_from_file_txt( attribute_name[i] = '\0'; // Skip any white spaces or other delimeters - while (*pos == ' ' || *pos == ':') { + while (*pos == ' ' || *pos == '\t' || *pos == ':') { ++pos; } @@ -217,7 +218,7 @@ void theme_from_file_txt( // Handle different attribute types UIAttribute attribute = {}; - if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_TYPE), attribute_name) == 0) { + if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_TYPE), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_TYPE; char str[32]; @@ -227,16 +228,16 @@ void theme_from_file_txt( } *temp = '\0'; + for (int32 j = 0; j < UI_ELEMENT_TYPE_SIZE; ++j) { + if (strcmp(str, ui_element_type_to_string((UIElementType) j)) == 0) { - for (int32 i = 0; i < UI_ELEMENT_TYPE_SIZE; ++i) { - if (strcmp(str, ui_attribute_type_to_string(i)) == 0) { - attribute.value_int = i; + attribute.value_int = j; break; } } ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_STYLE), attribute_name) == 0) { + } 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; @@ -246,7 +247,7 @@ void theme_from_file_txt( *temp = '\0'; ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_FONT_COLOR), attribute_name) == 0) { + } 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; @@ -257,25 +258,25 @@ void theme_from_file_txt( 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; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_FONT_SIZE), attribute_name) == 0) { + } 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 = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_FONT_WEIGHT), attribute_name) == 0) { + attribute.value_float = strtof(pos, &pos); ++pos; + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_FONT_WEIGHT), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_FONT_WEIGHT; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_FONT_LINE_HEIGHT), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_FONT_LINE_HEIGHT), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_FONT_LINE_HEIGHT; - attribute.value_float = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_ALIGN_H), attribute_name) == 0) { + attribute.value_float = strtof(pos, &pos); ++pos; + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_ALIGN_H), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_ALIGN_H; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_ALIGN_V), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_ALIGN_V), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_ALIGN_V; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_ZINDEX), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_ZINDEX), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_ZINDEX; attribute.value_float = SWAP_ENDIAN_LITTLE(strtof(pos, &pos)); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR), attribute_name) == 0) { ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR; @@ -286,7 +287,7 @@ void theme_from_file_txt( 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; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG), attribute_name) == 0) { + } 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; @@ -295,19 +296,19 @@ void theme_from_file_txt( } attribute.value_str[i] = '\0'; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_OPACITY), attribute_name) == 0) { + } 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)); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_V), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_V), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_V; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_H), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_H), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_H; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_STYLE), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_STYLE), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_STYLE; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_COLOR), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_COLOR), attribute_name) == 0) { ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_COLOR; @@ -318,10 +319,10 @@ void theme_from_file_txt( 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; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_WIDTH), attribute_name) == 0) { + } 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); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_TOP_COLOR), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_TOP_COLOR), attribute_name) == 0) { ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_TOP_COLOR; @@ -332,10 +333,10 @@ void theme_from_file_txt( 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; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_TOP_WIDTH), attribute_name) == 0) { + } 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); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_RIGHT_COLOR), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_RIGHT_COLOR), attribute_name) == 0) { ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_RIGHT_COLOR; @@ -346,10 +347,10 @@ void theme_from_file_txt( 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; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_RIGHT_WIDTH), attribute_name) == 0) { + } 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); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_COLOR), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_COLOR), attribute_name) == 0) { ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_COLOR; @@ -360,10 +361,10 @@ void theme_from_file_txt( 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; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_WIDTH), attribute_name) == 0) { + } 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); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_LEFT_COLOR), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_LEFT_COLOR), attribute_name) == 0) { ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_LEFT_COLOR; @@ -374,25 +375,25 @@ void theme_from_file_txt( 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; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_LEFT_WIDTH), attribute_name) == 0) { + } 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); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING_TOP), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING_TOP), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING_TOP; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING_RIGHT), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING_RIGHT), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING_RIGHT; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING_BOTTOM), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING_BOTTOM), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING_BOTTOM; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING_LEFT), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING_LEFT), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING_LEFT; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_INNER_COLOR), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_INNER_COLOR), attribute_name) == 0) { ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_INNER_COLOR; @@ -403,13 +404,13 @@ void theme_from_file_txt( 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; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_INNER_ANGLE), attribute_name) == 0) { + } 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); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_INNER_DISTANCE), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_INNER_DISTANCE), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_INNER_DISTANCE; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_COLOR), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_COLOR), attribute_name) == 0) { ++pos; // Skip '#' attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_OUTER_COLOR; @@ -420,24 +421,28 @@ void theme_from_file_txt( 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; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_ANGLE), attribute_name) == 0) { + } 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); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_DISTANCE), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_DISTANCE), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_OUTER_DISTANCE; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_TRANSITION_ANIMATION), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_TRANSITION_ANIMATION), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_TRANSITION_ANIMATION; attribute.value_int = strtoul(pos, &pos, 10); ++pos; - } else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_TRANSITION_DURATION), attribute_name) == 0) { + } else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_TRANSITION_DURATION), attribute_name) == 0) { attribute.attribute_id = UI_ATTRIBUTE_TYPE_TRANSITION_DURATION; attribute.value_float = strtof(pos, &pos); ++pos; } else { + while (*pos != '\n' && *pos != '\0') { + ++pos; + } + continue; } // Again, currently this if check is redundant but it wasn't in the past and we may need it again in the future. - if (block_name[0] == '#') { + if (block_name[0] == '#' || block_name[0] == '.') { // Named block memcpy( temp_group->attributes + temp_group->attribute_size, @@ -480,7 +485,8 @@ void theme_from_file( // Prepare hashmap (incl. reserve memory) by initializing it the same way we originally did // Of course we still need to populate the data using hashmap_load() - hashmap_create(&theme->hash_map, SWAP_ENDIAN_LITTLE(*((uint64 *) pos)), sizeof(HashEntryInt64), theme->data); + // The value is a int64 (because this is the value of the chunk buffer size but the hashmap only allows int32) + hashmap_create(&theme->hash_map, (int32) SWAP_ENDIAN_LITTLE(*((uint64 *) pos)), sizeof(HashEntryInt64), theme->data); pos += hashmap_load(&theme->hash_map, pos); // theme data diff --git a/utils/StringUtils.h b/utils/StringUtils.h index 24ca65d..cb71f4f 100644 --- a/utils/StringUtils.h +++ b/utils/StringUtils.h @@ -15,16 +15,6 @@ #include "../stdlib/Types.h" -constexpr -size_t strlen_const(const char* str) { - size_t len = 0; - while (str[len] != '\0') { - ++len; - } - - return len; -} - inline int32 utf8_encode(uint32 codepoint, char* out) { @@ -244,13 +234,15 @@ inline char* strsep(const char* *sp, const char* sep) return s; } -inline void +inline int64 str_concat( const char* src1, const char* src2, char* dst ) { - size_t len = strlen(src1); + int64 len = strlen(src1); + int64 len_total = len; + memcpy(dst, src1, len); dst += len; @@ -259,9 +251,11 @@ str_concat( dst += len; *dst = '\0'; + + return len_total + len; } -inline void +inline int64 str_concat( const char* src1, size_t src1_length, const char* src2, size_t src2_length, @@ -274,6 +268,8 @@ str_concat( dst += src2_length; *dst = '\0'; + + return src1_length + src2_length; } inline @@ -416,4 +412,23 @@ void str_replace(const char* str, const char* __restrict search, const char* __r strcpy(result_ptr, str); } +void print_bytes(const void* ptr, size_t size) +{ + const unsigned char* bytePtr = (const unsigned char *) ptr; + + int32 count = 0; + + for (int32 i = 0; i < size; i++) { + ++count; + if (count == 1) { + printf("%03d - %03d: %02x ", i + 1, i + 8, bytePtr[i]); + } else if (count < 8) { + printf("%02x ", bytePtr[i]); + } else { + printf("%02x\n", bytePtr[i]); + count = 0; + } + } +} + #endif \ No newline at end of file