/*
GameEngine and Editor
by John Ryland
Copyright (c) 2023
*/
#include "SchemaFile.h"
#include <cstdio>
#include <cstdlib>
static
void CheckReadResult(size_t result, size_t expected)
{
if (result != expected)
{
printf("read result: %lu, expected: %lu\n", result, expected);
exit(0);
}
}
namespace GameRuntime {
Schema* LoadSchemaFromFile(const char* schemaFileName)
{
Schema* schema = nullptr;
// printf("opening file: %s\n", schemaFileName);
FILE* schemaFile = fopen(schemaFileName, "r");
if (schemaFile)
{
// printf("opened %s as fd: %p\n", schemaFileName, schemaFile);
SchemaFileFormatHeader fileHeader;
CheckReadResult(fread(&fileHeader, sizeof(fileHeader), 1, schemaFile), 1);
schema = (Schema*)malloc(sizeof(Schema));
schema->strings = (StringTable*)malloc(sizeof(uint64_t) + sizeof(char) * fileHeader.stringTableSize);
schema->enums = (NameValueTable*)malloc(sizeof(uint64_t) + sizeof(NameValue) * fileHeader.nameValueTableSize);
schema->variables = (VariableDescriptionTable*)malloc(sizeof(uint64_t) + sizeof(VariableDescription) * fileHeader.variableDescriptionTableSize);
// printf("seeking to: %lu\n", fileHeader.stringTableFileOffset);
fseek(schemaFile, fileHeader.stringTableFileOffset, SEEK_SET);
schema->strings->count = fileHeader.stringTableSize;
CheckReadResult(fread(schema->strings->text, fileHeader.stringTableSize * sizeof(char), 1, schemaFile), 1);
// printf("seeking to: %lu\n", fileHeader.nameValueTableFileOffset);
fseek(schemaFile, fileHeader.nameValueTableFileOffset, SEEK_SET);
schema->enums->count = fileHeader.nameValueTableSize;
CheckReadResult(fread(schema->enums->values, fileHeader.nameValueTableSize * sizeof(NameValue), 1, schemaFile), 1);
// printf("seeking to: %lu\n", fileHeader.variableDescriptionTableFileOffset);
fseek(schemaFile, fileHeader.variableDescriptionTableFileOffset, SEEK_SET);
schema->variables->count = fileHeader.variableDescriptionTableSize;
CheckReadResult(fread(schema->variables->variables, fileHeader.variableDescriptionTableSize * sizeof(VariableDescription), 1, schemaFile), 1);
fclose(schemaFile);
}
return schema;
}
void DestroySchema(Schema* schema)
{
if (schema)
{
free(schema->strings);
free(schema->enums);
free(schema->variables);
free(schema);
}
}
size_t CalculateEnumSize(const Schema& schema, const EnumDescription& enumDesc)
{
NameValue* enumValues = schema.enums->values + enumDesc.nameValueTableOffset;
uint64_t maxEnumValue = 0ULL;
for (int i = 0; i < enumDesc.numberOfEnumValues; ++i)
if (enumValues[i].value > maxEnumValue)
maxEnumValue = enumValues[i].value;
// If use indirection instead then could do this:
// maxEnumValue = enumDesc.numberOfEnumValues;
if (maxEnumValue <= UINT8_MAX)
return sizeof(uint8_t);
else if (maxEnumValue <= UINT16_MAX)
return sizeof(uint16_t);
else if (maxEnumValue <= UINT32_MAX)
return sizeof(uint32_t);
return sizeof(uint64_t);
}
size_t CalculateNumberSize(const Schema& schema, const NumberTypeEnum& numberDesc)
{
switch (numberDesc)
{
case E_UInt8:
case E_Int8:
return 1;
case E_UInt16:
case E_Int16:
return 2;
case E_Int32:
case E_UInt32:
case E_Float32:
case E_Angle:
case E_Ratio:
return 4;
case E_Int64:
case E_UInt64:
case E_Float64:
return 8;
}
return 16;
}
size_t CalculateAlignmentPadding(size_t currentStructSize, size_t alignToSize)
{
return ((alignToSize - currentStructSize) % alignToSize);
}
size_t CalculateFieldSize(const Schema& schema, size_t structOffset, const VariableDescription& fieldDesc)
{
size_t paddingSize = 0;
size_t fieldSize = 0;
switch (fieldDesc.variableType)
{
case VariableTypeEnum::E_Entity:
fieldSize = sizeof(uint64_t);
paddingSize = CalculateAlignmentPadding(structOffset, alignof(uint64_t));
break;
case VariableTypeEnum::E_Void:
fieldSize = 0;
break;
case VariableTypeEnum::E_Bool:
fieldSize = sizeof(bool);
paddingSize = CalculateAlignmentPadding(structOffset, alignof(bool));
break;
case VariableTypeEnum::E_Enum:
fieldSize = CalculateEnumSize(schema, fieldDesc.enumDescription);
paddingSize = CalculateAlignmentPadding(structOffset, fieldSize);
break;
case VariableTypeEnum::E_String:
fieldSize = fieldDesc.stringDescription.maximumCharacterCount;
break;
case VariableTypeEnum::E_Number:
fieldSize = CalculateNumberSize(schema, fieldDesc.numberDescription.numberType);
paddingSize = CalculateAlignmentPadding(structOffset, fieldSize);
break;
case VariableTypeEnum::E_EncodedNumber:
// fieldSize = 0; // Not supported
break;
case VariableTypeEnum::E_Color:
fieldSize = sizeof(uint32_t);
paddingSize = CalculateAlignmentPadding(structOffset, alignof(uint32_t));
break;
case VariableTypeEnum::E_Asset:
// fieldSize = 0; // Not supported yet
break;
case VariableTypeEnum::E_Struct:
fieldSize = CalculateComponentSize(schema, fieldDesc.structDescription);
break;
}
return paddingSize + fieldSize;
}
// TODO: alignment of fields
size_t CalculateComponentSize(const Schema& schema, const StructDescription& fields)
{
size_t structSize = 0;
size_t fieldSize = 0;
VariableDescription* fieldsDesc = schema.variables->variables + fields.variableDescriptionTableOffset;
for (int field = 0; field < fields.numberOfFields; ++field)
{
const VariableDescription& fieldDesc = fieldsDesc[field];
structSize += CalculateFieldSize(schema, structSize, fieldDesc);
/*
switch (fieldDesc.variableType)
{
case VariableTypeEnum::E_Entity:
structSize += CalculateAlignmentPadding(structSize, alignof(uint64_t));
structSize += sizeof(uint64_t);
break;
case VariableTypeEnum::E_Void:
structSize += 0;
break;
case VariableTypeEnum::E_Bool:
structSize += CalculateAlignmentPadding(structSize, alignof(bool));
structSize += sizeof(bool);
break;
case VariableTypeEnum::E_Enum:
fieldSize = CalculateEnumSize(schema, fieldDesc.enumDescription);
structSize += CalculateAlignmentPadding(structSize, fieldSize);
structSize += fieldSize;
break;
case VariableTypeEnum::E_String:
structSize += fieldDesc.stringDescription.maximumCharacterCount;
break;
case VariableTypeEnum::E_Number:
fieldSize = CalculateNumberSize(schema, fieldDesc.numberDescription.numberType);
structSize += CalculateAlignmentPadding(structSize, fieldSize);
structSize += fieldSize;
break;
case VariableTypeEnum::E_EncodedNumber:
// structSize += 0; // Not supported
break;
case VariableTypeEnum::E_Color:
structSize += CalculateAlignmentPadding(structSize, alignof(uint32_t));
structSize += sizeof(uint32_t);
break;
case VariableTypeEnum::E_Asset:
// structSize += 0; // Not supported yet
break;
case VariableTypeEnum::E_Struct:
structSize += CalculateComponentSize(schema, fieldDesc.structDescription);
break;
}
*/
}
// TODO: will there be any trailing padding needed between elements of these in an array?
return structSize;
}
} // GameRuntime namespace