Compressing Type Info Generation
This commit is contained in:
parent
d1353e52fa
commit
af11a85e94
|
@ -1,15 +1,9 @@
|
|||
//
|
||||
// Usage
|
||||
// File: foldhaus_meta.cpp
|
||||
// Author: Peter Slattery
|
||||
// Creation Date: 2020-01-19
|
||||
//
|
||||
// GSMetaTag(<tag name>) to give commands to the meta layer
|
||||
//
|
||||
// Tag Values
|
||||
//
|
||||
// breakpoint
|
||||
// will cause the meta layer to break in the debugger when it reaches
|
||||
// that point in processing the file
|
||||
// TODO: specify which stage you want it to break at
|
||||
|
||||
#ifndef FOLDHAUS_META_CPP
|
||||
|
||||
#include "gs_meta.cpp"
|
||||
#include "gs_meta_typeinfo_generator.h"
|
||||
|
@ -23,25 +17,64 @@ int main(int ArgCount, char* Args[])
|
|||
}
|
||||
|
||||
gs_meta_preprocessor Meta = PreprocessProgram(Args[1]);
|
||||
s64 Cycles_Preprocess = GetWallClock();
|
||||
|
||||
typeinfo_generator TypeGenerator = InitTypeInfoGenerator(Meta.TypeTable);
|
||||
|
||||
GenerateFilteredTypeInfo(MakeStringLiteral("node_struct"), Meta.TypeTable, &TypeGenerator);
|
||||
GenerateFilteredTypeInfo(MakeStringLiteral("gen_type_info"), Meta.TypeTable, &TypeGenerator);
|
||||
|
||||
FinishGeneratingTypes(&TypeGenerator);
|
||||
|
||||
gsm_code_generator NodeTypeGen = BeginEnumGeneration("node_type", "NodeType", false, true);
|
||||
|
||||
#if 0
|
||||
// TODO(Peter): Create a FilterTypesByTag function to create a contiguous array
|
||||
// of type_definition**
|
||||
printf("\n\n");
|
||||
for (u32 i = 0; i < Meta.TypeTable.Types.Used; i++)
|
||||
{
|
||||
type_definition* Decl = Meta.TypeTable.Types.GetElementAtIndex(i);
|
||||
if (HasTag(MakeStringLiteral("node_proc"), Decl->MetaTags) &&
|
||||
Decl->Type == TypeDef_Function)
|
||||
{
|
||||
AddEnumElement(&NodeTypeGen, Decl->Identifier);
|
||||
|
||||
type_table_handle ReturnTypeHandle = Decl->Function.ReturnTypeHandle;
|
||||
type_definition* ReturnType = GetTypeDefinition(ReturnTypeHandle, Meta.TypeTable);
|
||||
printf("%.*s %.*s(\n", StringExpand(ReturnType->Identifier), StringExpand(Decl->Identifier));
|
||||
for (u32 j = 0; j < Decl->Function.Parameters.Used; j++)
|
||||
{
|
||||
variable_decl* Param = Decl->Function.Parameters.GetElementAtIndex(j);
|
||||
type_table_handle ParamTypeHandle = Param->TypeHandle;
|
||||
type_definition* ParamType = GetTypeDefinition(ParamTypeHandle, Meta.TypeTable);
|
||||
printf(" %.*s %.*s,\n", StringExpand(ParamType->Identifier), StringExpand(Param->Identifier));
|
||||
}
|
||||
printf(");\n\n");
|
||||
}
|
||||
}
|
||||
printf("\n\n");
|
||||
#endif
|
||||
|
||||
FinishEnumGeneration(&NodeTypeGen);
|
||||
|
||||
FILE* TypeInfoH = fopen("C:\\projects\\foldhaus\\src\\generated\\gs_meta_generated_typeinfo.h", "w");
|
||||
if (TypeInfoH)
|
||||
{
|
||||
WriteStringBuilderToFile(TypeGenerator.TypeList, TypeInfoH);
|
||||
WriteStringBuilderToFile(*TypeGenerator.TypeList.Builder, TypeInfoH);
|
||||
WriteStringBuilderToFile(TypeGenerator.StructMembers, TypeInfoH);
|
||||
WriteStringBuilderToFile(TypeGenerator.TypeDefinitions, TypeInfoH);
|
||||
fclose(TypeInfoH);
|
||||
}
|
||||
|
||||
FILE* NodeInfoH = fopen("C:\\projects\\foldhaus\\src\\generated\\foldhaus_nodes_generated.h", "w");
|
||||
if (NodeInfoH)
|
||||
{
|
||||
WriteStringBuilderToFile(*NodeTypeGen.Builder, NodeInfoH);
|
||||
fclose(NodeInfoH);
|
||||
}
|
||||
|
||||
FinishMetaprogram(&Meta);
|
||||
//__debugbreak();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FOLDHAUS_META_CPP
|
||||
#endif // FOLDHAUS_META_CPP
|
|
@ -16,10 +16,17 @@ enum type_definition_type
|
|||
TypeDef_Union,
|
||||
TypeDef_BasicType,
|
||||
TypeDef_FunctionPointer,
|
||||
TypeDef_Function,
|
||||
|
||||
TypeDef_Count,
|
||||
};
|
||||
|
||||
struct type_table_handle
|
||||
{
|
||||
s32 BucketIndex;
|
||||
u32 IndexInBucket;
|
||||
};
|
||||
|
||||
struct meta_tag
|
||||
{
|
||||
string Identifier;
|
||||
|
@ -31,7 +38,7 @@ struct variable_decl
|
|||
// at the same time. This means that not all types will be able to be matched
|
||||
// up on the first pass through. A TypeIndex of -1 means we need to fixup that
|
||||
// type at a later time
|
||||
s32 TypeIndex;
|
||||
type_table_handle TypeHandle;
|
||||
string Identifier;
|
||||
b32 Pointer;
|
||||
|
||||
|
@ -45,6 +52,7 @@ struct variable_decl
|
|||
|
||||
struct struct_decl
|
||||
{
|
||||
b32 IsAnonymous;
|
||||
// TODO(Peter): Lots of tiny arrays everywhere! Pull these into a central allocation
|
||||
// buffer somewhere
|
||||
// :SmallAllocationsAllOver
|
||||
|
@ -53,11 +61,18 @@ struct struct_decl
|
|||
|
||||
struct function_pointer_decl
|
||||
{
|
||||
s32 ReturnTypeIndex;
|
||||
type_table_handle ReturnTypeHandle;
|
||||
// :SmallAllocationsAllOver
|
||||
gs_bucket<variable_decl> Parameters;
|
||||
};
|
||||
|
||||
struct function_decl
|
||||
{
|
||||
type_table_handle ReturnTypeHandle;
|
||||
gs_bucket<variable_decl> Parameters;
|
||||
// TODO(Peter): AST?
|
||||
};
|
||||
|
||||
struct enum_decl
|
||||
{
|
||||
gs_bucket<string> Identifiers;
|
||||
|
@ -80,13 +95,22 @@ struct type_definition
|
|||
enum_decl Enum;
|
||||
struct_decl Struct;
|
||||
function_pointer_decl FunctionPtr;
|
||||
function_decl Function;
|
||||
};
|
||||
b32 Pointer;
|
||||
};
|
||||
|
||||
#define TYPE_TABLE_BUCKET_MAX 1024
|
||||
struct type_table_hash_bucket
|
||||
{
|
||||
u32* Keys;
|
||||
type_definition* Values;
|
||||
};
|
||||
|
||||
struct type_table
|
||||
{
|
||||
gs_bucket<type_definition> Types;
|
||||
type_table_hash_bucket* Types;
|
||||
u32 TypeBucketsCount;
|
||||
};
|
||||
|
||||
internal b32
|
||||
|
@ -119,63 +143,190 @@ CopyMetaTagsAndClear(gs_bucket<token>* Source, gs_bucket<meta_tag>* Dest)
|
|||
Source->Used = 0;
|
||||
}
|
||||
|
||||
internal s32
|
||||
#define InvalidTypeTableHandle type_table_handle{0, 0}
|
||||
|
||||
// #define TypeHandleIsValid(handle) (!((handle).BucketIndex == 0) && ((handle).IndexInBucket == 0))
|
||||
inline b32 TypeHandleIsValid(type_table_handle A)
|
||||
{
|
||||
b32 FirstBucket = (A.BucketIndex == 0);
|
||||
b32 FirstIndex = (A.IndexInBucket == 0);
|
||||
b32 Both = FirstBucket && FirstIndex;
|
||||
return !Both;
|
||||
}
|
||||
|
||||
#define TypeHandlesEqual(a, b) (((a).BucketIndex == (b).BucketIndex) && ((a).IndexInBucket == (b).IndexInBucket))
|
||||
|
||||
internal u32
|
||||
HashIdentifier(string Identifier)
|
||||
{
|
||||
u32 IdentHash = HashString(Identifier);
|
||||
if (IdentHash == 0)
|
||||
{
|
||||
// NOTE(Peter): We are excluding a has of zero so taht
|
||||
// the type_table_handle where BucketIndex and IndexInBucket
|
||||
// are both zero is an invalid handle
|
||||
IdentHash += 1;
|
||||
}
|
||||
return IdentHash;
|
||||
}
|
||||
|
||||
internal type_table_handle
|
||||
PushTypeOnHashTable(type_definition TypeDef, type_table* TypeTable)
|
||||
{
|
||||
type_table_handle Result = InvalidTypeTableHandle;
|
||||
|
||||
u32 IdentHash = HashIdentifier(TypeDef.Identifier);
|
||||
u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX;
|
||||
|
||||
for (u32 b = 0; b < TypeTable->TypeBucketsCount; b++)
|
||||
{
|
||||
type_table_hash_bucket* Bucket = TypeTable->Types + b;
|
||||
if (Bucket->Keys[Index] == 0)
|
||||
{
|
||||
Bucket->Keys[Index] = IdentHash;
|
||||
Bucket->Values[Index] = TypeDef;
|
||||
|
||||
Result.BucketIndex = b;
|
||||
Result.IndexInBucket = Index;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TypeHandleIsValid(Result))
|
||||
{
|
||||
// Grow Hash Table
|
||||
u32 NewTypeBucketIndex = TypeTable->TypeBucketsCount++;
|
||||
u32 NewTypesSize = TypeTable->TypeBucketsCount * sizeof(type_table_hash_bucket);
|
||||
TypeTable->Types = (type_table_hash_bucket*)realloc(TypeTable->Types, NewTypesSize);
|
||||
|
||||
type_table_hash_bucket* NewBucket = TypeTable->Types + NewTypeBucketIndex;
|
||||
NewBucket->Keys = (u32*)malloc(sizeof(u32) * TYPE_TABLE_BUCKET_MAX);
|
||||
NewBucket->Values = (type_definition*)malloc(sizeof(type_definition) * TYPE_TABLE_BUCKET_MAX);
|
||||
GSZeroMemory((u8*)NewBucket->Keys, sizeof(u32) * TYPE_TABLE_BUCKET_MAX);
|
||||
GSZeroMemory((u8*)NewBucket->Values, sizeof(type_definition) * TYPE_TABLE_BUCKET_MAX);
|
||||
|
||||
NewBucket->Keys[Index] = IdentHash;
|
||||
NewBucket->Values[Index] = TypeDef;
|
||||
|
||||
Result.BucketIndex = NewTypeBucketIndex;
|
||||
Result.IndexInBucket = Index;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal type_table_handle
|
||||
PushUndeclaredType (string Identifier, type_table* TypeTable)
|
||||
{
|
||||
type_definition UndeclaredTypeDef = {};
|
||||
UndeclaredTypeDef.Identifier = Identifier;
|
||||
UndeclaredTypeDef.Type = TypeDef_Unknown;
|
||||
s32 TypeIndex = (s32)TypeTable->Types.PushElementOnBucket(UndeclaredTypeDef);
|
||||
return TypeIndex;
|
||||
type_table_handle Result = PushTypeOnHashTable(UndeclaredTypeDef, TypeTable);
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal s32
|
||||
GetIndexOfType (string Identifier, type_table TypeTable)
|
||||
internal type_table_handle
|
||||
GetTypeHandle (string Identifier, type_table TypeTable)
|
||||
{
|
||||
s32 Result = -1;
|
||||
for (u32 i = 0; i < TypeTable.Types.Used; i++)
|
||||
type_table_handle Result = InvalidTypeTableHandle;
|
||||
|
||||
u32 IdentHash = HashIdentifier(Identifier);
|
||||
u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX;
|
||||
|
||||
for (u32 b = 0; b < TypeTable.TypeBucketsCount; b++)
|
||||
{
|
||||
type_definition* TypeDef = TypeTable.Types.GetElementAtIndex(i);
|
||||
if (StringsEqual(Identifier, TypeDef->Identifier))
|
||||
type_table_hash_bucket Bucket = TypeTable.Types[b];
|
||||
if (Bucket.Keys[Index] == IdentHash)
|
||||
{
|
||||
Result = i;
|
||||
Result.BucketIndex = b;
|
||||
Result.IndexInBucket = Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Guaranteed to return a valid result
|
||||
internal type_definition*
|
||||
GetTypeDefinition(type_table_handle Handle, type_table TypeTable)
|
||||
{
|
||||
Assert(TypeHandleIsValid(Handle));
|
||||
type_definition* Result = 0;
|
||||
if (TypeTable.Types[Handle.BucketIndex].Keys != 0)
|
||||
{
|
||||
Result = TypeTable.Types[Handle.BucketIndex].Values + Handle.IndexInBucket;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
// May return zero
|
||||
internal type_definition*
|
||||
GetTypeDefinitionUnsafe(type_table_handle Handle, type_table TypeTable)
|
||||
{
|
||||
type_definition* Result = 0;
|
||||
if (TypeTable.Types[Handle.BucketIndex].Keys != 0)
|
||||
{
|
||||
Result = TypeTable.Types[Handle.BucketIndex].Values + Handle.IndexInBucket;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal type_definition*
|
||||
GetTypeDefinition(string Identifier, type_table TypeTable)
|
||||
{
|
||||
type_definition* Result = 0;
|
||||
u32 IdentHash = HashIdentifier(Identifier);
|
||||
u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX;
|
||||
for (u32 b = 0; b < TypeTable.TypeBucketsCount; b++)
|
||||
{
|
||||
type_table_hash_bucket Bucket = TypeTable.Types[b];
|
||||
if (Bucket.Keys[Index] == IdentHash )
|
||||
{
|
||||
Result = Bucket.Values + Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal s32
|
||||
internal type_table_handle
|
||||
PushTypeDefOnTypeTable(type_definition TypeDef, type_table* TypeTable)
|
||||
{
|
||||
s32 Index = -1;
|
||||
// NOTE(Peter): We don't accept type definitions with empty identifiers.
|
||||
// If a struct or union is anonymous, it should be assigned a name of the form
|
||||
// parent_struct_name_# where # is the member index
|
||||
// ie.
|
||||
// struct foo { int a; union { int x }; };
|
||||
// the union in foo would have the identifier foo_1
|
||||
Assert(TypeDef.Identifier.Length != 0);
|
||||
|
||||
s32 ExistingUndeclaredTypeIndex = GetIndexOfType(TypeDef.Identifier, *TypeTable);
|
||||
type_table_handle Result = InvalidTypeTableHandle;
|
||||
type_table_handle ExistingUndeclaredTypeHandle = GetTypeHandle(TypeDef.Identifier, *TypeTable);
|
||||
|
||||
// NOTE(Peter): If the identifier length is zero, they will all match with the
|
||||
// first anonymous struct/union member. So every anon struct/union gets its own
|
||||
// typeef
|
||||
if (ExistingUndeclaredTypeIndex < 0 || TypeDef.Identifier.Length == 0)
|
||||
if (!TypeHandleIsValid(ExistingUndeclaredTypeHandle))
|
||||
{
|
||||
Index = TypeTable->Types.PushElementOnBucket(TypeDef);
|
||||
Result = PushTypeOnHashTable(TypeDef, TypeTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
Index = ExistingUndeclaredTypeIndex;
|
||||
type_definition* ExistingTypeDef = TypeTable->Types.GetElementAtIndex(ExistingUndeclaredTypeIndex);
|
||||
Result = ExistingUndeclaredTypeHandle;
|
||||
type_definition* ExistingTypeDef = GetTypeDefinition(Result, *TypeTable);
|
||||
Assert(ExistingTypeDef != 0);
|
||||
*ExistingTypeDef = TypeDef;
|
||||
}
|
||||
|
||||
return Index;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal s32
|
||||
GetSizeOfType (s32 TypeIndex, type_table TypeTable)
|
||||
GetSizeOfType (type_table_handle TypeHandle, type_table TypeTable)
|
||||
{
|
||||
s32 Result = -1;
|
||||
Assert(TypeIndex >= 0 && (u32)TypeIndex < TypeTable.Types.Used);
|
||||
type_definition* TypeDef = TypeTable.Types.GetElementAtIndex(TypeIndex);
|
||||
Result = TypeDef->Size;
|
||||
type_definition* TypeDef = GetTypeDefinition(TypeHandle, TypeTable);
|
||||
if (TypeDef)
|
||||
{
|
||||
Result = TypeDef->Size;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
@ -183,14 +334,10 @@ internal s32
|
|||
GetSizeOfType (string Identifier, type_table TypeTable)
|
||||
{
|
||||
s32 Result = -1;
|
||||
for (u32 i = 0; i < TypeTable.Types.Used; i++)
|
||||
type_definition* TypeDef = GetTypeDefinition(Identifier, TypeTable);
|
||||
if (TypeDef)
|
||||
{
|
||||
type_definition* TypeDef = TypeTable.Types.GetElementAtIndex(i);
|
||||
if (StringsEqual(Identifier, TypeDef->Identifier))
|
||||
{
|
||||
Result = TypeDef->Size;
|
||||
break;
|
||||
}
|
||||
Result = TypeDef->Size;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
@ -199,7 +346,7 @@ internal b32
|
|||
VariableDeclsEqual (variable_decl A, variable_decl B)
|
||||
{
|
||||
b32 Result = false;
|
||||
if (A.TypeIndex == B.TypeIndex &&
|
||||
if (TypeHandlesEqual(A.TypeHandle, B.TypeHandle) &&
|
||||
A.ArrayCount == B.ArrayCount &&
|
||||
StringsEqual(A.Identifier, B.Identifier))
|
||||
{
|
||||
|
@ -236,51 +383,35 @@ StructOrUnionsEqual (type_definition A, type_definition B)
|
|||
return Result;
|
||||
}
|
||||
|
||||
internal s32
|
||||
FindIndexOfMatchingType (type_definition Match, type_table TypeTable)
|
||||
internal type_table_handle
|
||||
FindHandleOfMatchingType (type_definition Match, type_table TypeTable)
|
||||
{
|
||||
s32 Result = -1;
|
||||
for (u32 i = 0; i < TypeTable.Types.Used; i++)
|
||||
type_table_handle Result = InvalidTypeTableHandle;
|
||||
type_table_handle Handle = GetTypeHandle(Match.Identifier, TypeTable);
|
||||
if (TypeHandleIsValid(Handle))
|
||||
{
|
||||
type_definition* TypeDef = TypeTable.Types.GetElementAtIndex(i);
|
||||
if (StringsEqual(Match.Identifier, TypeDef->Identifier))
|
||||
{
|
||||
if (Match.Type == TypeDef_Struct ||
|
||||
Match.Type == TypeDef_Union)
|
||||
{
|
||||
if (StructOrUnionsEqual(Match, *TypeDef))
|
||||
{
|
||||
Result = (s32)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = (s32)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Result = Handle;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void FixUpStructSize (s32 StructIndex, type_table TypeTable, errors* Errors);
|
||||
internal void FixUpUnionSize (s32 UnionIndex, type_table TypeTable, errors* Errors);
|
||||
internal void FixUpStructSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors);
|
||||
internal void FixUpUnionSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors);
|
||||
|
||||
internal void
|
||||
FixupMemberType (variable_decl* Member, type_table TypeTable)
|
||||
{
|
||||
if (Member->TypeIndex == -1)
|
||||
if (!TypeHandleIsValid(Member->TypeHandle))
|
||||
{
|
||||
Member->TypeIndex = GetIndexOfType(Member->Identifier, TypeTable);
|
||||
Member->TypeHandle = GetTypeHandle(Member->Identifier, TypeTable);
|
||||
}
|
||||
Assert(Member->TypeIndex >= 0);
|
||||
Assert(TypeHandleIsValid(Member->TypeHandle));
|
||||
}
|
||||
|
||||
internal s32
|
||||
CalculateStructMemberSize (variable_decl Member, type_definition MemberType)
|
||||
{
|
||||
Assert(Member.TypeIndex >= 0);
|
||||
Assert(TypeHandleIsValid(Member.TypeHandle));
|
||||
// NOTE(Peter): At one point we were Asserting on struct sizes of zero, but
|
||||
// that's actually incorrect. It is valid to have an empty struct.
|
||||
|
||||
|
@ -325,11 +456,11 @@ FixupStructMember (variable_decl* Member, type_definition* MemberTypeDef, type_t
|
|||
{
|
||||
if (MemberTypeDef->Type == TypeDef_Struct)
|
||||
{
|
||||
FixUpStructSize(Member->TypeIndex, TypeTable, Errors);
|
||||
FixUpStructSize(Member->TypeHandle, TypeTable, Errors);
|
||||
}
|
||||
else if (MemberTypeDef->Type == TypeDef_Union)
|
||||
{
|
||||
FixUpUnionSize(Member->TypeIndex, TypeTable, Errors);
|
||||
FixUpUnionSize(Member->TypeHandle, TypeTable, Errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -353,9 +484,9 @@ FixupStructMember (variable_decl* Member, type_definition* MemberTypeDef, type_t
|
|||
}
|
||||
|
||||
internal void
|
||||
FixUpStructSize (s32 StructIndex, type_table TypeTable, errors* Errors)
|
||||
FixUpStructSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors)
|
||||
{
|
||||
type_definition* Struct = TypeTable.Types.GetElementAtIndex(StructIndex);
|
||||
type_definition* Struct = GetTypeDefinition(TypeHandle, TypeTable);
|
||||
Assert(Struct->Type == TypeDef_Struct);
|
||||
|
||||
if (HasTag(MakeStringLiteral("breakpoint"), Struct->MetaTags))
|
||||
|
@ -369,12 +500,10 @@ FixUpStructSize (s32 StructIndex, type_table TypeTable, errors* Errors)
|
|||
variable_decl* Member = Struct->Struct.MemberDecls.GetElementAtIndex(j);
|
||||
FixupMemberType(Member, TypeTable);
|
||||
|
||||
if (Member->TypeIndex >= 0)
|
||||
if (TypeHandleIsValid(Member->TypeHandle))
|
||||
{
|
||||
type_definition* MemberTypeDef = TypeTable.Types.GetElementAtIndex(Member->TypeIndex);
|
||||
|
||||
type_definition* MemberTypeDef = GetTypeDefinition(Member->TypeHandle, TypeTable);
|
||||
FixupStructMember(Member, MemberTypeDef, TypeTable, Errors);
|
||||
|
||||
u32 MemberSize = CalculateStructMemberSize(*Member, *MemberTypeDef);
|
||||
SizeAcc += MemberSize;
|
||||
}
|
||||
|
@ -400,9 +529,9 @@ FixUpStructSize (s32 StructIndex, type_table TypeTable, errors* Errors)
|
|||
}
|
||||
|
||||
internal void
|
||||
FixUpUnionSize (s32 UnionIndex, type_table TypeTable, errors* Errors)
|
||||
FixUpUnionSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors)
|
||||
{
|
||||
type_definition* Union = TypeTable.Types.GetElementAtIndex(UnionIndex);
|
||||
type_definition* Union = GetTypeDefinition(TypeHandle, TypeTable);
|
||||
Assert(Union->Type == TypeDef_Union);
|
||||
|
||||
s32 BiggestMemberSize = 0;
|
||||
|
@ -411,9 +540,9 @@ FixUpUnionSize (s32 UnionIndex, type_table TypeTable, errors* Errors)
|
|||
variable_decl* Member = Union->Struct.MemberDecls.GetElementAtIndex(j);
|
||||
FixupMemberType(Member, TypeTable);
|
||||
|
||||
if (Member->TypeIndex >= 0)
|
||||
if (TypeHandleIsValid(Member->TypeHandle))
|
||||
{
|
||||
type_definition* MemberTypeDef = TypeTable.Types.GetElementAtIndex(Member->TypeIndex);
|
||||
type_definition* MemberTypeDef = GetTypeDefinition(Member->TypeHandle, TypeTable);
|
||||
FixupStructMember(Member, MemberTypeDef, TypeTable, Errors);
|
||||
s32 MemberSize = CalculateStructMemberSize(*Member, *MemberTypeDef);
|
||||
BiggestMemberSize = GSMax(BiggestMemberSize, MemberSize);
|
||||
|
|
596
meta/gs_meta.cpp
596
meta/gs_meta.cpp
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// File: gs_meta_code_generator.h
|
||||
// Author: Peter Slattery
|
||||
// Creation Date: 2020-01-20
|
||||
//
|
||||
#ifndef GS_META_CODE_GENERATOR_H
|
||||
|
||||
#include <gs_string.h>
|
||||
#include <gs_string_builder.h>
|
||||
|
||||
enum gsm_code_gen_type
|
||||
{
|
||||
gsm_CodeGen_Enum,
|
||||
gsm_CodeGen_Count,
|
||||
};
|
||||
|
||||
struct gsm_enum_generator
|
||||
{
|
||||
string Identifier;
|
||||
string Prefix;
|
||||
b32 EndsWithCount;
|
||||
};
|
||||
|
||||
struct gsm_code_generator
|
||||
{
|
||||
gsm_code_gen_type Type;
|
||||
string_builder* Builder;
|
||||
|
||||
union
|
||||
{
|
||||
gsm_enum_generator Enum;
|
||||
};
|
||||
};
|
||||
|
||||
// ---------------
|
||||
// Enum
|
||||
// ---------------
|
||||
|
||||
internal gsm_code_generator
|
||||
BeginEnumGeneration(string EnumIdentifier, string ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount)
|
||||
{
|
||||
gsm_code_generator Gen = {};
|
||||
|
||||
// TODO(Peter): TEMP!!
|
||||
Gen.Builder = (string_builder*)malloc(sizeof(string_builder));
|
||||
*Gen.Builder = {};
|
||||
|
||||
Gen.Type = gsm_CodeGen_Enum;
|
||||
Gen.Enum.Identifier = EnumIdentifier;
|
||||
Gen.Enum.Prefix = ValuePrefix;
|
||||
Gen.Enum.EndsWithCount = EndsWithCount;
|
||||
|
||||
WriteF(Gen.Builder, "enum %S\n{\n", EnumIdentifier);
|
||||
if (StartsWithInvalid)
|
||||
{
|
||||
WriteF(Gen.Builder, " %S_Invalid,\n", ValuePrefix);
|
||||
}
|
||||
|
||||
return Gen;
|
||||
}
|
||||
|
||||
internal gsm_code_generator
|
||||
BeginEnumGeneration(char* EnumIdentifier, char* ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount)
|
||||
{
|
||||
return BeginEnumGeneration(MakeStringLiteral(EnumIdentifier),
|
||||
MakeStringLiteral(ValuePrefix),
|
||||
StartsWithInvalid,
|
||||
EndsWithCount);
|
||||
}
|
||||
|
||||
internal void
|
||||
AddEnumElement(gsm_code_generator* Gen, string ElementIdentifier)
|
||||
{
|
||||
// TODO(Peter): Support const expr defining enum values
|
||||
Assert(Gen->Type == gsm_CodeGen_Enum);
|
||||
WriteF(Gen->Builder, " %S_%S,\n", Gen->Enum.Prefix, ElementIdentifier);
|
||||
}
|
||||
|
||||
internal void
|
||||
AddEnumElement(gsm_code_generator* Gen, char* ElementIdentifier)
|
||||
{
|
||||
AddEnumElement(Gen, MakeStringLiteral(ElementIdentifier));
|
||||
}
|
||||
|
||||
internal void
|
||||
FinishEnumGeneration(gsm_code_generator* Gen)
|
||||
{
|
||||
Assert(Gen->Type == gsm_CodeGen_Enum);
|
||||
|
||||
if (Gen->Enum.EndsWithCount)
|
||||
{
|
||||
WriteF(Gen->Builder, " %S_Count,\n", Gen->Enum.Prefix);
|
||||
}
|
||||
|
||||
WriteF(Gen->Builder, "};\n\n");
|
||||
}
|
||||
|
||||
|
||||
#define GS_META_CODE_GENERATOR_H
|
||||
#endif // GS_META_CODE_GENERATOR_H
|
|
@ -121,8 +121,7 @@ GetNextToken (tokenizer* Tokenizer)
|
|||
Tokenizer->At += 2;
|
||||
break;
|
||||
}
|
||||
EatToNewLine(Tokenizer);
|
||||
EatWhitespace(Tokenizer);
|
||||
Tokenizer->At++;
|
||||
}
|
||||
EatWhitespace(Tokenizer);
|
||||
}
|
||||
|
|
|
@ -3,15 +3,21 @@
|
|||
// Author: Peter Slattery
|
||||
// Creation Date: 2020-01-19
|
||||
//
|
||||
// Usage
|
||||
// TODO
|
||||
//
|
||||
//
|
||||
#ifndef GS_META_TYPEINFO_GENERATOR_H
|
||||
|
||||
#include <gs_language.h>
|
||||
#include <gs_string.h>
|
||||
#include <gs_string_builder.h>
|
||||
#include "gs_meta_code_generator.h"
|
||||
|
||||
struct typeinfo_generator
|
||||
{
|
||||
string_builder TypeList;
|
||||
string_builder TypeListString;
|
||||
gsm_code_generator TypeList;
|
||||
string_builder StructMembers;
|
||||
string_builder TypeDefinitions;
|
||||
|
||||
|
@ -20,16 +26,17 @@ struct typeinfo_generator
|
|||
b8* TypesGeneratedMask;
|
||||
};
|
||||
|
||||
#define TypeHandleToIndex(handle) ((handle.BucketIndex * TYPE_TABLE_BUCKET_MAX) + handle.IndexInBucket)
|
||||
internal typeinfo_generator
|
||||
InitTypeInfoGenerator(type_table TypeTable)
|
||||
{
|
||||
typeinfo_generator Result = {};
|
||||
|
||||
Result.TypesMax = TypeTable.Types.Used;
|
||||
Result.TypesMax = TypeTable.TypeBucketsCount * TYPE_TABLE_BUCKET_MAX;
|
||||
Result.TypesGeneratedMask = (b8*)malloc(sizeof(b8) * Result.TypesMax);
|
||||
GSZeroMemory((u8*)Result.TypesGeneratedMask, Result.TypesMax);
|
||||
|
||||
WriteF(&Result.TypeList, "enum gsm_struct_type\n{\n");
|
||||
Result.TypeList = BeginEnumGeneration("gsm_struct_type", "gsm_StructType", false, true);
|
||||
|
||||
WriteF(&Result.TypeDefinitions, "static gsm_struct_type_info StructTypes[] = {\n");
|
||||
return Result;
|
||||
|
@ -38,12 +45,12 @@ InitTypeInfoGenerator(type_table TypeTable)
|
|||
internal void
|
||||
FinishGeneratingTypes(typeinfo_generator* Generator)
|
||||
{
|
||||
WriteF(&Generator->TypeList, "gsm_StructTypeCount,\n};\n\n");
|
||||
FinishEnumGeneration(&Generator->TypeList);
|
||||
|
||||
WriteF(&Generator->StructMembers, "\n");
|
||||
|
||||
WriteF(&Generator->TypeDefinitions, "};\n");
|
||||
WriteF(&Generator->TypeDefinitions, "gsm_u32 StructTypesCount = %d;\n", Generator->GeneratedInfoTypesCount);
|
||||
WriteF(&Generator->TypeDefinitions, "static gsm_u32 StructTypesCount = %d;\n", Generator->GeneratedInfoTypesCount);
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -71,9 +78,12 @@ GenerateStructMemberInfo (variable_decl* Member, string StructIdentifier, type_t
|
|||
}
|
||||
|
||||
internal void
|
||||
GenerateTypeInfo (type_definition* Type, u32 TypeIndex, type_table TypeTable, typeinfo_generator* Generator)
|
||||
GenerateTypeInfo (type_definition* Type, type_table_handle TypeHandle, type_table TypeTable, typeinfo_generator* Generator)
|
||||
{
|
||||
Generator->TypesGeneratedMask[TypeIndex] = true;
|
||||
// TODO(Peter):
|
||||
// 1. allocate the full range of the types hash table
|
||||
// 2. use bucketindex * bucket_max + indexinbucket to get the consecutive index
|
||||
Generator->TypesGeneratedMask[TypeHandleToIndex(TypeHandle)] = true;
|
||||
Generator->GeneratedInfoTypesCount++;
|
||||
|
||||
{
|
||||
|
@ -81,8 +91,7 @@ GenerateTypeInfo (type_definition* Type, u32 TypeIndex, type_table TypeTable, ty
|
|||
// type info for any member types. If it doesn't, it will screw
|
||||
// up array ordering
|
||||
|
||||
// Lookup Enum
|
||||
WriteF(&Generator->TypeList, "gsm_StructType_%S,\n", Type->Identifier);
|
||||
AddEnumElement(&Generator->TypeList, Type->Identifier);
|
||||
|
||||
// Type Info
|
||||
WriteF(&Generator->TypeDefinitions, "{ gsm_StructType_%S, \"%S\", %d, %d, 0, 0, ",
|
||||
|
@ -110,12 +119,18 @@ GenerateTypeInfo (type_definition* Type, u32 TypeIndex, type_table TypeTable, ty
|
|||
for (u32 m = 0; m < Type->Struct.MemberDecls.Used; m++)
|
||||
{
|
||||
variable_decl* Member = Type->Struct.MemberDecls.GetElementAtIndex(m);
|
||||
type_definition* MemberType = TypeTable.Types.GetElementAtIndex(Member->TypeIndex);
|
||||
type_definition* MemberType = GetTypeDefinition(Member->TypeHandle, TypeTable);
|
||||
|
||||
if (MemberType->Identifier.Length == 0) { continue; } // Don't gen info for anonymous struct and union members
|
||||
if (Generator->TypesGeneratedMask[Member->TypeIndex]) { continue; }
|
||||
if ((MemberType->Type == TypeDef_Struct ||
|
||||
MemberType->Type == TypeDef_Union) &&
|
||||
MemberType->Struct.IsAnonymous)
|
||||
{
|
||||
continue; // Don't gen info for anonymous struct and union members
|
||||
}
|
||||
|
||||
GenerateTypeInfo(MemberType, Member->TypeIndex, TypeTable, Generator);
|
||||
if (Generator->TypesGeneratedMask[TypeHandleToIndex(Member->TypeHandle)]) { continue; }
|
||||
|
||||
GenerateTypeInfo(MemberType, Member->TypeHandle, TypeTable, Generator);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -123,14 +138,14 @@ GenerateTypeInfo (type_definition* Type, u32 TypeIndex, type_table TypeTable, ty
|
|||
for (u32 m = 0; m < Type->Struct.MemberDecls.Used; m++)
|
||||
{
|
||||
variable_decl* Member = Type->Struct.MemberDecls.GetElementAtIndex(m);
|
||||
type_definition* MemberType = TypeTable.Types.GetElementAtIndex(Member->TypeIndex);
|
||||
type_definition* MemberType = GetTypeDefinition(Member->TypeHandle, TypeTable);
|
||||
|
||||
if (MemberType->Identifier.Length > 0)
|
||||
if ((MemberType->Type != TypeDef_Struct && MemberType->Type != TypeDef_Union) ||
|
||||
!MemberType->Struct.IsAnonymous)
|
||||
{
|
||||
GenerateStructMemberInfo(Member, Type->Identifier, TypeTable, Generator);
|
||||
}
|
||||
else if (MemberType->Type == TypeDef_Struct ||
|
||||
MemberType->Type == TypeDef_Union)
|
||||
else if (MemberType->Struct.IsAnonymous)
|
||||
{
|
||||
// Anonymous Members
|
||||
for (u32 a = 0; a < MemberType->Struct.MemberDecls.Used; a++)
|
||||
|
@ -147,17 +162,29 @@ GenerateTypeInfo (type_definition* Type, u32 TypeIndex, type_table TypeTable, ty
|
|||
internal void
|
||||
GenerateFilteredTypeInfo (string MetaTagFilter, type_table TypeTable, typeinfo_generator* Generator)
|
||||
{
|
||||
for (u32 i = 0; i < TypeTable.Types.Used; i++)
|
||||
for (u32 b = 0; b < TypeTable.TypeBucketsCount; b++)
|
||||
{
|
||||
if (Generator->TypesGeneratedMask[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
type_table_hash_bucket Bucket = TypeTable.Types[b];
|
||||
|
||||
type_definition* Type = TypeTable.Types.GetElementAtIndex(i);
|
||||
if (HasTag(MetaTagFilter, Type->MetaTags))
|
||||
for (u32 i = 0; i < TYPE_TABLE_BUCKET_MAX; i++)
|
||||
{
|
||||
GenerateTypeInfo(Type, i, TypeTable, Generator);
|
||||
type_table_handle TypeHandle = {};
|
||||
TypeHandle.BucketIndex = b;
|
||||
TypeHandle.IndexInBucket = i;
|
||||
|
||||
if (Generator->TypesGeneratedMask[TypeHandleToIndex(TypeHandle)])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
type_definition* Type = GetTypeDefinitionUnsafe(TypeHandle, TypeTable);
|
||||
if (Type)
|
||||
{
|
||||
if (HasTag(MetaTagFilter, Type->MetaTags))
|
||||
{
|
||||
GenerateTypeInfo(Type, TypeHandle, TypeTable, Generator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ node_specification* NodeSpecifications = 0;
|
|||
|
||||
|
||||
#include "assembly_parser.cpp"
|
||||
//#include "test_patterns.h"
|
||||
#include "test_patterns.h"
|
||||
|
||||
// TODO(Peter): something we can do later is to remove all reliance on app_state and context
|
||||
// from foldhaus_pane.h. It should just emit lists of things that the app can iterate over and
|
||||
|
|
|
@ -1,22 +1,5 @@
|
|||
#define GENERATED_NODE_TYPES \
|
||||
NodeType_MultiplyNodeProc, \
|
||||
NodeType_AddNodeProc, \
|
||||
NodeType_FloatValueProc, \
|
||||
NodeType_SolidColorProc, \
|
||||
NodeType_VerticalColorFadeProc
|
||||
|
||||
#define GENERATED_NODE_SPECS \
|
||||
{ NodeType_MultiplyNodeProc, "MultiplyNodeProc", 16, MemberList_multiply_data, 12, 3, 2, 1, false}, \
|
||||
{ NodeType_AddNodeProc, "AddNodeProc", 11, MemberList_add_data, 48, 3, 2, 1, false}, \
|
||||
{ NodeType_FloatValueProc, "FloatValueProc", 14, MemberList_float_value_data, 8, 2, 1, 1, false}, \
|
||||
{ NodeType_SolidColorProc, "SolidColorProc", 14, MemberList_solid_color_data, 16, 1, 1, 0, true}, \
|
||||
{ NodeType_VerticalColorFadeProc, "VerticalColorFadeProc", 21, MemberList_vertical_color_fade_data, 24, 3, 3, 0, true}
|
||||
#define GENERATED_NODE_SPECS_COUNT 5
|
||||
|
||||
#define EVALUATE_GENERATED_NODES \
|
||||
case NodeType_MultiplyNodeProc: { MultiplyNodeProc((multiply_data*)NodeData); } break; \
|
||||
case NodeType_AddNodeProc: { AddNodeProc((add_data*)NodeData); } break; \
|
||||
case NodeType_FloatValueProc: { FloatValueProc((float_value_data*)NodeData); } break; \
|
||||
case NodeType_SolidColorProc: { SolidColorProc((solid_color_data*)NodeData, LEDs, Colors, LEDCount); } break; \
|
||||
case NodeType_VerticalColorFadeProc: { VerticalColorFadeProc((vertical_color_fade_data*)NodeData, LEDs, Colors, LEDCount); } break; \
|
||||
enum node_type
|
||||
{
|
||||
NodeType_Count,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
enum gsm_struct_type
|
||||
{
|
||||
gsm_StructType_sin_wave_data,
|
||||
gsm_StructType_r32,
|
||||
gsm_StructType_multiply_patterns_data,
|
||||
gsm_StructType_color_buffer,
|
||||
gsm_StructType_led,
|
||||
gsm_StructType_s32,
|
||||
gsm_StructType_v4,
|
||||
gsm_StructType_float,
|
||||
gsm_StructType_pixel,
|
||||
gsm_StructType_u8,
|
||||
gsm_StructTypeCount,
|
||||
gsm_StructType_sin_wave_data,
|
||||
gsm_StructType_r32,
|
||||
gsm_StructType_multiply_patterns_data,
|
||||
gsm_StructType_color_buffer,
|
||||
gsm_StructType_led,
|
||||
gsm_StructType_s32,
|
||||
gsm_StructType_v4,
|
||||
gsm_StructType_float,
|
||||
gsm_StructType_pixel,
|
||||
gsm_StructType_u8,
|
||||
gsm_StructType_Count,
|
||||
};
|
||||
|
||||
static gsm_struct_member_type_info StructMembers_sin_wave_data[] = {
|
||||
|
@ -64,4 +64,4 @@ static gsm_struct_type_info StructTypes[] = {
|
|||
{ gsm_StructType_pixel, "pixel", 5, 3, 0, 0, StructMembers_pixel, 2 },
|
||||
{ gsm_StructType_u8, "u8", 2, 1, 0, 0, 0, 0 },
|
||||
};
|
||||
gsm_u32 StructTypesCount = 10;
|
||||
static gsm_u32 StructTypesCount = 10;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
//
|
||||
#ifndef TEST_PATTERNS_H
|
||||
|
||||
|
||||
GSMetaTag(node_struct)
|
||||
struct solid_color_data
|
||||
{
|
||||
|
@ -17,20 +16,20 @@ struct solid_color_data
|
|||
};
|
||||
|
||||
GSMetaTag(node_proc); // :TagParamsForNodeParamStructs
|
||||
void SolidColorProc, solid_color_data* Data)
|
||||
void SolidColorProc(solid_color_data* Data)
|
||||
{
|
||||
u8 R = (u8)GSClamp(0.f, (Data->Color.r * 255), 255.f);
|
||||
u8 G = (u8)GSClamp(0.f, (Data->Color.g * 255), 255.f);
|
||||
u8 B = (u8)GSClamp(0.f, (Data->Color.b * 255), 255.f);
|
||||
|
||||
led* LED = Data->ResultLEDs;
|
||||
for (s32 l = 0; l < Data->ResultLEDCount; l++)
|
||||
led* LED = Data->Result.LEDs;
|
||||
for (s32 l = 0; l < Data->Result.LEDCount; l++)
|
||||
{
|
||||
Assert(LED->Index >= 0 && LED->Index < Data->ResultLEDCount);
|
||||
Assert(LED->Index >= 0 && LED->Index < Data->Result.LEDCount);
|
||||
|
||||
Data->ResultColors[LED->Index].R = R;
|
||||
Data->ResultColors[LED->Index].G = G;
|
||||
Data->ResultColors[LED->Index].B = B;
|
||||
Data->Result.Colors[LED->Index].R = R;
|
||||
Data->Result.Colors[LED->Index].G = G;
|
||||
Data->Result.Colors[LED->Index].B = B;
|
||||
LED++;
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +51,7 @@ struct vertical_color_fade_data
|
|||
};
|
||||
|
||||
GSMetaTag(node_proc); // :TagParamsForNodeParamStructs
|
||||
void VerticalColorFadeProc, vertical_color_fade_data* Data)
|
||||
void VerticalColorFadeProc(vertical_color_fade_data* Data)
|
||||
{
|
||||
r32 R = (Data->Color.r * 255);
|
||||
r32 G = (Data->Color.g * 255);
|
||||
|
@ -60,17 +59,17 @@ void VerticalColorFadeProc, vertical_color_fade_data* Data)
|
|||
|
||||
r32 Range = Data->Max - Data->Min;
|
||||
|
||||
led* LED = Data->ResultLEDs;
|
||||
for (s32 l = 0; l < Data->ResultLEDCount; l++)
|
||||
led* LED = Data->Result.LEDs;
|
||||
for (s32 l = 0; l < Data->Result.LEDCount; l++)
|
||||
{
|
||||
Assert(LED->Index >= 0 && LED->Index < Data->ResultLEDCount);
|
||||
Assert(LED->Index >= 0 && LED->Index < Data->Result.LEDCount);
|
||||
|
||||
r32 Amount = (LED->Position.y - Data->Min) / Range;
|
||||
Amount = GSClamp01(1.0f - Amount);
|
||||
|
||||
Data->ResultColors[LED->Index].R = (u8)(R * Amount);
|
||||
Data->ResultColors[LED->Index].G = (u8)(G * Amount);
|
||||
Data->ResultColors[LED->Index].B = (u8)(B * Amount);
|
||||
Data->Result.Colors[LED->Index].R = (u8)(R * Amount);
|
||||
Data->Result.Colors[LED->Index].G = (u8)(G * Amount);
|
||||
Data->Result.Colors[LED->Index].B = (u8)(B * Amount);
|
||||
LED++;
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +104,7 @@ struct revolving_discs_data
|
|||
};
|
||||
|
||||
GSMetaTag(node_proc); // :TagParamsForNodeParamStructs
|
||||
void RevolvingDiscs, revolving_discs_data* Data)
|
||||
void RevolvingDiscs(revolving_discs_data* Data)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
|
||||
|
@ -125,8 +124,8 @@ void RevolvingDiscs, revolving_discs_data* Data)
|
|||
r32 OuterRadiusSquared = Data->OuterRadius * Data->OuterRadius;
|
||||
r32 InnerRadiusSquared = Data->InnerRadius * Data->InnerRadius;
|
||||
|
||||
led* LED = Data->ResultLEDs;
|
||||
for (s32 l = 0; l < Data->ResultLEDCount; l++)
|
||||
led* LED = Data->Result.LEDs;
|
||||
for (s32 l = 0; l < Data->Result.LEDCount; l++)
|
||||
{
|
||||
v4 Position = LED->Position;
|
||||
|
||||
|
@ -144,7 +143,7 @@ void RevolvingDiscs, revolving_discs_data* Data)
|
|||
{
|
||||
if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0))
|
||||
{
|
||||
Data->ResultColors[LED->Index] = Color;
|
||||
Data->Result.Colors[LED->Index] = Color;
|
||||
}
|
||||
}
|
||||
LED++;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <windowsx.h>
|
||||
#include <gl/gl.h>
|
||||
|
||||
#include "../meta/foldhaus_meta_include.h"
|
||||
#include "foldhaus_platform.h"
|
||||
|
||||
#include "gs_win32.cpp"
|
||||
|
|
Loading…
Reference in New Issue