mirror of
https://github.com/Karaka-Management/cOMS.git
synced 2026-01-11 03:08:41 +00:00
first attempt at fixing toolset
This commit is contained in:
parent
5685a827a2
commit
ba244f8155
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
23
font/Font.h
23
font/Font.h
|
|
@ -7,6 +7,12 @@
|
|||
#include "../utils/Utils.h"
|
||||
#include "../stdlib/simd/SIMD_I32.h"
|
||||
|
||||
#if _WIN32
|
||||
#include "../platform/win32/UtilsWin32.h"
|
||||
#else
|
||||
#include "../platform/linux/UtilsLinux.h"
|
||||
#endif
|
||||
|
||||
struct GlyphMetrics {
|
||||
f32 width; // Width of the glyph
|
||||
f32 height; // Height of the glyph
|
||||
|
|
@ -57,15 +63,11 @@ Glyph* font_glyph_find(Font* font, uint32 codepoint)
|
|||
}
|
||||
|
||||
void font_from_file_txt(
|
||||
RingMemory* ring,
|
||||
const char* path,
|
||||
Font* font
|
||||
Font* font,
|
||||
byte* data
|
||||
)
|
||||
{
|
||||
FileBody file;
|
||||
file_read(path, &file, ring);
|
||||
|
||||
char* pos = (char *) file.content;
|
||||
char* pos = (char *) data;
|
||||
|
||||
bool start = true;
|
||||
char block_name[32];
|
||||
|
|
@ -87,6 +89,8 @@ void font_from_file_txt(
|
|||
++i;
|
||||
}
|
||||
|
||||
block_name[i] = '\0';
|
||||
|
||||
// Go to value
|
||||
while (*pos == ' ' || *pos == '\t' || *pos == ':') {
|
||||
++pos;
|
||||
|
|
@ -94,7 +98,7 @@ void font_from_file_txt(
|
|||
|
||||
if (strcmp(block_name, "texture") == 0) {
|
||||
while (*pos != '\n') {
|
||||
*texture_pos++ == *pos++;
|
||||
*texture_pos++ = *pos++;
|
||||
}
|
||||
} else if (strcmp(block_name, "font_size") == 0) {
|
||||
font->size = strtof(pos, &pos);
|
||||
|
|
@ -111,8 +115,7 @@ void font_from_file_txt(
|
|||
}
|
||||
|
||||
// Go to next line
|
||||
while (*pos++ != '\n') {};
|
||||
++pos;
|
||||
while (*pos != '\0' && *pos++ != '\n') {};
|
||||
} else {
|
||||
// Parsing glyphs
|
||||
// In the text file we don't have to define width and height of the character, we calculate that here
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -243,6 +243,8 @@ struct CSettings {
|
|||
|
||||
// UI settings
|
||||
// Themes
|
||||
char game_language[2];
|
||||
|
||||
char game_ui_theme[32];
|
||||
byte game_ui_size = 128;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
939
object/Mesh.h
939
object/Mesh.h
|
|
@ -13,7 +13,17 @@
|
|||
#include "FaceType.h"
|
||||
#include "../stdlib/Types.h"
|
||||
|
||||
#if _WIN32
|
||||
#include "../platform/win32/UtilsWin32.h"
|
||||
#else
|
||||
#include "../platform/linux/UtilsLinux.h"
|
||||
#endif
|
||||
|
||||
#include "../memory/RingMemory.h"
|
||||
#include "../stdlib/simd/SIMD_I32.h"
|
||||
#include "../utils/EndianUtils.h"
|
||||
|
||||
#define MESH_VERSION 1
|
||||
|
||||
// @todo how to handle different objects and groups?
|
||||
// maybe make a mesh hold other meshes?
|
||||
|
|
@ -81,4 +91,933 @@ struct Mesh {
|
|||
Mesh* meshes;
|
||||
};
|
||||
|
||||
// @todo also handle textures etc.
|
||||
// WARNING: mesh needs to have memory already reserved and asigned to data
|
||||
void mesh_from_file_txt(
|
||||
Mesh* mesh,
|
||||
byte* data
|
||||
) {
|
||||
char* pos = (char *) data;
|
||||
|
||||
// move past the version string
|
||||
pos += 8;
|
||||
|
||||
mesh->version = strtol(pos, &pos, 10); ++pos;
|
||||
|
||||
int32 object_index = 0;
|
||||
int32 group_index = 0;
|
||||
|
||||
mesh->vertices = (f32 *) mesh->data;
|
||||
|
||||
mesh->vertex_count = 0;
|
||||
mesh->normal_count = 0;
|
||||
mesh->tex_coord_count = 0;
|
||||
mesh->color_count = 0;
|
||||
|
||||
mesh->face_count = 0;
|
||||
mesh->face_normal_count = 0;
|
||||
mesh->face_tex_coord_count = 0;
|
||||
mesh->face_color_count = 0;
|
||||
|
||||
uint32 temp_color_count = 0;
|
||||
|
||||
while (*pos != '\0') {
|
||||
while (*pos == ' ' || *pos == '\t' || *pos == '\n') {
|
||||
++pos;
|
||||
}
|
||||
|
||||
if (*pos == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse type
|
||||
// WARNING: The code below could fail if [1] is outside of range
|
||||
// However that should never happen for well formed files
|
||||
int32 state = 0;
|
||||
if (*pos == 'v' && pos[1] == ' ') {
|
||||
state = 1;
|
||||
} else if (*pos == 'v' && pos[1] == 'n') {
|
||||
state = 2;
|
||||
} else if (*pos == 'v' && pos[1] == 't') {
|
||||
state = 3;
|
||||
} else if (*pos == 'v' && pos[1] == 'p') {
|
||||
state = 4;
|
||||
} else if (*pos == 'o' && pos[1] == ' ') {
|
||||
state = 5;
|
||||
} else if (*pos == 's' && pos[1] == ' ') {
|
||||
state = 6;
|
||||
} else if (*pos == 'f' && pos[1] == ' ') {
|
||||
state = 7;
|
||||
} else if (*pos == 'g' && pos[1] == ' ') {
|
||||
state = 8;
|
||||
} else if (*pos == 'l' && pos[1] == ' ') {
|
||||
state = 9;
|
||||
} else if (*pos == 'm' && pos[1] == 't') {
|
||||
state = 10;
|
||||
} else if (*pos == 'h' && pos[1] == 'i') {
|
||||
state = 11;
|
||||
} else if (*pos == 'a' && pos[1] == 'n') {
|
||||
state = 12;
|
||||
} else if (*pos == 'u' && pos[3] == 'm') {
|
||||
state = 13;
|
||||
} else if (*pos == 'u' && pos[3] == 'h') {
|
||||
state = 14;
|
||||
} else {
|
||||
// not supported or comment
|
||||
while (*pos != '\n' && *pos != '\0') {
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
// move past keyword
|
||||
while (*pos != ' ' && *pos != '\n' && *pos != '\0') {
|
||||
++pos;
|
||||
}
|
||||
|
||||
// move past whitespaces and newline
|
||||
bool is_next_line = false;
|
||||
while (*pos == ' ' || *pos == '\n') {
|
||||
is_next_line |= *pos == '\n';
|
||||
++pos;
|
||||
}
|
||||
|
||||
if (*pos == '\0' || is_next_line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: we always load a file in the format: POSITON + NORMAL + TEXTURE + COLOR
|
||||
// EVEN if some of the data is missing. This is necessary to keep the memory kinda in line.
|
||||
// The actual binary file later will have the minimized layout.
|
||||
|
||||
// handle data types
|
||||
switch (state) {
|
||||
case 0: break;
|
||||
case 1: {
|
||||
// 'v'
|
||||
if (mesh->vertex_count == 0) {
|
||||
mesh->vertex_type |= VERTEX_TYPE_POSITION;
|
||||
}
|
||||
|
||||
mesh->vertices[mesh->vertex_count * 3] = strtof(pos, &pos); ++pos;
|
||||
mesh->vertices[mesh->vertex_count * 3 + 1] = strtof(pos, &pos); ++pos;
|
||||
mesh->vertices[mesh->vertex_count * 3 + 2] = strtof(pos, &pos); ++pos;
|
||||
|
||||
// has color information
|
||||
// @todo Move to own case statement // 'co'
|
||||
if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') {
|
||||
if (mesh->vertex_count == 0) {
|
||||
mesh->vertex_type |= VERTEX_TYPE_COLOR;
|
||||
}
|
||||
|
||||
mesh->vertices[mesh->vertex_count * 12 + 8] = strtof(pos, &pos); ++pos;
|
||||
mesh->vertices[mesh->vertex_count * 12 + 9] = strtof(pos, &pos); ++pos;
|
||||
mesh->vertices[mesh->vertex_count * 12 + 10] = strtof(pos, &pos); ++pos;
|
||||
|
||||
// handle optional alpha [a]
|
||||
if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') {
|
||||
mesh->vertices[mesh->vertex_count * 12 + 11] = strtof(pos, &pos); ++pos;
|
||||
} else {
|
||||
mesh->vertices[mesh->vertex_count * 12 + 11] = 1.0f;
|
||||
}
|
||||
|
||||
++temp_color_count;
|
||||
}
|
||||
|
||||
++mesh->vertex_count;
|
||||
} break;
|
||||
case 2: {
|
||||
// 'vn'
|
||||
// @bug This requires normals to be defined before textures
|
||||
if (mesh->normal_count == 0) {
|
||||
mesh->normals = mesh->vertices + mesh->vertex_count * 3;
|
||||
}
|
||||
|
||||
mesh->normals[mesh->normal_count * 3] = strtof(pos, &pos); ++pos;
|
||||
mesh->normals[mesh->normal_count * 3 + 1] = strtof(pos, &pos); ++pos;
|
||||
mesh->normals[mesh->normal_count * 3 + 2] = strtof(pos, &pos); ++pos;
|
||||
|
||||
++mesh->normal_count;
|
||||
} break;
|
||||
case 3: {
|
||||
// 'vt'
|
||||
if (mesh->tex_coord_count == 0) {
|
||||
mesh->tex_coords = mesh->vertices + mesh->vertex_count * 3 + mesh->normal_count * 3;
|
||||
}
|
||||
|
||||
mesh->tex_coords[mesh->tex_coord_count * 2] = strtof(pos, &pos); ++pos;
|
||||
mesh->tex_coords[mesh->tex_coord_count * 2 + 1] = strtof(pos, &pos); ++pos;
|
||||
|
||||
++mesh->tex_coord_count;
|
||||
} break;
|
||||
case 4: {
|
||||
// 'vp'
|
||||
strtof(pos, &pos); ++pos;
|
||||
|
||||
// handle optional [v]
|
||||
if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') {
|
||||
strtof(pos, &pos); ++pos;
|
||||
|
||||
// handle optional [w]
|
||||
if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') {
|
||||
strtof(pos, &pos); ++pos;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case 5: {
|
||||
// 'o'
|
||||
char text[100];
|
||||
int32 i = 0;
|
||||
while (*pos != '\0' && *pos != ' ') {
|
||||
text[i++] = *pos++;
|
||||
}
|
||||
text[i] = '\0';
|
||||
|
||||
++object_index;
|
||||
} break;
|
||||
case 6: {
|
||||
// 's'
|
||||
strtol(pos, &pos, 10); ++pos;
|
||||
} break;
|
||||
case 7: {
|
||||
// 'f'
|
||||
if (mesh->face_count == 0) {
|
||||
mesh->faces = (uint32 *) (mesh->vertices + mesh->vertex_count * 3 + mesh->normal_count * 3 + mesh->tex_coord_count * 2 + mesh->color_count * 4);
|
||||
}
|
||||
|
||||
int32 ftype = 0;
|
||||
char* tmp = pos;
|
||||
while (*tmp != ' ') {
|
||||
if (*tmp++ == '/') {
|
||||
++ftype;
|
||||
|
||||
if (*tmp++ == '/') {
|
||||
ftype = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int32 max_blocks = 3; // @todo this could actually be N. Might have to change in the future
|
||||
int32 block = 0;
|
||||
|
||||
while (*pos != '\0' && *pos != '\n') {
|
||||
if (ftype == 0) {
|
||||
// v1 v2 v3 ...
|
||||
if (mesh->face_count == 0) {
|
||||
mesh->face_type = FACE_TYPE_VERTICES;
|
||||
}
|
||||
|
||||
mesh->faces[(mesh->face_count * max_blocks * 1) + block] = strtol(pos, &pos, 10) - 1; ++pos;
|
||||
} else if (ftype == 1) {
|
||||
// v1/vt1 v2/vt2 v3/vt3 ...
|
||||
if (mesh->face_count == 0) {
|
||||
mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_TEXTURES;
|
||||
}
|
||||
|
||||
mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos;
|
||||
mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos;
|
||||
} else if (ftype == 2) {
|
||||
// v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...
|
||||
if (mesh->face_count == 0) {
|
||||
mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_TEXTURES | FACE_TYPE_NORMALS;
|
||||
}
|
||||
|
||||
mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3] = strtol(pos, &pos, 10) - 1; ++pos;
|
||||
mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3 + 1] = strtol(pos, &pos, 10) - 1; ++pos;
|
||||
mesh->faces[(mesh->face_count * max_blocks * 3) + block * 3 + 2] = strtol(pos, &pos, 10) - 1; ++pos;
|
||||
} else if (ftype == 3) {
|
||||
// v1//vn1 v2//vn2 v3//vn3 ...
|
||||
if (mesh->face_count == 0) {
|
||||
mesh->face_type = FACE_TYPE_VERTICES | FACE_TYPE_NORMALS;
|
||||
}
|
||||
|
||||
mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2] = strtol(pos, &pos, 10) - 1; ++pos;
|
||||
++pos;
|
||||
mesh->faces[(mesh->face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, &pos, 10) - 1; ++pos;
|
||||
}
|
||||
|
||||
++block;
|
||||
}
|
||||
|
||||
++mesh->face_count;
|
||||
} break;
|
||||
case 8: {
|
||||
// 'g'
|
||||
char text[100];
|
||||
int32 i = 0;
|
||||
while (*pos != '\0' && *pos != ' ') {
|
||||
text[i++] = *pos++;
|
||||
}
|
||||
text[i] = '\0';
|
||||
|
||||
++group_index;
|
||||
} break;
|
||||
case 9: {
|
||||
//l
|
||||
while (*pos != '\0' && *pos != '\n') {
|
||||
strtol(pos, &pos, 10); ++pos;
|
||||
}
|
||||
} break;
|
||||
case 10: {
|
||||
// 'mtllib'
|
||||
char text[100];
|
||||
int32 i = 0;
|
||||
while (*pos != '\0' && *pos != ' ') {
|
||||
text[i++] = *pos++;
|
||||
}
|
||||
text[i] = '\0';
|
||||
} break;
|
||||
case 11: {
|
||||
// 'hitlib'
|
||||
char text[100];
|
||||
int32 i = 0;
|
||||
while (*pos != '\0' && *pos != ' ') {
|
||||
text[i++] = *pos++;
|
||||
}
|
||||
text[i] = '\0';
|
||||
} break;
|
||||
case 12: {
|
||||
// 'anilib'
|
||||
char text[100];
|
||||
int32 i = 0;
|
||||
while (*pos != '\0' && *pos != ' ') {
|
||||
text[i++] = *pos++;
|
||||
}
|
||||
text[i] = '\0';
|
||||
} break;
|
||||
case 13: {
|
||||
// 'usemtl'
|
||||
char text[100];
|
||||
int32 i = 0;
|
||||
while (*pos != '\0' && *pos != ' ') {
|
||||
text[i++] = *pos++;
|
||||
}
|
||||
text[i] = '\0';
|
||||
} break;
|
||||
case 14: {
|
||||
// 'usehit'
|
||||
char text[100];
|
||||
int32 i = 0;
|
||||
while (*pos != '\0' && *pos != ' ') {
|
||||
text[i++] = *pos++;
|
||||
}
|
||||
text[i] = '\0';
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ObjectLoadingRestriction {
|
||||
OBJECT_LOADING_RESTRICTION_POSITION = 1,
|
||||
OBJECT_LOADING_RESTRICTION_NORMAL = 2,
|
||||
OBJECT_LOADING_RESTRICTION_TEXTURE = 4,
|
||||
OBJECT_LOADING_RESTRICTION_COLOR = 8,
|
||||
OBJECT_LOADING_RESTRICTION_FACES = 16,
|
||||
OBJECT_LOADING_RESTRICTION_EVERYTHING = 31
|
||||
};
|
||||
|
||||
// @todo sometimes we don't care about some data, we should have an option which defines which data should be loaded
|
||||
// this can improve performance for algorithms on this. e.g.:
|
||||
// on the server side we only care about the vertex positions for collision (no normals, no color, ...)
|
||||
int32 mesh_from_file(
|
||||
RingMemory* ring,
|
||||
const char* path,
|
||||
Mesh* mesh,
|
||||
const char* group = NULL,
|
||||
int32 load_format = OBJECT_LOADING_RESTRICTION_EVERYTHING,
|
||||
int32 size = 8
|
||||
)
|
||||
{
|
||||
FileBody file;
|
||||
file_read(path, &file, ring);
|
||||
|
||||
byte* pos = file.content;
|
||||
|
||||
// Read version
|
||||
mesh->version = *((int32 *) pos);
|
||||
pos += sizeof(mesh->version);
|
||||
|
||||
// Read base data
|
||||
mesh->vertex_type = *((int32 *) pos);
|
||||
pos += sizeof(mesh->vertex_type);
|
||||
|
||||
mesh->vertex_count = *((int32 *) pos);
|
||||
pos += sizeof(mesh->vertex_count);
|
||||
|
||||
mesh->normal_count = *((int32 *) pos);
|
||||
pos += sizeof(mesh->normal_count);
|
||||
|
||||
mesh->tex_coord_count = *((int32 *) pos);
|
||||
pos += sizeof(mesh->tex_coord_count);
|
||||
|
||||
mesh->color_count = *((int32 *) pos);
|
||||
pos += sizeof(mesh->color_count);
|
||||
|
||||
#if !_WIN32 && !__LITTLE_ENDIAN
|
||||
mesh->version = endian_swap(mesh->version);
|
||||
mesh->vertex_type = endian_swap(mesh->vertex_type);
|
||||
mesh->verted_count = endian_swap(mesh->verted_count);
|
||||
mesh->normal_count = endian_swap(mesh->normal_count);
|
||||
mesh->tex_coord_count = endian_swap(mesh->tex_coord_count);
|
||||
mesh->color_count = endian_swap(mesh->color_count);
|
||||
#endif
|
||||
|
||||
int32 vertex_size = 0;
|
||||
if (mesh->vertex_type & VERTEX_TYPE_POSITION) {
|
||||
vertex_size += 3;
|
||||
}
|
||||
|
||||
if (mesh->vertex_type & VERTEX_TYPE_NORMAL) {
|
||||
vertex_size += 3;
|
||||
}
|
||||
|
||||
if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) {
|
||||
vertex_size += 2;
|
||||
}
|
||||
|
||||
if (mesh->vertex_type & VERTEX_TYPE_COLOR) {
|
||||
vertex_size += 4;
|
||||
}
|
||||
|
||||
int32 offset = 0;
|
||||
if (mesh->vertex_count > 0) {
|
||||
memcpy(mesh->data, pos, sizeof(f32) * vertex_size * mesh->vertex_count);
|
||||
mesh->vertices = (f32 *) mesh->data;
|
||||
|
||||
pos += sizeof(f32) * vertex_size * mesh->vertex_count;
|
||||
offset += sizeof(f32) * vertex_size * mesh->vertex_count;
|
||||
}
|
||||
|
||||
if (mesh->normal_count > 0) {
|
||||
memcpy(mesh->data + offset, pos, sizeof(f32) * 3 * mesh->normal_count);
|
||||
mesh->normals = (f32 *) (mesh->data + offset);
|
||||
|
||||
pos += sizeof(f32) * 3 * mesh->normal_count;
|
||||
offset += sizeof(f32) * 3 * mesh->normal_count;
|
||||
}
|
||||
|
||||
if (mesh->tex_coord_count > 0) {
|
||||
memcpy(mesh->data + offset, pos, sizeof(f32) * 3 * mesh->tex_coord_count);
|
||||
mesh->tex_coords = (f32 *) (mesh->data + offset);
|
||||
|
||||
pos += sizeof(f32) * 2 * mesh->tex_coord_count;
|
||||
offset += sizeof(f32) * 2 * mesh->tex_coord_count;
|
||||
}
|
||||
|
||||
if (mesh->color_count > 0) {
|
||||
memcpy(mesh->data + offset, pos, sizeof(f32) * 4 * mesh->color_count);
|
||||
mesh->colors = (f32 *) (mesh->data + offset);
|
||||
|
||||
pos += sizeof(f32) * 4 * mesh->color_count;
|
||||
offset += sizeof(f32) * 4 * mesh->color_count;
|
||||
}
|
||||
|
||||
// Read face data
|
||||
mesh->face_type = *((int32 *) pos);
|
||||
pos += sizeof(mesh->face_type);
|
||||
|
||||
mesh->face_count = *((int32 *) pos);
|
||||
pos += sizeof(mesh->face_count);
|
||||
|
||||
mesh->face_normal_count = *((int32 *) pos);
|
||||
pos += sizeof(mesh->face_normal_count);
|
||||
|
||||
mesh->face_tex_coord_count = *((int32 *) pos);
|
||||
pos += sizeof(mesh->face_tex_coord_count);
|
||||
|
||||
mesh->face_color_count = *((int32 *) pos);
|
||||
pos += sizeof(mesh->face_color_count);
|
||||
|
||||
#if !_WIN32 && !__LITTLE_ENDIAN
|
||||
mesh->face_type = endian_swap(mesh->face_type);
|
||||
mesh->face_count = endian_swap(mesh->face_count);
|
||||
mesh->face_normal_count = endian_swap(mesh->face_normal_count);
|
||||
mesh->face_tex_coord_count = endian_swap(mesh->face_tex_coord_count);
|
||||
mesh->face_color_count = endian_swap(mesh->face_color_count);
|
||||
#endif
|
||||
|
||||
int32 face_size = 0;
|
||||
if (mesh->face_type & FACE_TYPE_VERTICES) {
|
||||
face_size += 3;
|
||||
}
|
||||
|
||||
if ((mesh->face_type & FACE_TYPE_NORMALS)) {
|
||||
face_size += 3;
|
||||
}
|
||||
|
||||
if ((mesh->face_type & FACE_TYPE_TEXTURES)) {
|
||||
face_size += 3;
|
||||
}
|
||||
|
||||
if ((mesh->face_type & FACE_TYPE_COLORS)) {
|
||||
face_size += 3;
|
||||
}
|
||||
|
||||
// faces can be either in the form
|
||||
// f: v/vt/vn ...
|
||||
// or:
|
||||
// f: v ...
|
||||
// f: vn ...
|
||||
// f: vt ...
|
||||
if (mesh->face_count > 0) {
|
||||
memcpy(mesh->data + offset, pos, sizeof(uint32) * face_size * mesh->face_count);
|
||||
mesh->faces = (uint32 *) (mesh->data + offset);
|
||||
|
||||
pos += sizeof(uint32) * face_size * mesh->face_count;
|
||||
offset += sizeof(uint32) * face_size * mesh->face_count;
|
||||
}
|
||||
|
||||
if (mesh->face_normal_count > 0) {
|
||||
memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_normal_count);
|
||||
mesh->face_normals = (uint32 *) (mesh->data + offset);
|
||||
|
||||
pos += sizeof(uint32) * 3 * mesh->face_normal_count;
|
||||
offset += sizeof(uint32) * 3 * mesh->face_normal_count;
|
||||
}
|
||||
|
||||
if (mesh->face_tex_coord_count > 0) {
|
||||
memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_tex_coord_count);
|
||||
mesh->face_textures = (uint32 *) (mesh->data + offset);
|
||||
|
||||
pos += sizeof(uint32) * 3 * mesh->face_tex_coord_count;
|
||||
offset += sizeof(uint32) * 3 * mesh->face_tex_coord_count;
|
||||
}
|
||||
|
||||
if (mesh->face_color_count > 0) {
|
||||
memcpy(mesh->data + offset, pos, sizeof(uint32) * 3 * mesh->face_color_count);
|
||||
mesh->face_colors = (uint32 *) (mesh->data + offset);
|
||||
|
||||
pos += sizeof(uint32) * 3 * mesh->face_color_count;
|
||||
offset += sizeof(uint32) * 3 * mesh->face_color_count;
|
||||
}
|
||||
|
||||
SWAP_ENDIAN_LITTLE_SIMD(
|
||||
(int32 *) mesh->data,
|
||||
(int32 *) mesh->data,
|
||||
offset / 4, // everything is 4 bytes -> super easy to swap
|
||||
steps
|
||||
);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void mesh_to_file(
|
||||
RingMemory* ring,
|
||||
const char* path,
|
||||
const Mesh* mesh,
|
||||
int32 vertex_save_format = VERTEX_TYPE_POSITION,
|
||||
int32 face_save_format = FACE_TYPE_VERTICES,
|
||||
int32 size = 8
|
||||
)
|
||||
{
|
||||
FileBody file;
|
||||
|
||||
// Temporary file size for buffer
|
||||
// @todo check the actual size, we are currently more or less guessing
|
||||
file.size = sizeof(mesh)
|
||||
+ sizeof(Vertex3D) * mesh->vertex_count
|
||||
+ sizeof(f32) * 12 * mesh->vertex_count
|
||||
+ 4096;
|
||||
|
||||
file.content = ring_get_memory(ring, file.size, 64);
|
||||
byte* pos = file.content;
|
||||
|
||||
// version
|
||||
memcpy(pos, &mesh->version, sizeof(mesh->version));
|
||||
pos += sizeof(mesh->version);
|
||||
|
||||
// vertices
|
||||
memcpy(pos, &vertex_save_format, sizeof(vertex_save_format));
|
||||
pos += sizeof(vertex_save_format);
|
||||
|
||||
memcpy(pos, &mesh->vertex_count, sizeof(mesh->vertex_count));
|
||||
pos += sizeof(mesh->vertex_count);
|
||||
|
||||
// We are can save the mesh in a different format from the current format -> need to adjust some values
|
||||
uint32 normal_count = mesh->normal_count == 0 && (mesh->vertex_type & VERTEX_TYPE_NORMAL)
|
||||
? mesh->vertex_count
|
||||
: mesh->normal_count;
|
||||
|
||||
memcpy(pos, &normal_count, sizeof(mesh->normal_count));
|
||||
pos += sizeof(mesh->normal_count);
|
||||
|
||||
uint32 tex_coord_count = mesh->tex_coord_count == 0 && (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD)
|
||||
? mesh->vertex_count
|
||||
: mesh->tex_coord_count;
|
||||
|
||||
memcpy(pos, &tex_coord_count, sizeof(mesh->tex_coord_count));
|
||||
pos += sizeof(mesh->tex_coord_count);
|
||||
|
||||
uint32 color_count = mesh->color_count == 0 && (mesh->vertex_type & VERTEX_TYPE_COLOR)
|
||||
? mesh->vertex_count
|
||||
: mesh->color_count;
|
||||
|
||||
memcpy(pos, &color_count, sizeof(mesh->color_count));
|
||||
pos += sizeof(mesh->color_count);
|
||||
|
||||
// verticies
|
||||
if (mesh->vertex_count > 0) {
|
||||
int32 vertex_size = 0;
|
||||
if (mesh->vertex_type & VERTEX_TYPE_POSITION) {
|
||||
vertex_size += 3;
|
||||
}
|
||||
|
||||
if (mesh->vertex_type & VERTEX_TYPE_NORMAL) {
|
||||
vertex_size += 3;
|
||||
}
|
||||
|
||||
if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) {
|
||||
vertex_size += 2;
|
||||
}
|
||||
|
||||
if (mesh->vertex_type & VERTEX_TYPE_COLOR) {
|
||||
vertex_size += 4;
|
||||
}
|
||||
|
||||
int32 out_vertex_size = 0;
|
||||
if (vertex_save_format & VERTEX_TYPE_POSITION) {
|
||||
out_vertex_size += 3;
|
||||
}
|
||||
|
||||
if (vertex_save_format & VERTEX_TYPE_NORMAL) {
|
||||
out_vertex_size += 3;
|
||||
}
|
||||
|
||||
if (vertex_save_format & VERTEX_TYPE_TEXTURE_COORD) {
|
||||
out_vertex_size += 2;
|
||||
}
|
||||
|
||||
if (vertex_save_format & VERTEX_TYPE_COLOR) {
|
||||
out_vertex_size += 4;
|
||||
}
|
||||
|
||||
if ((mesh->vertex_type == VERTEX_TYPE_ALL && vertex_save_format == VERTEX_TYPE_ALL)
|
||||
|| (mesh->vertex_type == VERTEX_TYPE_POSITION && vertex_save_format == VERTEX_TYPE_POSITION)
|
||||
) {
|
||||
// data is the same as in the array
|
||||
memcpy(pos, mesh->vertices, vertex_size * sizeof(f32) * mesh->vertex_count);
|
||||
pos += vertex_size * sizeof(f32) * mesh->vertex_count;
|
||||
} else {
|
||||
f32* temp = mesh->vertices;
|
||||
f32* end = mesh->vertices + mesh->vertex_count * vertex_size;
|
||||
|
||||
int32 offset;
|
||||
|
||||
byte* vertice_start = pos;
|
||||
|
||||
// @bug index gets increased every iteration BUT different groups and objects in the source may have different data
|
||||
// This comes again down to how to handle hierarchal data with multiple groups and objects
|
||||
int32 index = 0;
|
||||
|
||||
// iterate over all vertices to create new output format
|
||||
while (temp < end) {
|
||||
// @question why do I even need offset? couldn't I just directly manipulate temp?
|
||||
offset = 0;
|
||||
|
||||
// First we save everything in one large array if that is the setting
|
||||
if (vertex_save_format & VERTEX_TYPE_POSITION) {
|
||||
if (mesh->vertex_type & VERTEX_TYPE_POSITION) {
|
||||
memcpy(pos, temp, sizeof(f32) * 3);
|
||||
pos += sizeof(f32) * 3;
|
||||
|
||||
offset += 3;
|
||||
} else {
|
||||
memset(pos, 0, sizeof(f32) * 3);
|
||||
pos += sizeof(f32) * 3;
|
||||
}
|
||||
}
|
||||
|
||||
// We want separate arrays for some data
|
||||
if ((mesh->vertex_type & VERTEX_TYPE_NORMAL) && !(vertex_save_format & VERTEX_TYPE_NORMAL)) {
|
||||
// go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data
|
||||
memcpy(vertice_start
|
||||
+ sizeof(f32) * out_vertex_size * mesh->vertex_count
|
||||
+ index * sizeof(f32) * 3, temp + offset, sizeof(f32) * 3);
|
||||
|
||||
offset += 3;
|
||||
} else if (vertex_save_format & VERTEX_TYPE_NORMAL) {
|
||||
if (mesh->vertex_type & VERTEX_TYPE_NORMAL) {
|
||||
memcpy(pos, temp + offset, sizeof(f32) * 3);
|
||||
pos += sizeof(f32) * 3;
|
||||
|
||||
offset += 3;
|
||||
} else {
|
||||
memset(pos, 0, sizeof(f32) * 3);
|
||||
pos += sizeof(f32) * 3;
|
||||
}
|
||||
}
|
||||
|
||||
// We want separate arrays for some data
|
||||
if ((mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) && !(vertex_save_format & VERTEX_TYPE_TEXTURE_COORD)) {
|
||||
// go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data
|
||||
memcpy(vertice_start
|
||||
+ sizeof(f32) * out_vertex_size * mesh->vertex_count
|
||||
+ sizeof(f32) * normal_count * 3
|
||||
+ index * sizeof(f32) * 3, temp + offset, sizeof(f32) * 3);
|
||||
|
||||
offset += 2;
|
||||
} else if (vertex_save_format & VERTEX_TYPE_TEXTURE_COORD) {
|
||||
if (mesh->vertex_type & VERTEX_TYPE_TEXTURE_COORD) {
|
||||
memcpy(pos, temp + offset, sizeof(f32) * 2);
|
||||
pos += sizeof(f32) * 2;
|
||||
|
||||
offset += 2;
|
||||
} else {
|
||||
memset(pos, 0, sizeof(f32) * 2);
|
||||
pos += sizeof(f32) * 2;
|
||||
}
|
||||
}
|
||||
|
||||
// We want separate arrays for some data
|
||||
if ((mesh->vertex_type & VERTEX_TYPE_COLOR) && !(vertex_save_format & VERTEX_TYPE_COLOR)) {
|
||||
// go to end of vertices * shift by previous array sizes + shift by current vertex -> creates one continous array with this data
|
||||
memcpy(vertice_start
|
||||
+ sizeof(f32) * out_vertex_size * mesh->vertex_count
|
||||
+ sizeof(f32) * normal_count * 3
|
||||
+ sizeof(f32) * tex_coord_count * 2
|
||||
+ index * sizeof(f32) * 4, temp + offset, sizeof(f32) * 4);
|
||||
|
||||
offset += 4;
|
||||
} else if (vertex_save_format & VERTEX_TYPE_COLOR) {
|
||||
if (mesh->vertex_type & VERTEX_TYPE_COLOR) {
|
||||
memcpy(pos, temp + offset, sizeof(f32) * 4);
|
||||
pos += sizeof(f32) * 4;
|
||||
|
||||
offset += 4;
|
||||
} else {
|
||||
memset(pos, 0, sizeof(f32) * 4);
|
||||
pos += sizeof(f32) * 4;
|
||||
}
|
||||
}
|
||||
|
||||
temp += offset;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have clean array data already -> output this array data directly
|
||||
if (mesh->normals && mesh->normal_count > 0) {
|
||||
memcpy(pos, mesh->normals, mesh->normal_count * sizeof(f32) * 3);
|
||||
pos += mesh->normal_count * sizeof(f32) * 3;
|
||||
}
|
||||
|
||||
if (mesh->tex_coords && mesh->tex_coord_count > 0) {
|
||||
memcpy(pos, mesh->tex_coords, mesh->tex_coord_count * sizeof(f32) * 2);
|
||||
pos += mesh->tex_coord_count * sizeof(f32) * 2;
|
||||
}
|
||||
|
||||
if (mesh->colors && mesh->color_count > 0) {
|
||||
memcpy(pos, mesh->colors, mesh->color_count * sizeof(f32) * 4);
|
||||
pos += mesh->color_count * sizeof(f32) * 4;
|
||||
}
|
||||
}
|
||||
|
||||
// faces/indices
|
||||
memcpy(pos, &face_save_format, sizeof(face_save_format));
|
||||
pos += sizeof(face_save_format);
|
||||
|
||||
memcpy(pos, &mesh->face_count, sizeof(mesh->face_count));
|
||||
pos += sizeof(mesh->face_count);
|
||||
|
||||
// We are can save the mesh in a different format from the current format -> need to adjust some values
|
||||
uint32 face_normal_count = mesh->face_normal_count == 0 && (mesh->face_type & FACE_TYPE_NORMALS)
|
||||
? mesh->face_count
|
||||
: mesh->face_normal_count;
|
||||
|
||||
memcpy(pos, &face_normal_count, sizeof(mesh->face_normal_count));
|
||||
pos += sizeof(mesh->face_normal_count);
|
||||
|
||||
uint32 face_tex_coord_count = mesh->face_tex_coord_count == 0 && (mesh->face_type & FACE_TYPE_TEXTURES)
|
||||
? mesh->face_count
|
||||
: mesh->face_tex_coord_count;
|
||||
|
||||
memcpy(pos, &face_tex_coord_count, sizeof(mesh->face_tex_coord_count));
|
||||
pos += sizeof(mesh->face_tex_coord_count);
|
||||
|
||||
uint32 face_color_count = mesh->face_color_count == 0 && (mesh->face_type & FACE_TYPE_COLORS)
|
||||
? mesh->face_count
|
||||
: mesh->face_color_count;
|
||||
|
||||
memcpy(pos, &face_color_count, sizeof(mesh->face_color_count));
|
||||
pos += sizeof(mesh->face_color_count);
|
||||
|
||||
if (mesh->face_count > 0) {
|
||||
// WARNING: Carefull, we again assume only 3 elements per face
|
||||
|
||||
int32 face_size = 0;
|
||||
if (mesh->face_type & FACE_TYPE_VERTICES) {
|
||||
face_size += 3;
|
||||
}
|
||||
|
||||
if (mesh->face_type & FACE_TYPE_NORMALS) {
|
||||
face_size += 3;
|
||||
}
|
||||
|
||||
if (mesh->face_type & FACE_TYPE_TEXTURES) {
|
||||
face_size += 3;
|
||||
}
|
||||
|
||||
if (mesh->face_type & FACE_TYPE_COLORS) {
|
||||
face_size += 3;
|
||||
}
|
||||
|
||||
int32 out_face_size = 0;
|
||||
if (face_save_format & FACE_TYPE_VERTICES) {
|
||||
out_face_size += 3;
|
||||
}
|
||||
|
||||
if (face_save_format & FACE_TYPE_NORMALS) {
|
||||
out_face_size += 3;
|
||||
}
|
||||
|
||||
if (face_save_format & FACE_TYPE_TEXTURES) {
|
||||
out_face_size += 3;
|
||||
}
|
||||
|
||||
if (face_save_format & FACE_TYPE_COLORS) {
|
||||
out_face_size += 3;
|
||||
}
|
||||
|
||||
if ((mesh->face_type == FACE_TYPE_ALL && face_save_format == FACE_TYPE_ALL)
|
||||
|| (mesh->face_type == FACE_TYPE_VERTICES && face_save_format == FACE_TYPE_VERTICES)
|
||||
) {
|
||||
// data is the same as in the array
|
||||
memcpy(pos, mesh->faces, face_size * sizeof(uint32) * mesh->face_count);
|
||||
pos += face_size * sizeof(uint32) * mesh->face_count;
|
||||
} else {
|
||||
uint32* temp = mesh->faces;
|
||||
uint32* end = mesh->faces + mesh->face_count * face_size;
|
||||
|
||||
int32 offset;
|
||||
|
||||
byte* face_start = pos;
|
||||
|
||||
// @bug index gets increased every iteration BUT different groups and objects in the source may have different data
|
||||
// This comes again down to how to handle hierarchal data with multiple groups and objects
|
||||
int32 index = 0;
|
||||
|
||||
// iterate over all faces to create new output format
|
||||
// one iteration represents 1 block (a block could be v/vt/vn or, v, or v//vn, ...)
|
||||
while (temp < end) {
|
||||
// @question why do I even need offset? couldn't I just directly manipulate temp?
|
||||
offset = 0;
|
||||
|
||||
// First we save everything in one large array if that is the setting
|
||||
if (face_save_format & FACE_TYPE_VERTICES) {
|
||||
if (mesh->face_type & FACE_TYPE_VERTICES) {
|
||||
memcpy(pos, temp, sizeof(uint32));
|
||||
pos += sizeof(uint32);
|
||||
|
||||
offset += 1;
|
||||
} else {
|
||||
memset(pos, 0, sizeof(f32));
|
||||
pos += sizeof(f32);
|
||||
}
|
||||
}
|
||||
|
||||
// We want separate arrays for some data
|
||||
if (mesh->face_type & FACE_TYPE_NORMALS && !(face_save_format & FACE_TYPE_NORMALS)) {
|
||||
// go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data
|
||||
memcpy(face_start
|
||||
+ sizeof(uint32) * out_face_size * mesh->face_count
|
||||
+ index * sizeof(uint32), temp + offset, sizeof(uint32));
|
||||
|
||||
offset += 1;
|
||||
} else if (face_save_format & FACE_TYPE_NORMALS) {
|
||||
if (mesh->face_type & FACE_TYPE_NORMALS) {
|
||||
memcpy(pos, temp + offset, sizeof(uint32));
|
||||
pos += sizeof(uint32);
|
||||
|
||||
offset += 1;
|
||||
} else {
|
||||
memset(pos, 0, sizeof(uint32));
|
||||
pos += sizeof(uint32);
|
||||
}
|
||||
}
|
||||
|
||||
// We want separate arrays for some data
|
||||
if (mesh->face_type & FACE_TYPE_TEXTURES && !(face_save_format & FACE_TYPE_TEXTURES)) {
|
||||
// go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data
|
||||
memcpy(face_start
|
||||
+ sizeof(uint32) * out_face_size * mesh->face_count
|
||||
+ sizeof(uint32) * 3 * face_normal_count
|
||||
+ index * sizeof(uint32), temp + offset, sizeof(uint32));
|
||||
|
||||
offset += 1;
|
||||
} else if (face_save_format & FACE_TYPE_TEXTURES) {
|
||||
if (mesh->face_type & FACE_TYPE_TEXTURES) {
|
||||
memcpy(pos, temp + offset, sizeof(uint32));
|
||||
pos += sizeof(uint32);
|
||||
|
||||
offset += 1;
|
||||
} else {
|
||||
memset(pos, 0, sizeof(uint32));
|
||||
pos += sizeof(uint32);
|
||||
}
|
||||
}
|
||||
|
||||
// We want separate arrays for some data
|
||||
if (mesh->face_type & VERTEX_TYPE_COLOR && !(face_save_format & VERTEX_TYPE_COLOR)) {
|
||||
// go to end of faces * shift by previous array sizes + shift by current face -> creates one continous array with this data
|
||||
memcpy(face_start
|
||||
+ sizeof(uint32) * out_face_size * mesh->face_count
|
||||
+ sizeof(uint32) * 3 * face_normal_count
|
||||
+ sizeof(uint32) * 3 * face_tex_coord_count
|
||||
+ index * sizeof(uint32), temp + offset, sizeof(uint32));
|
||||
|
||||
offset += 1;
|
||||
} else if (face_save_format & VERTEX_TYPE_COLOR) {
|
||||
if (mesh->face_type & VERTEX_TYPE_COLOR) {
|
||||
memcpy(pos, temp + offset, sizeof(uint32));
|
||||
pos += sizeof(uint32);
|
||||
|
||||
offset += 1;
|
||||
} else {
|
||||
memset(pos, 0, sizeof(uint32));
|
||||
pos += sizeof(uint32);
|
||||
}
|
||||
}
|
||||
|
||||
temp += offset;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have clean array data already -> output this array data directly
|
||||
if (mesh->face_normals && mesh->face_normal_count > 0) {
|
||||
memcpy(pos, mesh->face_normals, mesh->face_normal_count * sizeof(uint32) * 3);
|
||||
pos += mesh->face_normal_count * sizeof(uint32) * 3;
|
||||
}
|
||||
|
||||
if (mesh->face_textures && mesh->face_tex_coord_count > 0) {
|
||||
memcpy(pos, mesh->face_textures, mesh->face_tex_coord_count * sizeof(uint32) * 3);
|
||||
pos += mesh->face_tex_coord_count * sizeof(uint32) * 3;
|
||||
}
|
||||
|
||||
if (mesh->face_colors && mesh->face_color_count > 0) {
|
||||
memcpy(pos, mesh->face_colors, mesh->face_color_count * sizeof(uint32) * 3);
|
||||
pos += mesh->face_color_count * sizeof(uint32) * 3;
|
||||
}
|
||||
}
|
||||
|
||||
file.size = pos - file.content;
|
||||
|
||||
SWAP_ENDIAN_LITTLE_SIMD(
|
||||
(int32 *) file.content,
|
||||
(int32 *) file.content,
|
||||
file.size / 4, // everything in here is 4 bytes -> super easy to swap
|
||||
steps
|
||||
);
|
||||
|
||||
/*
|
||||
FileBody file2;
|
||||
file2.content = ring_get_memory(ring, file.size, 64);
|
||||
file2.size = encode_lzp(file.content, file.size, file2.content);
|
||||
|
||||
file_write(path, &file2);
|
||||
*/
|
||||
|
||||
file_write(path, &file);
|
||||
}
|
||||
|
||||
#endif
|
||||
961
object/Object.h
961
object/Object.h
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
595
platform/win32/SystemInfo.h
Normal 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
|
||||
|
|
@ -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
|
||||
102
stdlib/HashMap.h
102
stdlib/HashMap.h
|
|
@ -14,6 +14,7 @@
|
|||
#include "../memory/BufferMemory.h"
|
||||
#include "../memory/ChunkMemory.h"
|
||||
#include "Types.h"
|
||||
#include "../utils/StringUtils.h"
|
||||
|
||||
#define MAX_KEY_LENGTH 32
|
||||
|
||||
|
|
@ -77,7 +78,8 @@ void hashmap_create(HashMap* hm, int32 count, int32 element_size, RingMemory* ri
|
|||
byte* data = ring_get_memory(
|
||||
ring,
|
||||
count * (sizeof(void *) + element_size)
|
||||
+ CEIL_DIV(count, 64) * sizeof(hm->buf.free)
|
||||
+ CEIL_DIV(count, 64) * sizeof(hm->buf.free),
|
||||
0, true
|
||||
);
|
||||
|
||||
hm->table = (void **) data;
|
||||
|
|
@ -130,8 +132,18 @@ void hashmap_insert(HashMap* hm, const char* key, int32 value) {
|
|||
entry->key[MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
entry->next = (HashEntryInt32 *) hm->table[index];
|
||||
hm->table[index] = entry;
|
||||
entry->next = NULL;
|
||||
|
||||
if (hm->table[index]) {
|
||||
HashEntryInt32* tmp = (HashEntryInt32 *) hm->table[index];
|
||||
while(tmp->next) {
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp->next = entry;
|
||||
} else {
|
||||
hm->table[index] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void hashmap_insert(HashMap* hm, const char* key, int64 value) {
|
||||
|
|
@ -145,8 +157,18 @@ void hashmap_insert(HashMap* hm, const char* key, int64 value) {
|
|||
entry->key[MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
entry->next = (HashEntryInt64 *) hm->table[index];
|
||||
hm->table[index] = entry;
|
||||
entry->next = NULL;
|
||||
|
||||
if (hm->table[index]) {
|
||||
HashEntryInt64* tmp = (HashEntryInt64 *) hm->table[index];
|
||||
while(tmp->next) {
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp->next = entry;
|
||||
} else {
|
||||
hm->table[index] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void hashmap_insert(HashMap* hm, const char* key, uintptr_t value) {
|
||||
|
|
@ -160,8 +182,18 @@ void hashmap_insert(HashMap* hm, const char* key, uintptr_t value) {
|
|||
entry->key[MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
entry->next = (HashEntryUIntPtr *) hm->table[index];
|
||||
hm->table[index] = entry;
|
||||
entry->next = NULL;
|
||||
|
||||
if (hm->table[index]) {
|
||||
HashEntryUIntPtr* tmp = (HashEntryUIntPtr *) hm->table[index];
|
||||
while(tmp->next) {
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp->next = entry;
|
||||
} else {
|
||||
hm->table[index] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void hashmap_insert(HashMap* hm, const char* key, void* value) {
|
||||
|
|
@ -175,8 +207,18 @@ void hashmap_insert(HashMap* hm, const char* key, void* value) {
|
|||
entry->key[MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
entry->next = (HashEntryVoidP *) hm->table[index];
|
||||
hm->table[index] = entry;
|
||||
entry->next = NULL;
|
||||
|
||||
if (hm->table[index]) {
|
||||
HashEntryVoidP* tmp = (HashEntryVoidP *) hm->table[index];
|
||||
while(tmp->next) {
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp->next = entry;
|
||||
} else {
|
||||
hm->table[index] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void hashmap_insert(HashMap* hm, const char* key, f32 value) {
|
||||
|
|
@ -190,8 +232,18 @@ void hashmap_insert(HashMap* hm, const char* key, f32 value) {
|
|||
entry->key[MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->value = value;
|
||||
entry->next = (HashEntryFloat *) hm->table[index];
|
||||
hm->table[index] = entry;
|
||||
entry->next = NULL;
|
||||
|
||||
if (hm->table[index]) {
|
||||
HashEntryFloat* tmp = (HashEntryFloat *) hm->table[index];
|
||||
while(tmp->next) {
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp->next = entry;
|
||||
} else {
|
||||
hm->table[index] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void hashmap_insert(HashMap* hm, const char* key, const char* value) {
|
||||
|
|
@ -207,8 +259,18 @@ void hashmap_insert(HashMap* hm, const char* key, const char* value) {
|
|||
strncpy(entry->value, value, MAX_KEY_LENGTH);
|
||||
entry->value[MAX_KEY_LENGTH - 1] = '\0';
|
||||
|
||||
entry->next = (HashEntryStr *) hm->table[index];
|
||||
hm->table[index] = entry;
|
||||
entry->next = NULL;
|
||||
|
||||
if (hm->table[index]) {
|
||||
HashEntryStr* tmp = (HashEntryStr *) hm->table[index];
|
||||
while(tmp->next) {
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp->next = entry;
|
||||
} else {
|
||||
hm->table[index] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void hashmap_insert(HashMap* hm, const char* key, byte* value) {
|
||||
|
|
@ -225,8 +287,18 @@ void hashmap_insert(HashMap* hm, const char* key, byte* value) {
|
|||
|
||||
memcpy(entry->value, value, hm->buf.chunk_size - sizeof(HashEntry));
|
||||
|
||||
entry->next = (HashEntry *) hm->table[index];
|
||||
hm->table[index] = entry;
|
||||
entry->next = NULL;
|
||||
|
||||
if (hm->table[index]) {
|
||||
HashEntry* tmp = (HashEntry *) hm->table[index];
|
||||
while(tmp->next) {
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp->next = entry;
|
||||
} else {
|
||||
hm->table[index] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
HashEntry* hashmap_get_entry(HashMap* hm, const char* key) {
|
||||
|
|
|
|||
112
ui/UIAttribute.h
112
ui/UIAttribute.h
|
|
@ -24,6 +24,11 @@ enum UIAttributeType {
|
|||
UI_ATTRIBUTE_TYPE_TYPE,
|
||||
UI_ATTRIBUTE_TYPE_STYLE,
|
||||
|
||||
UI_ATTRIBUTE_TYPE_DIMENSION_X,
|
||||
UI_ATTRIBUTE_TYPE_DIMENSION_Y,
|
||||
UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH,
|
||||
UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT,
|
||||
|
||||
UI_ATTRIBUTE_TYPE_CONTENT,
|
||||
UI_ATTRIBUTE_TYPE_CONTENT_ALIGN_H,
|
||||
UI_ATTRIBUTE_TYPE_CONTENT_ALIGN_V,
|
||||
|
|
@ -44,9 +49,6 @@ enum UIAttributeType {
|
|||
UI_ATTRIBUTE_TYPE_POSITION_Y,
|
||||
UI_ATTRIBUTE_TYPE_PARENT,
|
||||
|
||||
UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH,
|
||||
UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT,
|
||||
|
||||
UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR_INDEX,
|
||||
UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR,
|
||||
UI_ATTRIBUTE_TYPE_BACKGROUND_IMG,
|
||||
|
|
@ -103,13 +105,115 @@ UIAttribute* ui_attribute_from_group(UIAttributeGroup* group, UIAttributeType ty
|
|||
return NULL;
|
||||
}
|
||||
|
||||
constexpr const char* ui_attribute_type_to_string(int32 e)
|
||||
constexpr const char* ui_attribute_type_to_string_const(UIAttributeType e)
|
||||
{
|
||||
switch (e) {
|
||||
case UI_ATTRIBUTE_TYPE_TYPE:
|
||||
return "type";
|
||||
case UI_ATTRIBUTE_TYPE_STYLE:
|
||||
return "style";
|
||||
case UI_ATTRIBUTE_TYPE_DIMENSION_X:
|
||||
return "x";
|
||||
case UI_ATTRIBUTE_TYPE_DIMENSION_Y:
|
||||
return "y";
|
||||
case UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH:
|
||||
return "width";
|
||||
case UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT:
|
||||
return "height";
|
||||
case UI_ATTRIBUTE_TYPE_FONT_NAME:
|
||||
return "font_name";
|
||||
case UI_ATTRIBUTE_TYPE_FONT_COLOR:
|
||||
return "font_color";
|
||||
case UI_ATTRIBUTE_TYPE_FONT_SIZE:
|
||||
return "font_size";
|
||||
case UI_ATTRIBUTE_TYPE_FONT_WEIGHT:
|
||||
return "font_weight";
|
||||
case UI_ATTRIBUTE_TYPE_FONT_LINE_HEIGHT:
|
||||
return "font_line_height";
|
||||
case UI_ATTRIBUTE_TYPE_ALIGN_H:
|
||||
return "align_h";
|
||||
case UI_ATTRIBUTE_TYPE_ALIGN_V:
|
||||
return "align_v";
|
||||
case UI_ATTRIBUTE_TYPE_ZINDEX:
|
||||
return "zindex";
|
||||
case UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR:
|
||||
return "background_color";
|
||||
case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG:
|
||||
return "background_img";
|
||||
case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_OPACITY:
|
||||
return "background_img_opacity";
|
||||
case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_V:
|
||||
return "background_img_position_v";
|
||||
case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_H:
|
||||
return "background_img_position_h";
|
||||
case UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_STYLE:
|
||||
return "background_img_style";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_COLOR:
|
||||
return "border_color";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_WIDTH:
|
||||
return "border_width";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_TOP_COLOR:
|
||||
return "border_top_color";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_TOP_WIDTH:
|
||||
return "border_top_width";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_RIGHT_COLOR:
|
||||
return "border_right_color";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_RIGHT_WIDTH:
|
||||
return "border_right_width";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_COLOR:
|
||||
return "border_bottom_color";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_WIDTH:
|
||||
return "border_bottom_width";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_LEFT_COLOR:
|
||||
return "border_left_color";
|
||||
case UI_ATTRIBUTE_TYPE_BORDER_LEFT_WIDTH:
|
||||
return "border_left_width";
|
||||
case UI_ATTRIBUTE_TYPE_PADDING:
|
||||
return "padding";
|
||||
case UI_ATTRIBUTE_TYPE_PADDING_TOP:
|
||||
return "padding_top";
|
||||
case UI_ATTRIBUTE_TYPE_PADDING_RIGHT:
|
||||
return "padding_right";
|
||||
case UI_ATTRIBUTE_TYPE_PADDING_BOTTOM:
|
||||
return "padding_bottom";
|
||||
case UI_ATTRIBUTE_TYPE_PADDING_LEFT:
|
||||
return "padding_left";
|
||||
case UI_ATTRIBUTE_TYPE_SHADOW_INNER_COLOR:
|
||||
return "shadow_inner_color";
|
||||
case UI_ATTRIBUTE_TYPE_SHADOW_INNER_ANGLE:
|
||||
return "shadow_inner_angle";
|
||||
case UI_ATTRIBUTE_TYPE_SHADOW_INNER_DISTANCE:
|
||||
return "shadow_inner_distance";
|
||||
case UI_ATTRIBUTE_TYPE_SHADOW_OUTER_COLOR:
|
||||
return "shadow_outer_color";
|
||||
case UI_ATTRIBUTE_TYPE_SHADOW_OUTER_ANGLE:
|
||||
return "shadow_outer_angle";
|
||||
case UI_ATTRIBUTE_TYPE_SHADOW_OUTER_DISTANCE:
|
||||
return "shadow_outer_distance";
|
||||
case UI_ATTRIBUTE_TYPE_TRANSITION_ANIMATION:
|
||||
return "transition_animation";
|
||||
case UI_ATTRIBUTE_TYPE_TRANSITION_DURATION:
|
||||
return "transition_duration";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ui_attribute_type_to_string(UIAttributeType e)
|
||||
{
|
||||
switch (e) {
|
||||
case UI_ATTRIBUTE_TYPE_TYPE:
|
||||
return "type";
|
||||
case UI_ATTRIBUTE_TYPE_STYLE:
|
||||
return "style";
|
||||
case UI_ATTRIBUTE_TYPE_DIMENSION_X:
|
||||
return "x";
|
||||
case UI_ATTRIBUTE_TYPE_DIMENSION_Y:
|
||||
return "y";
|
||||
case UI_ATTRIBUTE_TYPE_DIMENSION_WIDTH:
|
||||
return "width";
|
||||
case UI_ATTRIBUTE_TYPE_DIMENSION_HEIGHT:
|
||||
return "height";
|
||||
case UI_ATTRIBUTE_TYPE_FONT_NAME:
|
||||
return "font_name";
|
||||
case UI_ATTRIBUTE_TYPE_FONT_COLOR:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
118
ui/UITheme.h
118
ui/UITheme.h
|
|
@ -96,14 +96,10 @@ int compare_by_attribute_id(const void* a, const void* b) {
|
|||
|
||||
// WARNING: theme needs to have memory already reserved and asigned to data
|
||||
void theme_from_file_txt(
|
||||
RingMemory* ring,
|
||||
const char* path,
|
||||
UIThemeStyle* theme
|
||||
UIThemeStyle* theme,
|
||||
byte* data
|
||||
) {
|
||||
FileBody file;
|
||||
file_read(path, &file, ring);
|
||||
|
||||
char* pos = (char *) file.content;
|
||||
char* pos = (char *) data;
|
||||
|
||||
// move past the version string
|
||||
pos += 8;
|
||||
|
|
@ -147,7 +143,9 @@ void theme_from_file_txt(
|
|||
|
||||
UIAttributeGroup* temp_group = NULL;
|
||||
|
||||
pos = (char *) file.content;
|
||||
pos = (char *) data;
|
||||
pos += 8; // move past version
|
||||
|
||||
while (*pos != '\0') {
|
||||
while (*pos == ' ' || *pos == '\t') {
|
||||
++pos;
|
||||
|
|
@ -182,7 +180,9 @@ void theme_from_file_txt(
|
|||
// All blocks need to start with #. In the past this wasn't the case and may not be in the future. This is why we keep this if here.
|
||||
if (*block_name == '#' || *block_name == '.') {
|
||||
// Named style
|
||||
if (temp_group != NULL) {
|
||||
block_open = true;
|
||||
|
||||
if (temp_group) {
|
||||
// Before we insert a new group we have to sort the attributes
|
||||
// since this makes searching them later on more efficient.
|
||||
qsort(temp_group->attributes, temp_group->attribute_size, sizeof(UIAttribute), compare_by_attribute_id);
|
||||
|
|
@ -193,7 +193,8 @@ void theme_from_file_txt(
|
|||
|
||||
temp_group = (UIAttributeGroup *) (theme->data + data_offset);
|
||||
temp_group->attribute_size = 0;
|
||||
data_offset += sizeof(temp_group->attribute_size);
|
||||
temp_group->attributes = (UIAttribute *) (theme->data + data_offset + sizeof(UIAttributeGroup));
|
||||
data_offset += sizeof(UIAttributeGroup);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
|
@ -209,7 +210,7 @@ void theme_from_file_txt(
|
|||
attribute_name[i] = '\0';
|
||||
|
||||
// Skip any white spaces or other delimeters
|
||||
while (*pos == ' ' || *pos == ':') {
|
||||
while (*pos == ' ' || *pos == '\t' || *pos == ':') {
|
||||
++pos;
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +218,7 @@ void theme_from_file_txt(
|
|||
|
||||
// Handle different attribute types
|
||||
UIAttribute attribute = {};
|
||||
if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_TYPE), attribute_name) == 0) {
|
||||
if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_TYPE), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_TYPE;
|
||||
|
||||
char str[32];
|
||||
|
|
@ -227,16 +228,16 @@ void theme_from_file_txt(
|
|||
}
|
||||
|
||||
*temp = '\0';
|
||||
for (int32 j = 0; j < UI_ELEMENT_TYPE_SIZE; ++j) {
|
||||
if (strcmp(str, ui_element_type_to_string((UIElementType) j)) == 0) {
|
||||
|
||||
for (int32 i = 0; i < UI_ELEMENT_TYPE_SIZE; ++i) {
|
||||
if (strcmp(str, ui_attribute_type_to_string(i)) == 0) {
|
||||
attribute.value_int = i;
|
||||
attribute.value_int = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_STYLE), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_STYLE), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_STYLE;
|
||||
|
||||
char* temp = attribute.value_str;
|
||||
|
|
@ -246,7 +247,7 @@ void theme_from_file_txt(
|
|||
|
||||
*temp = '\0';
|
||||
++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_FONT_COLOR), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_FONT_COLOR), attribute_name) == 0) {
|
||||
++pos; // Skip '#'
|
||||
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_FONT_COLOR;
|
||||
|
|
@ -257,25 +258,25 @@ void theme_from_file_txt(
|
|||
attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_FONT_SIZE), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_FONT_SIZE), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_FONT_SIZE;
|
||||
attribute.value_float = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_FONT_WEIGHT), attribute_name) == 0) {
|
||||
attribute.value_float = strtof(pos, &pos); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_FONT_WEIGHT), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_FONT_WEIGHT;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_FONT_LINE_HEIGHT), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_FONT_LINE_HEIGHT), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_FONT_LINE_HEIGHT;
|
||||
attribute.value_float = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_ALIGN_H), attribute_name) == 0) {
|
||||
attribute.value_float = strtof(pos, &pos); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_ALIGN_H), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_ALIGN_H;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_ALIGN_V), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_ALIGN_V), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_ALIGN_V;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_ZINDEX), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_ZINDEX), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_ZINDEX;
|
||||
attribute.value_float = SWAP_ENDIAN_LITTLE(strtof(pos, &pos)); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR), attribute_name) == 0) {
|
||||
++pos; // Skip '#'
|
||||
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_COLOR;
|
||||
|
|
@ -286,7 +287,7 @@ void theme_from_file_txt(
|
|||
attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG;
|
||||
|
||||
i = 0;
|
||||
|
|
@ -295,19 +296,19 @@ void theme_from_file_txt(
|
|||
}
|
||||
|
||||
attribute.value_str[i] = '\0';
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_OPACITY), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_OPACITY), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_OPACITY;
|
||||
attribute.value_float = SWAP_ENDIAN_LITTLE(strtof(pos, &pos)); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_V), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_V), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_V;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_H), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_H), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_POSITION_H;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_STYLE), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_STYLE), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BACKGROUND_IMG_STYLE;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_COLOR), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_COLOR), attribute_name) == 0) {
|
||||
++pos; // Skip '#'
|
||||
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_COLOR;
|
||||
|
|
@ -318,10 +319,10 @@ void theme_from_file_txt(
|
|||
attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_WIDTH), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_WIDTH), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_WIDTH;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_TOP_COLOR), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_TOP_COLOR), attribute_name) == 0) {
|
||||
++pos; // Skip '#'
|
||||
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_TOP_COLOR;
|
||||
|
|
@ -332,10 +333,10 @@ void theme_from_file_txt(
|
|||
attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_TOP_WIDTH), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_TOP_WIDTH), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_TOP_WIDTH;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_RIGHT_COLOR), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_RIGHT_COLOR), attribute_name) == 0) {
|
||||
++pos; // Skip '#'
|
||||
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_RIGHT_COLOR;
|
||||
|
|
@ -346,10 +347,10 @@ void theme_from_file_txt(
|
|||
attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_RIGHT_WIDTH), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_RIGHT_WIDTH), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_RIGHT_WIDTH;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_COLOR), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_COLOR), attribute_name) == 0) {
|
||||
++pos; // Skip '#'
|
||||
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_COLOR;
|
||||
|
|
@ -360,10 +361,10 @@ void theme_from_file_txt(
|
|||
attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_WIDTH), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_WIDTH), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_BOTTOM_WIDTH;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_LEFT_COLOR), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_LEFT_COLOR), attribute_name) == 0) {
|
||||
++pos; // Skip '#'
|
||||
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_LEFT_COLOR;
|
||||
|
|
@ -374,25 +375,25 @@ void theme_from_file_txt(
|
|||
attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_BORDER_LEFT_WIDTH), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_BORDER_LEFT_WIDTH), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_BORDER_LEFT_WIDTH;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING_TOP), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING_TOP), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING_TOP;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING_RIGHT), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING_RIGHT), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING_RIGHT;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING_BOTTOM), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING_BOTTOM), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING_BOTTOM;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_PADDING_LEFT), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_PADDING_LEFT), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_PADDING_LEFT;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_INNER_COLOR), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_INNER_COLOR), attribute_name) == 0) {
|
||||
++pos; // Skip '#'
|
||||
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_INNER_COLOR;
|
||||
|
|
@ -403,13 +404,13 @@ void theme_from_file_txt(
|
|||
attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_INNER_ANGLE), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_INNER_ANGLE), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_INNER_ANGLE;
|
||||
attribute.value_float = strtof(pos, &pos); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_INNER_DISTANCE), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_INNER_DISTANCE), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_INNER_DISTANCE;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_COLOR), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_COLOR), attribute_name) == 0) {
|
||||
++pos; // Skip '#'
|
||||
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_OUTER_COLOR;
|
||||
|
|
@ -420,24 +421,28 @@ void theme_from_file_txt(
|
|||
attribute.value_v4_f32.g = (f32) ((value >> 16) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.b = (f32) ((value >> 8) & 0xFF) / 255.0f;
|
||||
attribute.value_v4_f32.a = (f32) (value & 0xFF) / 255.0f;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_ANGLE), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_ANGLE), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_OUTER_ANGLE;
|
||||
attribute.value_float = strtof(pos, &pos); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_DISTANCE), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_SHADOW_OUTER_DISTANCE), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_SHADOW_OUTER_DISTANCE;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_TRANSITION_ANIMATION), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_TRANSITION_ANIMATION), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_TRANSITION_ANIMATION;
|
||||
attribute.value_int = strtoul(pos, &pos, 10); ++pos;
|
||||
} else if (strcmp(ui_attribute_type_to_string(UI_ATTRIBUTE_TYPE_TRANSITION_DURATION), attribute_name) == 0) {
|
||||
} else if (strcmp(ui_attribute_type_to_string_const(UI_ATTRIBUTE_TYPE_TRANSITION_DURATION), attribute_name) == 0) {
|
||||
attribute.attribute_id = UI_ATTRIBUTE_TYPE_TRANSITION_DURATION;
|
||||
attribute.value_float = strtof(pos, &pos); ++pos;
|
||||
} else {
|
||||
while (*pos != '\n' && *pos != '\0') {
|
||||
++pos;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Again, currently this if check is redundant but it wasn't in the past and we may need it again in the future.
|
||||
if (block_name[0] == '#') {
|
||||
if (block_name[0] == '#' || block_name[0] == '.') {
|
||||
// Named block
|
||||
memcpy(
|
||||
temp_group->attributes + temp_group->attribute_size,
|
||||
|
|
@ -480,7 +485,8 @@ void theme_from_file(
|
|||
|
||||
// Prepare hashmap (incl. reserve memory) by initializing it the same way we originally did
|
||||
// Of course we still need to populate the data using hashmap_load()
|
||||
hashmap_create(&theme->hash_map, SWAP_ENDIAN_LITTLE(*((uint64 *) pos)), sizeof(HashEntryInt64), theme->data);
|
||||
// The value is a int64 (because this is the value of the chunk buffer size but the hashmap only allows int32)
|
||||
hashmap_create(&theme->hash_map, (int32) SWAP_ENDIAN_LITTLE(*((uint64 *) pos)), sizeof(HashEntryInt64), theme->data);
|
||||
pos += hashmap_load(&theme->hash_map, pos);
|
||||
|
||||
// theme data
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue
Block a user