first attempt at fixing toolset

This commit is contained in:
Dennis Eichhorn 2024-10-24 02:47:29 +02:00
parent 5685a827a2
commit ba244f8155
22 changed files with 2022 additions and 1136 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,6 +6,8 @@
#include "Log.h"
#include "TimingStat.h"
global_persist DebugContainer* debug_container = NULL;
#if _WIN32
#include <windows.h>
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;
}

View File

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

View File

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

View File

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

View File

@ -243,6 +243,8 @@ struct CSettings {
// UI settings
// Themes
char game_language[2];
char game_ui_theme[32];
byte game_ui_size = 128;

View File

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

View File

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

View File

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

View File

@ -12,8 +12,8 @@
#include <stdio.h>
#include <stdint.h>
#include "../stdlib/Types.h"
#include "StringUtils.h"
#include "../stdlib/simd/SIMD_Helper.h"
#include "StringUtils.h"
#if _WIN32
#include <winsock2.h>
@ -24,6 +24,9 @@
#include <dxgi.h>
#include <wbemidl.h>
#include <comdef.h>
#include <winnls.h>
#else
#include <locale.h>
#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);

View File

@ -14,6 +14,10 @@
#include <stdio.h>
#include <stdlib.h>
#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);

595
platform/win32/SystemInfo.h Normal file
View File

@ -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 <stdio.h>
#include <stdint.h>
#include "../../stdlib/Types.h"
#include "../../stdlib/simd/SIMD_Helper.h"
#include "../../utils/StringUtils.h"
#include <winsock2.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <d3d11.h>
#include <dxgi.h>
#include <wbemidl.h>
#include <comdef.h>
#include <winnls.h>
#ifdef _MSC_VER
// @performance Do we really need all these libs, can't we simplify that?!
#include <intrin.h>
#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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
#ifndef TOS_UI_ELEMENT_TYPE_H
#define TOS_UI_ELEMENT_TYPE_H
#include <stdio.h>
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:

View File

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

View File

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