shader codegen and compilation
This commit is contained in:
parent
531c86a899
commit
84f6eb4583
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
src/scratch.c
|
||||
build/*
|
||||
*sublime*
|
||||
*ctm*
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
// raddbg 0.9.17 project file
|
||||
|
||||
recent_file: path: "src/render/d3d12/render_d3d12.c"
|
||||
recent_file: path: "src/os/win32/os_gfx_win32.c"
|
||||
recent_file: path: "d:/os/obj/amd64fre/minkernel/crts/ucrt/src/appcrt/string/mt/objfre/amd64/minkernel/crts/ucrt/src/appcrt/string/amd64/strlen.asm"
|
||||
recent_file: path: "src/main.c"
|
||||
recent_file: path: "src/os/win32/os_gfx_win32.c"
|
||||
target:
|
||||
{
|
||||
executable: "build/program.exe"
|
||||
|
||||
@ -9,7 +9,7 @@ pushd .\build
|
||||
|
||||
ctime -begin timeBuild.ctm
|
||||
|
||||
cl /Zi /nologo /wd5287 ../src/metagen/codegen.c
|
||||
cl /Zi /nologo /wd5287 ..\\src\\metagen\\metagen_main.c
|
||||
|
||||
set LastError=%ERRORLEVEL%
|
||||
ctime -end timeBuild.ctm %LastError%
|
||||
@ -22,12 +22,7 @@ IF NOT %LastError%==0 GOTO :end
|
||||
ctime -begin timeBuild.ctm
|
||||
|
||||
pushd src
|
||||
pushd gen_test
|
||||
..\..\build\codegen.exe ./
|
||||
popd
|
||||
pushd os
|
||||
..\..\build\codegen.exe ./
|
||||
popd
|
||||
..\build\metagen_main.exe
|
||||
popd
|
||||
|
||||
echo Codegen time:
|
||||
|
||||
@ -11,13 +11,16 @@
|
||||
#define COMPILER_MSVC 1
|
||||
#endif
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# pragma section(".rdata$", read)
|
||||
# define read_only __declspec(allocate(".rdata$"))
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Asserts
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# define Trap() __debugbreak()
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
# define Trap() __builtin_trap()
|
||||
#else
|
||||
# error Unknown trap intrinsic for this compiler.
|
||||
#endif
|
||||
|
||||
@ -10,9 +10,24 @@ typedef union Vec3F32
|
||||
{
|
||||
F32 x;
|
||||
F32 y;
|
||||
F32 z;
|
||||
};
|
||||
F32 v[3];
|
||||
}
|
||||
Vec3F32;
|
||||
|
||||
typedef union Vec4F32
|
||||
{
|
||||
struct
|
||||
{
|
||||
F32 x;
|
||||
F32 y;
|
||||
F32 z;
|
||||
F32 w;
|
||||
};
|
||||
F32 v[4];
|
||||
}
|
||||
Vec4F32;
|
||||
|
||||
|
||||
#endif /* BASE_MATH_H */
|
||||
2
src/gen_test/generated/gen_test.meta.c
Normal file
2
src/gen_test/generated/gen_test.meta.c
Normal file
@ -0,0 +1,2 @@
|
||||
//- GENERATED CODE
|
||||
|
||||
6
src/gen_test/generated/gen_test.meta.h
Normal file
6
src/gen_test/generated/gen_test.meta.h
Normal file
@ -0,0 +1,6 @@
|
||||
//- GENERATED CODE
|
||||
|
||||
#ifndef GEN_TEST_META_H
|
||||
#define GEN_TEST_META_H
|
||||
|
||||
#endif // GEN_TEST_META_H
|
||||
@ -1,8 +0,0 @@
|
||||
char * test_value_table[4] =
|
||||
{
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
};
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
typedef enum TestEnum
|
||||
{
|
||||
TestEnum_A,
|
||||
TestEnum_B,
|
||||
TestEnum_C,
|
||||
TestEnum_D,
|
||||
TestEnum_COUNT
|
||||
}
|
||||
TestEnum;
|
||||
|
||||
extern char * test_value_table[4];
|
||||
|
||||
@ -59,7 +59,7 @@ entry_point()
|
||||
for(U64 i = 0; i < os_events_received_on_frame(); i += 1)
|
||||
{
|
||||
OS_Event *event = &os_events.list[i];
|
||||
if(event->kind != OS_EventKind_Null)
|
||||
if(event->kind != OS_EventKind_Null && event->kind != OS_EventKind_MouseMove)
|
||||
{
|
||||
os_console_log_fmt("%s ", os_key_display_string[event->key]);
|
||||
if(event->kind == OS_EventKind_Release)
|
||||
|
||||
4
src/main.h
Normal file
4
src/main.h
Normal file
@ -0,0 +1,4 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#endif // MAIN_H
|
||||
1228
src/mdesk/mdesk.c
Normal file
1228
src/mdesk/mdesk.c
Normal file
File diff suppressed because it is too large
Load Diff
346
src/mdesk/mdesk.h
Normal file
346
src/mdesk/mdesk.h
Normal file
@ -0,0 +1,346 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef MDESK_H
|
||||
#define MDESK_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Messages
|
||||
|
||||
typedef enum MD_MsgKind
|
||||
{
|
||||
MD_MsgKind_Null,
|
||||
MD_MsgKind_Note,
|
||||
MD_MsgKind_Warning,
|
||||
MD_MsgKind_Error,
|
||||
MD_MsgKind_FatalError,
|
||||
}
|
||||
MD_MsgKind;
|
||||
|
||||
typedef struct MD_Msg MD_Msg;
|
||||
struct MD_Msg
|
||||
{
|
||||
MD_Msg *next;
|
||||
struct MD_Node *node;
|
||||
MD_MsgKind kind;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct MD_MsgList MD_MsgList;
|
||||
struct MD_MsgList
|
||||
{
|
||||
MD_Msg *first;
|
||||
MD_Msg *last;
|
||||
U64 count;
|
||||
MD_MsgKind worst_message_kind;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Token Types
|
||||
|
||||
typedef U32 MD_TokenFlags;
|
||||
enum
|
||||
{
|
||||
// rjf: base kind info
|
||||
MD_TokenFlag_Identifier = (1<<0),
|
||||
MD_TokenFlag_Numeric = (1<<1),
|
||||
MD_TokenFlag_StringLiteral = (1<<2),
|
||||
MD_TokenFlag_Symbol = (1<<3),
|
||||
MD_TokenFlag_Reserved = (1<<4),
|
||||
MD_TokenFlag_Comment = (1<<5),
|
||||
MD_TokenFlag_Whitespace = (1<<6),
|
||||
MD_TokenFlag_Newline = (1<<7),
|
||||
|
||||
// rjf: decoration info
|
||||
MD_TokenFlag_StringSingleQuote = (1<<8),
|
||||
MD_TokenFlag_StringDoubleQuote = (1<<9),
|
||||
MD_TokenFlag_StringTick = (1<<10),
|
||||
MD_TokenFlag_StringTriplet = (1<<11),
|
||||
|
||||
// rjf: error info
|
||||
MD_TokenFlag_BrokenComment = (1<<12),
|
||||
MD_TokenFlag_BrokenStringLiteral = (1<<13),
|
||||
MD_TokenFlag_BadCharacter = (1<<14),
|
||||
};
|
||||
|
||||
typedef U32 MD_TokenGroups;
|
||||
enum
|
||||
{
|
||||
MD_TokenGroup_Comment = MD_TokenFlag_Comment,
|
||||
MD_TokenGroup_Whitespace = (MD_TokenFlag_Whitespace|
|
||||
MD_TokenFlag_Newline),
|
||||
MD_TokenGroup_Irregular = (MD_TokenGroup_Comment|
|
||||
MD_TokenGroup_Whitespace),
|
||||
MD_TokenGroup_Regular = ~MD_TokenGroup_Irregular,
|
||||
MD_TokenGroup_Label = (MD_TokenFlag_Identifier|
|
||||
MD_TokenFlag_Numeric|
|
||||
MD_TokenFlag_StringLiteral|
|
||||
MD_TokenFlag_Symbol),
|
||||
MD_TokenGroup_Error = (MD_TokenFlag_BrokenComment|
|
||||
MD_TokenFlag_BrokenStringLiteral|
|
||||
MD_TokenFlag_BadCharacter),
|
||||
};
|
||||
|
||||
typedef struct MD_Token MD_Token;
|
||||
struct MD_Token
|
||||
{
|
||||
Rng1U64 range;
|
||||
MD_TokenFlags flags;
|
||||
};
|
||||
|
||||
typedef struct MD_TokenChunkNode MD_TokenChunkNode;
|
||||
struct MD_TokenChunkNode
|
||||
{
|
||||
MD_TokenChunkNode *next;
|
||||
MD_Token *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct MD_TokenChunkList MD_TokenChunkList;
|
||||
struct MD_TokenChunkList
|
||||
{
|
||||
MD_TokenChunkNode *first;
|
||||
MD_TokenChunkNode *last;
|
||||
U64 chunk_count;
|
||||
U64 total_token_count;
|
||||
};
|
||||
|
||||
typedef struct MD_TokenArray MD_TokenArray;
|
||||
struct MD_TokenArray
|
||||
{
|
||||
MD_Token *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Types
|
||||
|
||||
typedef enum MD_NodeKind
|
||||
{
|
||||
MD_NodeKind_Nil,
|
||||
MD_NodeKind_File,
|
||||
MD_NodeKind_ErrorMarker,
|
||||
MD_NodeKind_Main,
|
||||
MD_NodeKind_Tag,
|
||||
MD_NodeKind_List,
|
||||
MD_NodeKind_Reference,
|
||||
MD_NodeKind_COUNT
|
||||
}
|
||||
MD_NodeKind;
|
||||
|
||||
typedef U32 MD_NodeFlags;
|
||||
enum
|
||||
{
|
||||
MD_NodeFlag_MaskSetDelimiters = (0x3F<<0),
|
||||
MD_NodeFlag_HasParenLeft = (1<<0),
|
||||
MD_NodeFlag_HasParenRight = (1<<1),
|
||||
MD_NodeFlag_HasBracketLeft = (1<<2),
|
||||
MD_NodeFlag_HasBracketRight = (1<<3),
|
||||
MD_NodeFlag_HasBraceLeft = (1<<4),
|
||||
MD_NodeFlag_HasBraceRight = (1<<5),
|
||||
|
||||
MD_NodeFlag_MaskSeparators = (0xF<<6),
|
||||
MD_NodeFlag_IsBeforeSemicolon = (1<<6),
|
||||
MD_NodeFlag_IsAfterSemicolon = (1<<7),
|
||||
MD_NodeFlag_IsBeforeComma = (1<<8),
|
||||
MD_NodeFlag_IsAfterComma = (1<<9),
|
||||
|
||||
MD_NodeFlag_MaskStringDelimiters = (0xF<<10),
|
||||
MD_NodeFlag_StringSingleQuote = (1<<10),
|
||||
MD_NodeFlag_StringDoubleQuote = (1<<11),
|
||||
MD_NodeFlag_StringTick = (1<<12),
|
||||
MD_NodeFlag_StringTriplet = (1<<13),
|
||||
|
||||
MD_NodeFlag_MaskLabelKind = (0xF<<14),
|
||||
MD_NodeFlag_Numeric = (1<<14),
|
||||
MD_NodeFlag_Identifier = (1<<15),
|
||||
MD_NodeFlag_StringLiteral = (1<<16),
|
||||
MD_NodeFlag_Symbol = (1<<17),
|
||||
};
|
||||
#define MD_NodeFlag_AfterFromBefore(f) ((f) << 1)
|
||||
|
||||
typedef struct MD_Node MD_Node;
|
||||
struct MD_Node
|
||||
{
|
||||
// rjf: tree links
|
||||
MD_Node *next;
|
||||
MD_Node *prev;
|
||||
MD_Node *parent;
|
||||
MD_Node *first;
|
||||
MD_Node *last;
|
||||
|
||||
// rjf: tag links
|
||||
MD_Node *first_tag;
|
||||
MD_Node *last_tag;
|
||||
|
||||
// rjf: node info
|
||||
MD_NodeKind kind;
|
||||
MD_NodeFlags flags;
|
||||
String8 string;
|
||||
String8 raw_string;
|
||||
|
||||
// rjf: source code info
|
||||
U64 src_offset;
|
||||
|
||||
// rjf: user-controlled generation number
|
||||
//
|
||||
// (unused by mdesk layer, but can be used by usage code to use MD_Node trees
|
||||
// in a "retained mode" way, where stable generational handles can be formed
|
||||
// to nodes)
|
||||
U64 user_gen;
|
||||
|
||||
// rjf: extra padding to 128 bytes
|
||||
U64 _unused_[2];
|
||||
};
|
||||
|
||||
typedef struct MD_NodeRec MD_NodeRec;
|
||||
struct MD_NodeRec
|
||||
{
|
||||
MD_Node *next;
|
||||
S32 push_count;
|
||||
S32 pop_count;
|
||||
};
|
||||
|
||||
typedef struct MD_NodePtrNode MD_NodePtrNode;
|
||||
struct MD_NodePtrNode
|
||||
{
|
||||
MD_NodePtrNode *next;
|
||||
MD_Node *v;
|
||||
};
|
||||
|
||||
typedef struct MD_NodePtrList MD_NodePtrList;
|
||||
struct MD_NodePtrList
|
||||
{
|
||||
MD_NodePtrNode *first;
|
||||
MD_NodePtrNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text -> Tokens Types
|
||||
|
||||
typedef struct MD_TokenizeResult MD_TokenizeResult;
|
||||
struct MD_TokenizeResult
|
||||
{
|
||||
MD_TokenArray tokens;
|
||||
MD_MsgList msgs;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tokens -> Tree Types
|
||||
|
||||
typedef struct MD_ParseResult MD_ParseResult;
|
||||
struct MD_ParseResult
|
||||
{
|
||||
MD_Node *root;
|
||||
MD_MsgList msgs;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global read_only MD_Node md_nil_node =
|
||||
{
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
&md_nil_node,
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Type Functions
|
||||
|
||||
internal void md_msg_list_push(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, String8 string);
|
||||
internal void md_msg_list_pushf(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, char *fmt, ...);
|
||||
internal void md_msg_list_concat_in_place(MD_MsgList *dst, MD_MsgList *to_push);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Token Type Functions
|
||||
|
||||
internal MD_Token md_token_make(Rng1U64 range, MD_TokenFlags flags);
|
||||
internal B32 md_token_match(MD_Token a, MD_Token b);
|
||||
internal String8List md_string_list_from_token_flags(Arena *arena, MD_TokenFlags flags);
|
||||
internal void md_token_chunk_list_push(Arena *arena, MD_TokenChunkList *list, U64 cap, MD_Token token);
|
||||
internal MD_TokenArray md_token_array_from_chunk_list(Arena *arena, MD_TokenChunkList *chunks);
|
||||
internal String8 md_content_string_from_token_flags_str8(MD_TokenFlags flags, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Type Functions
|
||||
|
||||
//- rjf: flag conversions
|
||||
internal MD_NodeFlags md_node_flags_from_token_flags(MD_TokenFlags flags);
|
||||
|
||||
//- rjf: nil
|
||||
internal B32 md_node_is_nil(MD_Node *node);
|
||||
|
||||
//- rjf: iteration
|
||||
#define MD_EachNode(it, first) (MD_Node *it = first; !md_node_is_nil(it); it = it->next)
|
||||
internal MD_NodeRec md_node_rec_depth_first(MD_Node *node, MD_Node *subtree_root, U64 child_off, U64 sib_off);
|
||||
#define md_node_rec_depth_first_pre(node, subtree_root) md_node_rec_depth_first((node), (subtree_root), OffsetOf(MD_Node, first), OffsetOf(MD_Node, next))
|
||||
#define md_node_rec_depth_first_pre_rev(node, subtree_root) md_node_rec_depth_first((node), (subtree_root), OffsetOf(MD_Node, last), OffsetOf(MD_Node, prev))
|
||||
|
||||
//- rjf: tree building
|
||||
internal MD_Node *md_push_node(Arena *arena, MD_NodeKind kind, MD_NodeFlags flags, String8 string, String8 raw_string, U64 src_offset);
|
||||
internal void md_node_insert_child(MD_Node *parent, MD_Node *prev_child, MD_Node *node);
|
||||
internal void md_node_insert_tag(MD_Node *parent, MD_Node *prev_child, MD_Node *node);
|
||||
internal void md_node_push_child(MD_Node *parent, MD_Node *node);
|
||||
internal void md_node_push_tag(MD_Node *parent, MD_Node *node);
|
||||
internal void md_unhook(MD_Node *node);
|
||||
|
||||
//- rjf: tree introspection
|
||||
internal MD_Node * md_node_from_chain_string(MD_Node *first, MD_Node *opl, String8 string, StringMatchFlags flags);
|
||||
internal MD_Node * md_node_from_chain_index(MD_Node *first, MD_Node *opl, U64 index);
|
||||
internal MD_Node * md_node_from_chain_flags(MD_Node *first, MD_Node *opl, MD_NodeFlags flags);
|
||||
internal U64 md_index_from_node(MD_Node *node);
|
||||
internal MD_Node * md_root_from_node(MD_Node *node);
|
||||
internal MD_Node * md_child_from_string(MD_Node *node, String8 child_string, StringMatchFlags flags);
|
||||
internal MD_Node * md_tag_from_string(MD_Node *node, String8 tag_string, StringMatchFlags flags);
|
||||
internal MD_Node * md_child_from_index(MD_Node *node, U64 index);
|
||||
internal MD_Node * md_tag_from_index(MD_Node *node, U64 index);
|
||||
internal MD_Node * md_tag_arg_from_index(MD_Node *node, String8 tag_string, StringMatchFlags flags, U64 index);
|
||||
internal MD_Node * md_tag_arg_from_string(MD_Node *node, String8 tag_string, StringMatchFlags tag_str_flags, String8 arg_string, StringMatchFlags arg_str_flags);
|
||||
internal B32 md_node_has_child(MD_Node *node, String8 string, StringMatchFlags flags);
|
||||
internal B32 md_node_has_tag(MD_Node *node, String8 string, StringMatchFlags flags);
|
||||
internal U64 md_child_count_from_node(MD_Node *node);
|
||||
internal U64 md_tag_count_from_node(MD_Node *node);
|
||||
internal String8 md_string_from_children(Arena *arena, MD_Node *root);
|
||||
|
||||
//- rjf: tree comparison
|
||||
internal B32 md_tree_match(MD_Node *a, MD_Node *b, StringMatchFlags flags);
|
||||
internal B32 md_node_match(MD_Node *a, MD_Node *b, StringMatchFlags flags);
|
||||
|
||||
//- rjf: tree duplication
|
||||
internal MD_Node *md_tree_copy(Arena *arena, MD_Node *src_root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text -> Tokens Functions
|
||||
|
||||
internal MD_TokenizeResult md_tokenize_from_text(Arena *arena, String8 text);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tokens -> Tree Functions
|
||||
|
||||
internal MD_ParseResult md_parse_from_text_tokens(Arena *arena, String8 filename, String8 text, MD_TokenArray tokens);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bundled Text -> Tree Functions
|
||||
|
||||
internal MD_ParseResult md_parse_from_text(Arena *arena, String8 filename, String8 text);
|
||||
#define md_tree_from_string(arena, string) (md_parse_from_text((arena), str8_zero(), (string)).root)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tree -> Text Functions
|
||||
|
||||
internal String8List md_debug_string_list_from_tree(Arena *arena, MD_Node *root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Pointer List Functions
|
||||
|
||||
internal void md_node_ptr_list_push(Arena *arena, MD_NodePtrList *list, MD_Node *node);
|
||||
internal void md_node_ptr_list_push_front(Arena *arena, MD_NodePtrList *list, MD_Node *node);
|
||||
|
||||
#endif // MDESK_H
|
||||
@ -1,148 +0,0 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "metadesk_base/md.h"
|
||||
#include "metadesk_base/md.c"
|
||||
|
||||
#include "codegen.h"
|
||||
|
||||
#include "codegen_table.h"
|
||||
#include "codegen_table.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
static CG_FilePair
|
||||
CG_FilePairFromNode(MD_Node *node)
|
||||
{
|
||||
CG_FilePair result = {0};
|
||||
MD_CodeLoc loc = MD_CodeLocFromNode(node);
|
||||
MD_String8 filename = loc.filename;
|
||||
MD_b32 found = 0;
|
||||
for(int i = 0; i < cg_file_pair_count; i += 1)
|
||||
{
|
||||
if(MD_S8Match(filename, cg_file_pairs[i].src_filename, 0))
|
||||
{
|
||||
result = cg_file_pairs[i];
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(found == 0)
|
||||
{
|
||||
MD_String8 folder = MD_PathChopLastSlash(filename);
|
||||
MD_String8 layer_name = MD_PathChopLastPeriod(MD_PathSkipLastSlash(loc.filename));
|
||||
MD_String8 gen_folder = MD_S8Fmt(cg_arena, "%.*s/generated", MD_S8VArg(folder));
|
||||
MD_String8 h_filename = MD_S8Fmt(cg_arena, "%.*s/%.*s.meta.h", MD_S8VArg(gen_folder), MD_S8VArg(layer_name));
|
||||
MD_String8 c_filename = MD_S8Fmt(cg_arena, "%.*s/%.*s.meta.c", MD_S8VArg(gen_folder), MD_S8VArg(layer_name));
|
||||
result.src_filename = filename;
|
||||
result.h = fopen((char *)h_filename.str, "w");
|
||||
result.c = fopen((char *)c_filename.str, "w");
|
||||
cg_file_pairs[cg_file_pair_count] = result;
|
||||
cg_file_pair_count += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
CG_CloseAllFiles(void)
|
||||
{
|
||||
for(int i = 0; i < cg_file_pair_count; i += 1)
|
||||
{
|
||||
fclose(cg_file_pairs[i].h);
|
||||
fclose(cg_file_pairs[i].c);
|
||||
}
|
||||
}
|
||||
|
||||
static MD_String8
|
||||
CG_EscapedFromString(MD_Arena *arena, MD_String8 string)
|
||||
{
|
||||
MD_ArenaTemp scratch = MD_GetScratch(&arena, 1);
|
||||
MD_String8List strs = {0};
|
||||
MD_b32 escaped = 0;
|
||||
MD_u64 start = 0;
|
||||
for(MD_u64 idx = 0; idx <= string.size; idx += 1)
|
||||
{
|
||||
if(idx < string.size && escaped)
|
||||
{
|
||||
escaped = 0;
|
||||
start = idx+1;
|
||||
MD_u8 replace_char = 0;
|
||||
switch(string.str[idx])
|
||||
{
|
||||
default: break;
|
||||
case 'a': replace_char = 0x07; break;
|
||||
case 'b': replace_char = 0x08; break;
|
||||
case 'e': replace_char = 0x1b; break;
|
||||
case 'f': replace_char = 0x0c; break;
|
||||
case 'n': replace_char = 0x0a; break;
|
||||
case 'r': replace_char = 0x0d; break;
|
||||
case 't': replace_char = 0x09; break;
|
||||
case 'v': replace_char = 0x0b; break;
|
||||
case '\\': replace_char = 0x5c; break;
|
||||
case '\'': replace_char = 0x27; break;
|
||||
case '\"': replace_char = 0x22; break;
|
||||
case '\?': replace_char = 0x3f; break;
|
||||
}
|
||||
if(replace_char)
|
||||
{
|
||||
MD_String8 string = MD_S8Copy(scratch.arena, MD_S8(&replace_char, 1));
|
||||
MD_S8ListPush(scratch.arena, &strs, string);
|
||||
}
|
||||
}
|
||||
else if(idx == string.size || string.str[idx] == '\\')
|
||||
{
|
||||
escaped = (string.str[idx] == '\\');
|
||||
MD_String8 part = MD_S8Substring(string, start, idx);
|
||||
MD_S8ListPush(scratch.arena, &strs, part);
|
||||
start = idx;
|
||||
}
|
||||
}
|
||||
MD_String8 result = MD_S8ListJoin(arena, strs, 0);
|
||||
MD_ReleaseScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entry Point
|
||||
|
||||
int main(int argument_count, char **arguments)
|
||||
{
|
||||
cg_arena = MD_ArenaAlloc();
|
||||
|
||||
//- rjf: parse command line
|
||||
MD_String8List options = MD_StringListFromArgCV(cg_arena, argument_count, arguments);
|
||||
MD_CmdLine cmdln = MD_MakeCmdLineFromOptions(cg_arena, options);
|
||||
|
||||
//- rjf: parse all files
|
||||
MD_Node *file_list = MD_MakeList(cg_arena);
|
||||
for(MD_String8Node *n = cmdln.inputs.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_String8 code_dir = n->string;
|
||||
printf("searching %.*s for metacode...\n", MD_S8VArg(code_dir));
|
||||
MD_FileIter it = {0};
|
||||
MD_FileIterBegin(&it, code_dir);
|
||||
for(MD_FileInfo info = {0};;)
|
||||
{
|
||||
info = MD_FileIterNext(cg_arena, &it);
|
||||
if(info.filename.size == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(!(info.flags & MD_FileFlag_Directory) &&
|
||||
MD_S8Match(MD_PathSkipLastPeriod(info.filename), MD_S8Lit("mdesk"), MD_StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
printf("parsing %.*s...\n", MD_S8VArg(info.filename));
|
||||
MD_String8 path = MD_S8Fmt(cg_arena, "%.*s/%.*s", MD_S8VArg(code_dir), MD_S8VArg(info.filename));
|
||||
MD_ParseResult parse = MD_ParseWholeFile(cg_arena, path);
|
||||
MD_PushNewReference(cg_arena, file_list, parse.node);
|
||||
}
|
||||
}
|
||||
MD_FileIterEnd(&it);
|
||||
}
|
||||
|
||||
//- rjf: send all parses to backends
|
||||
CG_TBL_Generate(file_list);
|
||||
CG_CloseAllFiles();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
#ifndef METAPROGRAM_H
|
||||
#define METAPROGRAM_H
|
||||
|
||||
typedef struct CG_FilePair CG_FilePair;
|
||||
struct CG_FilePair
|
||||
{
|
||||
MD_String8 src_filename;
|
||||
FILE *h;
|
||||
FILE *c;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
static CG_FilePair CG_FilePairFromNode(MD_Node *node);
|
||||
static void CG_CloseAllFiles(void);
|
||||
static MD_String8 CG_EscapedFromString(MD_Arena *arena, MD_String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
static MD_Arena *cg_arena = 0;
|
||||
static int cg_file_pair_count = 0;
|
||||
static CG_FilePair cg_file_pairs[4096] = {0};
|
||||
|
||||
#endif // METAPROGRAM_H
|
||||
@ -1,564 +0,0 @@
|
||||
static MD_Map cg_tbl_top_level_node_grid_map = {0};
|
||||
static MD_Map cg_tbl_top_level_table_header_map = {0};
|
||||
|
||||
static MD_Map cg_tbl_layer_map_gen = {0};
|
||||
static MD_Map cg_tbl_layer_map_gen_enum = {0};
|
||||
static MD_Map cg_tbl_layer_map_gen_data = {0};
|
||||
|
||||
static MD_String8 cg_tbl_tag__table = MD_S8LitComp("table");
|
||||
static MD_String8 cg_tbl_tag__table_gen = MD_S8LitComp("table_gen");
|
||||
static MD_String8 cg_tbl_tag__table_gen_enum = MD_S8LitComp("table_gen_enum");
|
||||
static MD_String8 cg_tbl_tag__table_gen_data = MD_S8LitComp("table_gen_data");
|
||||
|
||||
static CG_NodeArray
|
||||
CG_NodeArrayMake(MD_u64 count)
|
||||
{
|
||||
CG_NodeArray result = {0};
|
||||
result.count = count;
|
||||
result.v = MD_PushArrayZero(cg_arena, MD_Node *, result.count);
|
||||
for(MD_u64 idx = 0; idx < result.count; idx += 1)
|
||||
{
|
||||
result.v[idx] = MD_NilNode();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CG_NodeGrid
|
||||
CG_GridFromNode(MD_Node *node)
|
||||
{
|
||||
CG_NodeGrid grid = {0};
|
||||
|
||||
//- rjf: determine dimensions
|
||||
MD_u64 row_count = 0;
|
||||
MD_u64 column_count = 0;
|
||||
{
|
||||
for(MD_EachNode(row, node->first_child))
|
||||
{
|
||||
row_count += 1;
|
||||
MD_u64 cell_count_this_row = MD_ChildCountFromNode(row);
|
||||
column_count = MD_Max(cell_count_this_row, column_count);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: allocate cells / row parents
|
||||
{
|
||||
grid.cells = CG_NodeArrayMake(row_count * column_count);
|
||||
grid.row_parents = CG_NodeArrayMake(row_count);
|
||||
}
|
||||
|
||||
//- rjf: fill cells
|
||||
{
|
||||
MD_u64 row_idx = 0;
|
||||
for(MD_EachNode(row, node->first_child))
|
||||
{
|
||||
MD_u64 col_idx = 0;
|
||||
grid.row_parents.v[row_idx] = row;
|
||||
for(MD_EachNode(cell, row->first_child))
|
||||
{
|
||||
grid.cells.v[row_idx * column_count + col_idx] = cell;
|
||||
col_idx += 1;
|
||||
}
|
||||
row_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
static CG_TableHeader
|
||||
CG_TableHeaderFromTag(MD_Node *tag)
|
||||
{
|
||||
CG_TableHeader result = {0};
|
||||
result.column_count = MD_ChildCountFromNode(tag);
|
||||
result.column_descs = MD_PushArrayZero(cg_arena, CG_ColumnDesc, result.column_count);
|
||||
MD_u64 idx = 0;
|
||||
for(MD_EachNode(column_node, tag->first_child))
|
||||
{
|
||||
result.column_descs[idx].kind = CG_ColumnKind_Default;
|
||||
result.column_descs[idx].name = column_node->string;
|
||||
MD_Node *check_for_tag = MD_TagFromString(column_node, MD_S8Lit("check_for_tag"), 0);
|
||||
if(!MD_NodeIsNil(check_for_tag))
|
||||
{
|
||||
result.column_descs[idx].kind = CG_ColumnKind_CheckForTag;
|
||||
result.column_descs[idx].tag_string = check_for_tag->first_child->string;
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static MD_u64
|
||||
CG_RowChildIndexFromColumnName(CG_TableHeader *header, MD_String8 column_name)
|
||||
{
|
||||
MD_u64 result = 0;
|
||||
for(MD_u64 idx = 0; idx < header->column_count; idx += 1)
|
||||
{
|
||||
if(MD_S8Match(header->column_descs[idx].name, column_name, 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(header->column_descs[idx].kind == CG_ColumnKind_Default)
|
||||
{
|
||||
result += 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static MD_i64
|
||||
CG_TableExprEvaluate_Numeric(CG_ExpandInfo *info, MD_Expr *expr)
|
||||
{
|
||||
MD_i64 result = 0;
|
||||
CG_TableOp op = expr->op ? expr->op->op_id : CG_TableOp_Null;
|
||||
switch(op)
|
||||
{
|
||||
case CG_TableOp_Equal:
|
||||
case CG_TableOp_IsNotEqual:
|
||||
{
|
||||
MD_ArenaTemp scratch = MD_GetScratch(0, 0);
|
||||
MD_String8List left_strs = {0};
|
||||
MD_String8List right_strs = {0};
|
||||
CG_TableExprEvaluate_String(info, expr->left, &left_strs);
|
||||
CG_TableExprEvaluate_String(info, expr->right, &right_strs);
|
||||
MD_String8 left_str = MD_S8ListJoin(scratch.arena, left_strs, 0);
|
||||
MD_String8 right_str = MD_S8ListJoin(scratch.arena, right_strs, 0);
|
||||
result = MD_S8Match(left_str, right_str, 0);
|
||||
if(op == CG_TableOp_IsNotEqual)
|
||||
{
|
||||
result = !result;
|
||||
}
|
||||
MD_ReleaseScratch(scratch);
|
||||
}break;
|
||||
|
||||
case CG_TableOp_BooleanAnd:
|
||||
case CG_TableOp_BooleanOr:
|
||||
{
|
||||
MD_i64 left = CG_TableExprEvaluate_Numeric(info, expr->left);
|
||||
MD_i64 right = CG_TableExprEvaluate_Numeric(info, expr->right);
|
||||
switch(op)
|
||||
{
|
||||
case CG_TableOp_BooleanAnd: result = left && right; break;
|
||||
case CG_TableOp_BooleanOr: result = left || right; break;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
CG_TableExprEvaluate_String(CG_ExpandInfo *info, MD_Expr *expr, MD_String8List *out)
|
||||
{
|
||||
CG_TableOp op = expr->op ? expr->op->op_id : CG_TableOp_Null;
|
||||
switch(op)
|
||||
{
|
||||
default:
|
||||
case CG_TableOp_Null:
|
||||
{
|
||||
MD_S8ListPush(cg_arena, out, expr->md_node->string);
|
||||
}break;
|
||||
|
||||
case CG_TableOp_Dot:
|
||||
{
|
||||
MD_Expr *label_expr = expr->left;
|
||||
MD_Expr *column_query_expr = expr->right;
|
||||
MD_Node *label_node = label_expr->md_node;
|
||||
MD_Node *column_query_node = column_query_expr->md_node;
|
||||
MD_String8 label = label_node->string;
|
||||
MD_String8 column_query = column_query_node->string;
|
||||
MD_b32 column_query_is_by_name = column_query_node->flags & MD_NodeFlag_Identifier;
|
||||
MD_b32 column_query_is_by_index = column_query_node->flags & MD_NodeFlag_Numeric;
|
||||
|
||||
// rjf: find which expansion this label refers to, grab its iterator
|
||||
CG_ExpandIter *iter = 0;
|
||||
for(CG_ExpandIter *it = info->first_expand_iter; it != 0; it = it->next)
|
||||
{
|
||||
if(MD_S8Match(it->label, label, 0))
|
||||
{
|
||||
iter = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: error on invalid label
|
||||
if(iter == 0)
|
||||
{
|
||||
MD_PrintMessageFmt(stderr, MD_CodeLocFromNode(label_node), MD_MessageKind_Error, "Expansion label \"%S\" was not found as referring to a valid @expand tag.", label);
|
||||
}
|
||||
|
||||
// rjf: generate strings from iterator's table
|
||||
if(iter != 0)
|
||||
{
|
||||
CG_NodeGrid *grid = iter->grid;
|
||||
CG_TableHeader *header = iter->header;
|
||||
MD_Node *row = grid->row_parents.v[iter->idx];
|
||||
|
||||
// rjf: grab the cell string given the row & column_query
|
||||
MD_String8 cell_string = {0};
|
||||
{
|
||||
// NOTE(rjf): by-name index (look into table header)
|
||||
if(column_query_is_by_name && header != 0)
|
||||
{
|
||||
MD_u64 column_idx = 0;
|
||||
CG_ColumnDesc *column = 0;
|
||||
for(MD_u64 col_idx = 0; col_idx < header->column_count; col_idx += 1)
|
||||
{
|
||||
if(MD_S8Match(header->column_descs[col_idx].name, column_query, 0))
|
||||
{
|
||||
column = &header->column_descs[col_idx];
|
||||
column_idx = col_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MD_u64 row_child_idx = CG_RowChildIndexFromColumnName(header, column_query);
|
||||
|
||||
// rjf: error on invalid column
|
||||
if(column == 0)
|
||||
{
|
||||
MD_PrintMessageFmt(stderr, MD_CodeLocFromNode(column_query_node), MD_MessageKind_Error, "Column query \"%S\" did not map to a valid column for expansion label \"%S\".", column_query, label);
|
||||
}
|
||||
|
||||
if(column != 0)
|
||||
{
|
||||
switch(column->kind)
|
||||
{
|
||||
default:
|
||||
case CG_ColumnKind_Default:
|
||||
{
|
||||
MD_Node *cell_node = MD_ChildFromIndex(row, row_child_idx);
|
||||
cell_string = cell_node->string;
|
||||
if(MD_S8Match(cell_node->raw_string, MD_S8Lit("/"), 0))
|
||||
{
|
||||
cell_string = MD_S8Lit("");
|
||||
}
|
||||
}break;
|
||||
|
||||
case CG_ColumnKind_CheckForTag:
|
||||
{
|
||||
MD_b32 has_tag = MD_NodeHasTag(row, column->tag_string, 0);
|
||||
cell_string = has_tag ? MD_S8Lit("1") : MD_S8Lit("0");
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE(rjf): by-index (grab nth child of row)
|
||||
else if(column_query_is_by_index)
|
||||
{
|
||||
MD_i64 index = MD_CStyleIntFromString(column_query);
|
||||
cell_string = MD_ChildFromIndex(row, index)->string;
|
||||
}
|
||||
}
|
||||
|
||||
MD_S8ListPush(cg_arena, out, cell_string);
|
||||
}
|
||||
|
||||
}break;
|
||||
|
||||
case CG_TableOp_Bump:
|
||||
{
|
||||
MD_u64 dst = MD_CStyleIntFromString(expr->unary_operand->md_node->string);
|
||||
MD_u64 src = out->total_size;
|
||||
MD_u64 spaces_to_print = dst - src;
|
||||
if(dst > src)
|
||||
{
|
||||
for(MD_u64 space_idx = 0; space_idx < spaces_to_print; space_idx += 1)
|
||||
{
|
||||
MD_S8ListPush(cg_arena, out, MD_S8Lit(" "));
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
case CG_TableOp_CheckIfTrue:
|
||||
{
|
||||
MD_i64 check_val = CG_TableExprEvaluate_Numeric(info, expr->left);
|
||||
if(check_val)
|
||||
{
|
||||
CG_TableExprEvaluate_String(info, expr->right, out);
|
||||
}
|
||||
}break;
|
||||
|
||||
case CG_TableOp_Concat:
|
||||
{
|
||||
CG_TableExprEvaluate_String(info, expr->left, out);
|
||||
CG_TableExprEvaluate_String(info, expr->right, out);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CG_LoopExpansionDimension(CG_ExpandIter *it, CG_ExpandInfo *info, MD_String8List *out)
|
||||
{
|
||||
if(it->next)
|
||||
{
|
||||
for(MD_u64 idx = 0; idx < it->count; idx += 1)
|
||||
{
|
||||
it->idx = idx;
|
||||
CG_LoopExpansionDimension(it->next, info, out);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(MD_u64 idx = 0; idx < it->count; idx += 1)
|
||||
{
|
||||
it->idx = idx;
|
||||
MD_String8List expansion_strs = {0};
|
||||
MD_u64 start_idx = 0;
|
||||
for(MD_u64 char_idx = 0; char_idx <= info->strexpr.size; char_idx += 1)
|
||||
{
|
||||
MD_b32 is_expr_marker = info->strexpr.str[char_idx] == '$';
|
||||
|
||||
// rjf: push regular string contents
|
||||
if(char_idx == info->strexpr.size || is_expr_marker)
|
||||
{
|
||||
MD_String8 normal_string_chunk = MD_S8Substring(info->strexpr, start_idx, char_idx);
|
||||
MD_String8 escaped = CG_EscapedFromString(cg_arena, normal_string_chunk);
|
||||
MD_S8ListPush(cg_arena, &expansion_strs, escaped);
|
||||
}
|
||||
|
||||
// rjf: handle expansion
|
||||
if(is_expr_marker)
|
||||
{
|
||||
MD_String8 expr_string = MD_S8Skip(info->strexpr, char_idx+1);
|
||||
{
|
||||
MD_i64 paren_nest = 0;
|
||||
for(MD_u64 expr_str_char_idx = 0; expr_str_char_idx < expr_string.size; expr_str_char_idx += 1)
|
||||
{
|
||||
if(expr_string.str[expr_str_char_idx] == '(')
|
||||
{
|
||||
paren_nest += 1;
|
||||
}
|
||||
else if(expr_string.str[expr_str_char_idx] == ')')
|
||||
{
|
||||
paren_nest -= 1;
|
||||
if(paren_nest == 0)
|
||||
{
|
||||
expr_string.size = expr_str_char_idx+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MD_ParseResult parse = MD_ParseOneNode(cg_arena, expr_string, 0);
|
||||
MD_Node *node = parse.node;
|
||||
MD_ExprParseResult expr_parse = MD_ExprParse(cg_arena, &info->expr_op_table, node->first_child, MD_NilNode());
|
||||
MD_Expr *expr = expr_parse.expr;
|
||||
CG_TableExprEvaluate_String(info, expr, &expansion_strs);
|
||||
MD_String8 parsed_string = MD_S8Substring(info->strexpr, char_idx+1, char_idx+1+parse.string_advance);
|
||||
parsed_string = MD_S8ChopWhitespace(parsed_string);
|
||||
start_idx = char_idx+1+parsed_string.size;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: push expansion string to output list
|
||||
MD_String8 expansion_str = MD_S8ListJoin(cg_arena, expansion_strs, 0);
|
||||
MD_S8ListPush(cg_arena, out, expansion_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static MD_String8List
|
||||
CG_GenStringListFromNode(MD_ExprOprTable expr_op_table, MD_Node *gen)
|
||||
{
|
||||
MD_String8List result = {0};
|
||||
MD_ArenaTemp scratch = MD_GetScratch(0, 0);
|
||||
|
||||
for(MD_EachNode(strexpr, gen->first_child))
|
||||
{
|
||||
//- rjf: build expansion iterator list
|
||||
CG_ExpandIter *first_iter = 0;
|
||||
CG_ExpandIter *last_iter = 0;
|
||||
{
|
||||
for(MD_EachNode(tag, strexpr->first_tag))
|
||||
{
|
||||
if(MD_S8Match(tag->string, MD_S8Lit("expand"), 0))
|
||||
{
|
||||
MD_Node *table_name_node = MD_ChildFromIndex(tag, 0);
|
||||
MD_Node *label_node = MD_ChildFromIndex(tag, 1);
|
||||
MD_String8 table_name = table_name_node->string;
|
||||
MD_String8 label = label_node->string;
|
||||
|
||||
// rjf: grab the table associated with table_name
|
||||
CG_NodeGrid *grid = 0;
|
||||
{
|
||||
MD_MapSlot *slot = MD_MapLookup(&cg_tbl_top_level_node_grid_map, MD_MapKeyStr(table_name));
|
||||
if(slot != 0)
|
||||
{
|
||||
grid = slot->val;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: grab the table header associated with table_name
|
||||
CG_TableHeader *header = 0;
|
||||
{
|
||||
MD_MapSlot *slot = MD_MapLookup(&cg_tbl_top_level_table_header_map, MD_MapKeyStr(table_name));
|
||||
if(slot != 0)
|
||||
{
|
||||
header = slot->val;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: make iterator node if we got a grid
|
||||
if(grid != 0)
|
||||
{
|
||||
CG_ExpandIter *iter = MD_PushArrayZero(scratch.arena, CG_ExpandIter, 1);
|
||||
MD_QueuePush(first_iter, last_iter, iter);
|
||||
iter->grid = grid;
|
||||
iter->header = header;
|
||||
iter->label = label;
|
||||
iter->count = grid->row_parents.count;
|
||||
}
|
||||
|
||||
// rjf: print out an error if grid is 0
|
||||
if(grid == 0)
|
||||
{
|
||||
MD_PrintMessageFmt(stderr, MD_CodeLocFromNode(tag), MD_MessageKind_Error, "Table \"%S\" was not found.", table_name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: generate string list for this strexpr & push to result
|
||||
if(first_iter != 0)
|
||||
{
|
||||
CG_ExpandInfo info = {0};
|
||||
{
|
||||
info.strexpr = strexpr->string;
|
||||
info.first_expand_iter = first_iter;
|
||||
info.expr_op_table = expr_op_table;
|
||||
}
|
||||
CG_LoopExpansionDimension(first_iter, &info, &result);
|
||||
}
|
||||
//- rjf: generate non-expansion strings
|
||||
else
|
||||
{
|
||||
MD_String8 escaped = CG_EscapedFromString(cg_arena, strexpr->string);
|
||||
MD_S8ListPush(cg_arena, &result, escaped);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MD_ReleaseScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
CG_TBL_Generate(MD_Node *file_list)
|
||||
{
|
||||
//- rjf: initialize all maps
|
||||
cg_tbl_top_level_node_grid_map = MD_MapMake(cg_arena);
|
||||
cg_tbl_top_level_table_header_map = MD_MapMake(cg_arena);
|
||||
cg_tbl_layer_map_gen = MD_MapMake(cg_arena);
|
||||
cg_tbl_layer_map_gen_enum = MD_MapMake(cg_arena);
|
||||
cg_tbl_layer_map_gen_data = MD_MapMake(cg_arena);
|
||||
|
||||
//- rjf: build table expression operator table
|
||||
MD_ExprOprTable table_expr_op_table = {0};
|
||||
{
|
||||
MD_ExprOprList ops_list = {0};
|
||||
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 10, MD_S8Lit("."), CG_TableOp_Dot, 0);
|
||||
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Prefix, 9, MD_S8Lit("=>"), CG_TableOp_Bump, 0);
|
||||
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 6, MD_S8Lit("??"), CG_TableOp_CheckIfTrue, 0);
|
||||
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 7, MD_S8Lit(".."), CG_TableOp_Concat, 0);
|
||||
|
||||
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 8, MD_S8Lit("=="), CG_TableOp_Equal, 0);
|
||||
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 8, MD_S8Lit("!="), CG_TableOp_IsNotEqual, 0);
|
||||
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 5, MD_S8Lit("&&"), CG_TableOp_BooleanAnd, 0);
|
||||
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 4, MD_S8Lit("||"), CG_TableOp_BooleanOr, 0);
|
||||
table_expr_op_table = MD_ExprBakeOprTableFromList(cg_arena, &ops_list);
|
||||
}
|
||||
|
||||
//- rjf: gather phase
|
||||
for(MD_EachNode(file_ref, file_list->first_child))
|
||||
{
|
||||
MD_Node *file = MD_ResolveNodeFromReference(file_ref);
|
||||
MD_String8 layer_name = file->string;
|
||||
MD_MapKey layer_key = MD_MapKeyStr(layer_name);
|
||||
for(MD_EachNode(node, file->first_child))
|
||||
{
|
||||
MD_Node *table_tag = MD_TagFromString(node, cg_tbl_tag__table, 0);
|
||||
if(!MD_NodeIsNil(table_tag))
|
||||
{
|
||||
CG_NodeGrid *grid = MD_PushArrayZero(cg_arena, CG_NodeGrid, 1);
|
||||
*grid = CG_GridFromNode(node);
|
||||
MD_MapOverwrite(cg_arena, &cg_tbl_top_level_node_grid_map, MD_MapKeyStr(node->string), grid);
|
||||
CG_TableHeader *header = MD_PushArrayZero(cg_arena, CG_TableHeader, 1);
|
||||
*header = CG_TableHeaderFromTag(table_tag);
|
||||
MD_MapOverwrite(cg_arena, &cg_tbl_top_level_table_header_map, MD_MapKeyStr(node->string), header);
|
||||
}
|
||||
if(MD_NodeHasTag(node, cg_tbl_tag__table_gen, 0))
|
||||
{
|
||||
MD_MapInsert(cg_arena, &cg_tbl_layer_map_gen, layer_key, node);
|
||||
}
|
||||
if(MD_NodeHasTag(node, cg_tbl_tag__table_gen_enum, 0))
|
||||
{
|
||||
MD_MapInsert(cg_arena, &cg_tbl_layer_map_gen_enum, layer_key, node);
|
||||
}
|
||||
if(MD_NodeHasTag(node, cg_tbl_tag__table_gen_data, 0))
|
||||
{
|
||||
MD_MapInsert(cg_arena, &cg_tbl_layer_map_gen_data, layer_key, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: generation phase
|
||||
for(MD_EachNode(file_ref, file_list->first_child))
|
||||
{
|
||||
MD_Node *file = MD_ResolveNodeFromReference(file_ref);
|
||||
MD_String8 layer_name = file->string;
|
||||
MD_MapKey layer_key = MD_MapKeyStr(layer_name);
|
||||
|
||||
//- rjf: generate all table enums
|
||||
for(MD_MapSlot *slot = MD_MapLookup(&cg_tbl_layer_map_gen_enum, layer_key);
|
||||
slot != 0;
|
||||
slot = MD_MapScan(slot->next, layer_key))
|
||||
{
|
||||
MD_Node *gen = (MD_Node *)slot->val;
|
||||
CG_FilePair f = CG_FilePairFromNode(gen);
|
||||
fprintf(f.h, "typedef enum %.*s\n{\n", MD_S8VArg(gen->string));
|
||||
MD_String8List gen_strings = CG_GenStringListFromNode(table_expr_op_table, gen);
|
||||
MD_StringJoin join = { MD_S8Lit(""), MD_S8Lit("\n"), MD_S8Lit("") };
|
||||
MD_String8 gen_string = MD_S8ListJoin(cg_arena, gen_strings, &join);
|
||||
fprintf(f.h, "%.*s", MD_S8VArg(gen_string));
|
||||
fprintf(f.h, "\n}\n%.*s;\n\n", MD_S8VArg(gen->string));
|
||||
}
|
||||
|
||||
//- rjf: generate all data tables
|
||||
for(MD_MapSlot *slot = MD_MapLookup(&cg_tbl_layer_map_gen_data, layer_key);
|
||||
slot != 0;
|
||||
slot = MD_MapScan(slot->next, layer_key))
|
||||
{
|
||||
MD_Node *gen = (MD_Node *)slot->val;
|
||||
MD_Node *tag = MD_TagFromString(gen, cg_tbl_tag__table_gen_data, 0);
|
||||
MD_Node *data_table_type_node = tag->first_child;
|
||||
MD_String8 data_table_type = data_table_type_node->string;
|
||||
MD_String8List gen_strings = CG_GenStringListFromNode(table_expr_op_table, gen);
|
||||
MD_String8 h_decl_specifier = MD_S8Lit("extern");
|
||||
|
||||
CG_FilePair f = CG_FilePairFromNode(gen);
|
||||
fprintf(f.h, "%.*s %.*s %.*s[%" PRIu64 "];\n\n", MD_S8VArg(h_decl_specifier), MD_S8VArg(data_table_type), MD_S8VArg(gen->string), gen_strings.node_count);
|
||||
fprintf(f.c, "%.*s %.*s[%" PRIu64 "] =\n{\n", MD_S8VArg(data_table_type), MD_S8VArg(gen->string), gen_strings.node_count);
|
||||
MD_StringJoin join = { MD_S8Lit(""), MD_S8Lit("\n"), MD_S8Lit("") };
|
||||
MD_String8 gen_string = MD_S8ListJoin(cg_arena, gen_strings, &join);
|
||||
fprintf(f.c, "%.*s", MD_S8VArg(gen_string));
|
||||
fprintf(f.c, "\n};\n");
|
||||
fprintf(f.c, "\n");
|
||||
}
|
||||
|
||||
//- rjf: generate all general generations
|
||||
for(MD_MapSlot *slot = MD_MapLookup(&cg_tbl_layer_map_gen, layer_key);
|
||||
slot != 0;
|
||||
slot = MD_MapScan(slot->next, layer_key))
|
||||
{
|
||||
MD_Node *gen = (MD_Node *)slot->val;
|
||||
CG_FilePair f = CG_FilePairFromNode(gen);
|
||||
FILE *file = MD_NodeHasTag(gen, MD_S8Lit("c"), 0) ? f.c : f.h;
|
||||
MD_String8List gen_strings = CG_GenStringListFromNode(table_expr_op_table, gen);
|
||||
MD_StringJoin join = { MD_S8Lit(""), MD_S8Lit("\n"), MD_S8Lit("") };
|
||||
MD_String8 gen_string = MD_S8ListJoin(cg_arena, gen_strings, &join);
|
||||
fprintf(file, "%.*s", MD_S8VArg(gen_string));
|
||||
fprintf(file, "\n\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,92 +0,0 @@
|
||||
#ifndef METAPROGRAM_TABLE_H
|
||||
#define METAPROGRAM_TABLE_H
|
||||
|
||||
typedef enum CG_TableOp
|
||||
{
|
||||
CG_TableOp_Null,
|
||||
|
||||
CG_TableOp_BeginStringOps,
|
||||
CG_TableOp_Dot,
|
||||
CG_TableOp_Bump,
|
||||
CG_TableOp_CheckIfTrue,
|
||||
CG_TableOp_Concat,
|
||||
CG_TableOp_EndStringOps,
|
||||
|
||||
CG_TableOp_BeginNumericOps,
|
||||
CG_TableOp_Equal,
|
||||
CG_TableOp_IsNotEqual,
|
||||
CG_TableOp_BooleanAnd,
|
||||
CG_TableOp_BooleanOr,
|
||||
CG_TableOp_EndNumericOps,
|
||||
|
||||
CG_TableOp_COUNT
|
||||
}
|
||||
CG_TableOp;
|
||||
|
||||
typedef struct CG_NodeArray CG_NodeArray;
|
||||
struct CG_NodeArray
|
||||
{
|
||||
MD_u64 count;
|
||||
MD_Node **v;
|
||||
};
|
||||
|
||||
typedef struct CG_NodeGrid CG_NodeGrid;
|
||||
struct CG_NodeGrid
|
||||
{
|
||||
CG_NodeArray cells;
|
||||
CG_NodeArray row_parents;
|
||||
};
|
||||
|
||||
typedef enum CG_ColumnKind
|
||||
{
|
||||
CG_ColumnKind_Default,
|
||||
CG_ColumnKind_CheckForTag,
|
||||
CG_ColumnKind_COUNT
|
||||
}
|
||||
CG_ColumnKind;
|
||||
|
||||
typedef struct CG_ColumnDesc CG_ColumnDesc;
|
||||
struct CG_ColumnDesc
|
||||
{
|
||||
CG_ColumnKind kind;
|
||||
MD_String8 name;
|
||||
MD_String8 tag_string;
|
||||
};
|
||||
|
||||
typedef struct CG_TableHeader CG_TableHeader;
|
||||
struct CG_TableHeader
|
||||
{
|
||||
MD_u64 column_count;
|
||||
CG_ColumnDesc *column_descs;
|
||||
};
|
||||
|
||||
typedef struct CG_ExpandIter CG_ExpandIter;
|
||||
struct CG_ExpandIter
|
||||
{
|
||||
CG_ExpandIter *next;
|
||||
CG_NodeGrid *grid;
|
||||
CG_TableHeader *header;
|
||||
MD_String8 label;
|
||||
MD_u64 idx;
|
||||
MD_u64 count;
|
||||
};
|
||||
|
||||
typedef struct CG_ExpandInfo CG_ExpandInfo;
|
||||
struct CG_ExpandInfo
|
||||
{
|
||||
MD_String8 strexpr;
|
||||
CG_ExpandIter *first_expand_iter;
|
||||
MD_ExprOprTable expr_op_table;
|
||||
};
|
||||
|
||||
static CG_NodeArray CG_NodeArrayMake(MD_u64 count);
|
||||
static CG_NodeGrid CG_GridFromNode(MD_Node *node);
|
||||
static CG_TableHeader CG_TableHeaderFromTag(MD_Node *tag);
|
||||
static MD_u64 CG_RowChildIndexFromColumnName(CG_TableHeader *header, MD_String8 column_name);
|
||||
static MD_i64 CG_TableExprEvaluate_Numeric(CG_ExpandInfo *info, MD_Expr *expr);
|
||||
static void CG_TableExprEvaluate_String(CG_ExpandInfo *info, MD_Expr *expr, MD_String8List *out);
|
||||
static void CG_LoopExpansionDimension(CG_ExpandIter *it, CG_ExpandInfo *info, MD_String8List *out);
|
||||
static MD_String8List CG_GenStringListFromNode(MD_ExprOprTable expr_op_table, MD_Node *gen);
|
||||
static void CG_TBL_Generate(MD_Node *file_list);
|
||||
|
||||
#endif // METAPROGRAM_TABLE_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1144
src/metagen/metagen.c
Normal file
1144
src/metagen/metagen.c
Normal file
File diff suppressed because it is too large
Load Diff
329
src/metagen/metagen.h
Normal file
329
src/metagen/metagen.h
Normal file
@ -0,0 +1,329 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef METAGEN_H
|
||||
#define METAGEN_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Type
|
||||
|
||||
typedef struct MG_Msg MG_Msg;
|
||||
struct MG_Msg
|
||||
{
|
||||
String8 location;
|
||||
String8 kind;
|
||||
String8 msg;
|
||||
};
|
||||
|
||||
typedef struct MG_MsgNode MG_MsgNode;
|
||||
struct MG_MsgNode
|
||||
{
|
||||
MG_MsgNode *next;
|
||||
MG_Msg v;
|
||||
};
|
||||
|
||||
typedef struct MG_MsgList MG_MsgList;
|
||||
struct MG_MsgList
|
||||
{
|
||||
MG_MsgNode *first;
|
||||
MG_MsgNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Artifact Types
|
||||
|
||||
typedef struct MG_FileParse MG_FileParse;
|
||||
struct MG_FileParse
|
||||
{
|
||||
MD_Node *root;
|
||||
};
|
||||
|
||||
typedef struct MG_FileParseNode MG_FileParseNode;
|
||||
struct MG_FileParseNode
|
||||
{
|
||||
MG_FileParseNode *next;
|
||||
MG_FileParse v;
|
||||
};
|
||||
|
||||
typedef struct MG_FileParseList MG_FileParseList;
|
||||
struct MG_FileParseList
|
||||
{
|
||||
MG_FileParseNode *first;
|
||||
MG_FileParseNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Type
|
||||
|
||||
typedef struct MG_MapNode MG_MapNode;
|
||||
struct MG_MapNode
|
||||
{
|
||||
MG_MapNode *next;
|
||||
String8 key;
|
||||
void *val;
|
||||
};
|
||||
|
||||
typedef struct MG_MapSlot MG_MapSlot;
|
||||
struct MG_MapSlot
|
||||
{
|
||||
MG_MapNode *first;
|
||||
MG_MapNode *last;
|
||||
};
|
||||
|
||||
typedef struct MG_Map MG_Map;
|
||||
struct MG_Map
|
||||
{
|
||||
MG_MapSlot *slots;
|
||||
U64 slots_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Expression Types
|
||||
|
||||
typedef enum MG_StrExprOpKind
|
||||
{
|
||||
MG_StrExprOpKind_Null,
|
||||
MG_StrExprOpKind_Prefix,
|
||||
MG_StrExprOpKind_Postfix,
|
||||
MG_StrExprOpKind_Binary,
|
||||
MG_StrExprOpKind_COUNT
|
||||
}
|
||||
MG_StrExprOpKind;
|
||||
|
||||
typedef enum MG_StrExprOp
|
||||
{
|
||||
MG_StrExprOp_Null,
|
||||
|
||||
#define MG_StrExprOp_FirstString MG_StrExprOp_Dot
|
||||
MG_StrExprOp_Dot,
|
||||
MG_StrExprOp_ExpandIfTrue,
|
||||
MG_StrExprOp_Concat,
|
||||
MG_StrExprOp_BumpToColumn,
|
||||
#define MG_StrExprOp_LastString MG_StrExprOp_BumpToColumn
|
||||
|
||||
#define MG_StrExprOp_FirstNumeric MG_StrExprOp_Add
|
||||
MG_StrExprOp_Add,
|
||||
MG_StrExprOp_Subtract,
|
||||
MG_StrExprOp_Multiply,
|
||||
MG_StrExprOp_Divide,
|
||||
MG_StrExprOp_Modulo,
|
||||
MG_StrExprOp_LeftShift,
|
||||
MG_StrExprOp_RightShift,
|
||||
MG_StrExprOp_BitwiseAnd,
|
||||
MG_StrExprOp_BitwiseOr,
|
||||
MG_StrExprOp_BitwiseXor,
|
||||
MG_StrExprOp_BitwiseNegate,
|
||||
MG_StrExprOp_BooleanAnd,
|
||||
MG_StrExprOp_BooleanOr,
|
||||
MG_StrExprOp_BooleanNot,
|
||||
MG_StrExprOp_Equals,
|
||||
MG_StrExprOp_DoesNotEqual,
|
||||
#define MG_StrExprOp_LastNumeric MG_StrExprOp_DoesNotEqual
|
||||
|
||||
MG_StrExprOp_COUNT,
|
||||
}
|
||||
MG_StrExprOp;
|
||||
|
||||
typedef struct MG_StrExpr MG_StrExpr;
|
||||
struct MG_StrExpr
|
||||
{
|
||||
MG_StrExpr *parent;
|
||||
MG_StrExpr *left;
|
||||
MG_StrExpr *right;
|
||||
MG_StrExprOp op;
|
||||
MD_Node *node;
|
||||
};
|
||||
|
||||
typedef struct MG_StrExprParseResult MG_StrExprParseResult;
|
||||
struct MG_StrExprParseResult
|
||||
{
|
||||
MG_StrExpr *root;
|
||||
MD_MsgList msgs;
|
||||
MD_Node *next_node;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Generation Types
|
||||
|
||||
typedef struct MG_NodeArray MG_NodeArray;
|
||||
struct MG_NodeArray
|
||||
{
|
||||
MD_Node **v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct MG_NodeGrid MG_NodeGrid;
|
||||
struct MG_NodeGrid
|
||||
{
|
||||
U64 x_stride;
|
||||
U64 y_stride;
|
||||
MG_NodeArray cells;
|
||||
MG_NodeArray row_parents;
|
||||
};
|
||||
|
||||
typedef enum MG_ColumnKind
|
||||
{
|
||||
MG_ColumnKind_DirectCell,
|
||||
MG_ColumnKind_CheckForTag,
|
||||
MG_ColumnKind_TagChild,
|
||||
MG_ColumnKind_COUNT
|
||||
}
|
||||
MG_ColumnKind;
|
||||
|
||||
typedef struct MG_ColumnDesc MG_ColumnDesc;
|
||||
struct MG_ColumnDesc
|
||||
{
|
||||
String8 name;
|
||||
MG_ColumnKind kind;
|
||||
String8 tag_name;
|
||||
};
|
||||
|
||||
typedef struct MG_ColumnDescArray MG_ColumnDescArray;
|
||||
struct MG_ColumnDescArray
|
||||
{
|
||||
U64 count;
|
||||
MG_ColumnDesc *v;
|
||||
};
|
||||
|
||||
typedef struct MG_TableExpandTask MG_TableExpandTask;
|
||||
struct MG_TableExpandTask
|
||||
{
|
||||
MG_TableExpandTask *next;
|
||||
String8 expansion_label;
|
||||
MG_NodeGrid *grid;
|
||||
MG_ColumnDescArray column_descs;
|
||||
U64 count;
|
||||
U64 idx;
|
||||
};
|
||||
|
||||
typedef struct MG_TableExpandInfo MG_TableExpandInfo;
|
||||
struct MG_TableExpandInfo
|
||||
{
|
||||
MG_TableExpandTask *first_expand_task;
|
||||
String8 missing_value_fallback;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Output Path Types
|
||||
|
||||
typedef struct MG_Layer MG_Layer;
|
||||
struct MG_Layer
|
||||
{
|
||||
String8 key;
|
||||
B32 is_library;
|
||||
String8 gen_folder_name;
|
||||
String8 h_name_override;
|
||||
String8 c_name_override;
|
||||
String8List enums;
|
||||
String8List structs;
|
||||
String8List h_functions;
|
||||
String8List h_tables;
|
||||
String8List h_catchall;
|
||||
String8List h_header;
|
||||
String8List h_footer;
|
||||
String8List c_functions;
|
||||
String8List c_tables;
|
||||
String8List c_catchall;
|
||||
String8List c_header;
|
||||
String8List c_footer;
|
||||
};
|
||||
|
||||
typedef struct MG_LayerNode MG_LayerNode;
|
||||
struct MG_LayerNode
|
||||
{
|
||||
MG_LayerNode *next;
|
||||
MG_Layer v;
|
||||
};
|
||||
|
||||
typedef struct MG_LayerSlot MG_LayerSlot;
|
||||
struct MG_LayerSlot
|
||||
{
|
||||
MG_LayerNode *first;
|
||||
MG_LayerNode *last;
|
||||
};
|
||||
|
||||
typedef struct MG_State MG_State;
|
||||
struct MG_State
|
||||
{
|
||||
U64 slots_count;
|
||||
MG_LayerSlot *slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global Arena *mg_arena = 0;
|
||||
global MG_State *mg_state = 0;
|
||||
read_only global MG_StrExpr mg_str_expr_nil = {&mg_str_expr_nil, &mg_str_expr_nil, &mg_str_expr_nil};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 mg_hash_from_string(String8 string);
|
||||
internal TxtPt mg_txt_pt_from_string_off(String8 string, U64 off);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Lists
|
||||
|
||||
internal void mg_msg_list_push(Arena *arena, MG_MsgList *msgs, MG_Msg *msg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Escaping
|
||||
|
||||
internal String8 mg_escaped_from_str8(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Wrapping
|
||||
|
||||
internal String8List mg_wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: C-String-Izing
|
||||
|
||||
internal String8 mg_c_string_literal_from_multiline_string(String8 string);
|
||||
internal String8 mg_c_array_literal_contents_from_data(String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Functions
|
||||
|
||||
internal MG_Map mg_push_map(Arena *arena, U64 slot_count);
|
||||
internal void *mg_map_ptr_from_string(MG_Map *map, String8 string);
|
||||
internal void mg_map_insert_ptr(Arena *arena, MG_Map *map, String8 string, void *val);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Expression Parsing
|
||||
|
||||
internal MG_StrExpr *mg_push_str_expr(Arena *arena, MG_StrExprOp op, MD_Node *node);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node *opl, S8 min_prec);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl(Arena *arena, MD_Node *first, MD_Node *opl);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_root(Arena *arena, MD_Node *root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Generation Functions
|
||||
|
||||
internal MG_NodeArray mg_node_array_make(Arena *arena, U64 count);
|
||||
internal MG_NodeArray mg_child_array_from_node(Arena *arena, MD_Node *node);
|
||||
internal MG_NodeGrid mg_node_grid_make_from_node(Arena *arena, MD_Node *root);
|
||||
internal MG_NodeArray mg_row_from_index(MG_NodeGrid grid, U64 index);
|
||||
internal MG_NodeArray mg_column_from_index(Arena *arena, MG_NodeGrid grid, U64 index);
|
||||
internal MD_Node *mg_node_from_grid_xy(MG_NodeGrid grid, U64 x, U64 y);
|
||||
|
||||
internal MG_ColumnDescArray mg_column_desc_array_make(Arena *arena, U64 count, MG_ColumnDesc *descs);
|
||||
internal MG_ColumnDescArray mg_column_desc_array_from_tag(Arena *arena, MD_Node *tag);
|
||||
internal U64 mg_column_index_from_name(MG_ColumnDescArray descs, String8 name);
|
||||
internal String8 mg_string_from_row_desc_idx(MD_Node *row_parent, MG_ColumnDescArray descs, U64 idx);
|
||||
|
||||
internal S64 mg_eval_table_expand_expr__numeric(MG_StrExpr *expr, MG_TableExpandInfo *info);
|
||||
internal void mg_eval_table_expand_expr__string(Arena *arena, MG_StrExpr *expr, MG_TableExpandInfo *info, String8List *out);
|
||||
internal void mg_loop_table_column_expansion(Arena *arena, String8 strexpr, MG_TableExpandInfo *info, MG_TableExpandTask *task, String8List *out);
|
||||
internal String8List mg_string_list_from_table_gen(Arena *arena, MG_Map grid_name_map, MG_Map grid_column_desc_map, String8 fallback, MD_Node *gen);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Layer Lookup Functions
|
||||
|
||||
internal String8 mg_layer_key_from_path(String8 path);
|
||||
internal MG_Layer *mg_layer_from_key(String8 key);
|
||||
|
||||
#endif //METAGEN_H
|
||||
248
src/metagen/metagen_base/metagen_base_arena.c
Normal file
248
src/metagen/metagen_base/metagen_base_arena.c
Normal file
@ -0,0 +1,248 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Arena Functions
|
||||
|
||||
//- rjf: arena creation/destruction
|
||||
|
||||
internal Arena *
|
||||
arena_alloc_(ArenaParams *params)
|
||||
{
|
||||
// rjf: round up reserve/commit sizes
|
||||
U64 reserve_size = params->reserve_size;
|
||||
U64 commit_size = params->commit_size;
|
||||
if(params->flags & ArenaFlag_LargePages)
|
||||
{
|
||||
reserve_size = AlignPow2(reserve_size, os_get_system_info()->large_page_size);
|
||||
commit_size = AlignPow2(commit_size, os_get_system_info()->large_page_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
reserve_size = AlignPow2(reserve_size, os_get_system_info()->page_size);
|
||||
commit_size = AlignPow2(commit_size, os_get_system_info()->page_size);
|
||||
}
|
||||
|
||||
// rjf: reserve/commit initial block
|
||||
void *base = params->optional_backing_buffer;
|
||||
if(base == 0)
|
||||
{
|
||||
if(params->flags & ArenaFlag_LargePages)
|
||||
{
|
||||
base = os_reserve_large(reserve_size);
|
||||
os_commit_large(base, commit_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
base = os_reserve(reserve_size);
|
||||
os_commit(base, commit_size);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: panic on arena creation failure
|
||||
#if OS_FEATURE_GRAPHICAL
|
||||
if(Unlikely(base == 0))
|
||||
{
|
||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||
os_abort(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
// rjf: extract arena header & fill
|
||||
Arena *arena = (Arena *)base;
|
||||
arena->current = arena;
|
||||
arena->flags = params->flags;
|
||||
arena->cmt_size = params->commit_size;
|
||||
arena->res_size = params->reserve_size;
|
||||
arena->base_pos = 0;
|
||||
arena->pos = ARENA_HEADER_SIZE;
|
||||
arena->cmt = commit_size;
|
||||
arena->res = reserve_size;
|
||||
#if ARENA_FREE_LIST
|
||||
arena->free_size = 0;
|
||||
arena->free_last = 0;
|
||||
#endif
|
||||
AsanPoisonMemoryRegion(base, commit_size);
|
||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
||||
return arena;
|
||||
}
|
||||
|
||||
internal void
|
||||
arena_release(Arena *arena)
|
||||
{
|
||||
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
|
||||
{
|
||||
prev = n->prev;
|
||||
os_release(n, n->res);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: arena push/pop core functions
|
||||
|
||||
internal void *
|
||||
arena_push(Arena *arena, U64 size, U64 align)
|
||||
{
|
||||
Arena *current = arena->current;
|
||||
U64 pos_pre = AlignPow2(current->pos, align);
|
||||
U64 pos_pst = pos_pre + size;
|
||||
|
||||
// rjf: chain, if needed
|
||||
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
|
||||
{
|
||||
Arena *new_block = 0;
|
||||
|
||||
#if ARENA_FREE_LIST
|
||||
Arena *prev_block;
|
||||
for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev)
|
||||
{
|
||||
if(new_block->res >= AlignPow2(size, align))
|
||||
{
|
||||
if(prev_block)
|
||||
{
|
||||
prev_block->prev = new_block->prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
arena->free_last = new_block->prev;
|
||||
}
|
||||
arena->free_size -= new_block->res_size;
|
||||
AsanUnpoisonMemoryRegion((U8*)new_block + ARENA_HEADER_SIZE, new_block->res_size - ARENA_HEADER_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(new_block == 0)
|
||||
{
|
||||
U64 res_size = current->res_size;
|
||||
U64 cmt_size = current->cmt_size;
|
||||
if(size + ARENA_HEADER_SIZE > res_size)
|
||||
{
|
||||
res_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
||||
cmt_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
||||
}
|
||||
new_block = arena_alloc(.reserve_size = res_size,
|
||||
.commit_size = cmt_size,
|
||||
.flags = current->flags);
|
||||
}
|
||||
|
||||
new_block->base_pos = current->base_pos + current->res;
|
||||
SLLStackPush_N(arena->current, new_block, prev);
|
||||
|
||||
current = new_block;
|
||||
pos_pre = AlignPow2(current->pos, align);
|
||||
pos_pst = pos_pre + size;
|
||||
}
|
||||
|
||||
// rjf: commit new pages, if needed
|
||||
if(current->cmt < pos_pst)
|
||||
{
|
||||
U64 cmt_pst_aligned = pos_pst + current->cmt_size-1;
|
||||
cmt_pst_aligned -= cmt_pst_aligned%current->cmt_size;
|
||||
U64 cmt_pst_clamped = ClampTop(cmt_pst_aligned, current->res);
|
||||
U64 cmt_size = cmt_pst_clamped - current->cmt;
|
||||
U8 *cmt_ptr = (U8 *)current + current->cmt;
|
||||
if(current->flags & ArenaFlag_LargePages)
|
||||
{
|
||||
os_commit_large(cmt_ptr, cmt_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
os_commit(cmt_ptr, cmt_size);
|
||||
}
|
||||
current->cmt = cmt_pst_clamped;
|
||||
}
|
||||
|
||||
// rjf: push onto current block
|
||||
void *result = 0;
|
||||
if(current->cmt >= pos_pst)
|
||||
{
|
||||
result = (U8 *)current+pos_pre;
|
||||
current->pos = pos_pst;
|
||||
AsanUnpoisonMemoryRegion(result, size);
|
||||
}
|
||||
|
||||
// rjf: panic on failure
|
||||
#if OS_FEATURE_GRAPHICAL
|
||||
if(Unlikely(result == 0))
|
||||
{
|
||||
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||
os_abort(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
arena_pos(Arena *arena)
|
||||
{
|
||||
Arena *current = arena->current;
|
||||
U64 pos = current->base_pos + current->pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
internal void
|
||||
arena_pop_to(Arena *arena, U64 pos)
|
||||
{
|
||||
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
|
||||
Arena *current = arena->current;
|
||||
|
||||
#if ARENA_FREE_LIST
|
||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
||||
{
|
||||
prev = current->prev;
|
||||
current->pos = ARENA_HEADER_SIZE;
|
||||
arena->free_size += current->res_size;
|
||||
SLLStackPush_N(arena->free_last, current, prev);
|
||||
AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res_size - ARENA_HEADER_SIZE);
|
||||
}
|
||||
#else
|
||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
||||
{
|
||||
prev = current->prev;
|
||||
os_release(current, current->res);
|
||||
}
|
||||
#endif
|
||||
arena->current = current;
|
||||
U64 new_pos = big_pos - current->base_pos;
|
||||
AssertAlways(new_pos <= current->pos);
|
||||
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
||||
current->pos = new_pos;
|
||||
}
|
||||
|
||||
//- rjf: arena push/pop helpers
|
||||
|
||||
internal void
|
||||
arena_clear(Arena *arena)
|
||||
{
|
||||
arena_pop_to(arena, 0);
|
||||
}
|
||||
|
||||
internal void
|
||||
arena_pop(Arena *arena, U64 amt)
|
||||
{
|
||||
U64 pos_old = arena_pos(arena);
|
||||
U64 pos_new = pos_old;
|
||||
if(amt < pos_old)
|
||||
{
|
||||
pos_new = pos_old - amt;
|
||||
}
|
||||
arena_pop_to(arena, pos_new);
|
||||
}
|
||||
|
||||
//- rjf: temporary arena scopes
|
||||
|
||||
internal Temp
|
||||
temp_begin(Arena *arena)
|
||||
{
|
||||
U64 pos = arena_pos(arena);
|
||||
Temp temp = {arena, pos};
|
||||
return temp;
|
||||
}
|
||||
|
||||
internal void
|
||||
temp_end(Temp temp)
|
||||
{
|
||||
arena_pop_to(temp.arena, temp.pos);
|
||||
}
|
||||
91
src/metagen/metagen_base/metagen_base_arena.h
Normal file
91
src/metagen/metagen_base/metagen_base_arena.h
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_ARENA_H
|
||||
#define BASE_ARENA_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Constants
|
||||
|
||||
#define ARENA_HEADER_SIZE 128
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Types
|
||||
|
||||
typedef U64 ArenaFlags;
|
||||
enum
|
||||
{
|
||||
ArenaFlag_NoChain = (1<<0),
|
||||
ArenaFlag_LargePages = (1<<1),
|
||||
};
|
||||
|
||||
typedef struct ArenaParams ArenaParams;
|
||||
struct ArenaParams
|
||||
{
|
||||
ArenaFlags flags;
|
||||
U64 reserve_size;
|
||||
U64 commit_size;
|
||||
void *optional_backing_buffer;
|
||||
};
|
||||
|
||||
typedef struct Arena Arena;
|
||||
struct Arena
|
||||
{
|
||||
Arena *prev; // previous arena in chain
|
||||
Arena *current; // current arena in chain
|
||||
ArenaFlags flags;
|
||||
U64 cmt_size;
|
||||
U64 res_size;
|
||||
U64 base_pos;
|
||||
U64 pos;
|
||||
U64 cmt;
|
||||
U64 res;
|
||||
#if ARENA_FREE_LIST
|
||||
U64 free_size;
|
||||
Arena *free_last;
|
||||
#endif
|
||||
};
|
||||
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
|
||||
|
||||
typedef struct Temp Temp;
|
||||
struct Temp
|
||||
{
|
||||
Arena *arena;
|
||||
U64 pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Global Defaults
|
||||
|
||||
global U64 arena_default_reserve_size = MB(64);
|
||||
global U64 arena_default_commit_size = KB(64);
|
||||
global ArenaFlags arena_default_flags = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Arena Functions
|
||||
|
||||
//- rjf: arena creation/destruction
|
||||
internal Arena *arena_alloc_(ArenaParams *params);
|
||||
#define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = arena_default_reserve_size, .commit_size = arena_default_commit_size, .flags = arena_default_flags, __VA_ARGS__})
|
||||
internal void arena_release(Arena *arena);
|
||||
|
||||
//- rjf: arena push/pop/pos core functions
|
||||
internal void *arena_push(Arena *arena, U64 size, U64 align);
|
||||
internal U64 arena_pos(Arena *arena);
|
||||
internal void arena_pop_to(Arena *arena, U64 pos);
|
||||
|
||||
//- rjf: arena push/pop helpers
|
||||
internal void arena_clear(Arena *arena);
|
||||
internal void arena_pop(Arena *arena, U64 amt);
|
||||
|
||||
//- rjf: temporary arena scopes
|
||||
internal Temp temp_begin(Arena *arena);
|
||||
internal void temp_end(Temp temp);
|
||||
|
||||
//- rjf: push helper macros
|
||||
#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align))
|
||||
#define push_array_aligned(a, T, c, align) (T *)MemoryZero(push_array_no_zero_aligned(a, T, c, align), sizeof(T)*(c))
|
||||
#define push_array_no_zero(a, T, c) push_array_no_zero_aligned(a, T, c, Max(8, AlignOf(T)))
|
||||
#define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T)))
|
||||
|
||||
#endif // BASE_ARENA_H
|
||||
250
src/metagen/metagen_base/metagen_base_command_line.c
Normal file
250
src/metagen/metagen_base/metagen_base_command_line.c
Normal file
@ -0,0 +1,250 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64
|
||||
cmd_line_hash_from_string(String8 string)
|
||||
{
|
||||
U64 result = 5381;
|
||||
for(U64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CmdLineOpt **
|
||||
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
||||
{
|
||||
CmdLineOpt **slot = 0;
|
||||
if(cmd_line->option_table_size != 0)
|
||||
{
|
||||
U64 hash = cmd_line_hash_from_string(string);
|
||||
U64 bucket = hash % cmd_line->option_table_size;
|
||||
slot = &cmd_line->option_table[bucket];
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string)
|
||||
{
|
||||
CmdLineOpt *result = 0;
|
||||
for(CmdLineOpt *var = *slot; var; var = var->hash_next)
|
||||
{
|
||||
if(str8_match(string, var->string, 0))
|
||||
{
|
||||
result = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, var);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values)
|
||||
{
|
||||
CmdLineOpt *var = 0;
|
||||
CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string);
|
||||
CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string);
|
||||
if(existing_var != 0)
|
||||
{
|
||||
var = existing_var;
|
||||
}
|
||||
else
|
||||
{
|
||||
var = push_array(arena, CmdLineOpt, 1);
|
||||
var->hash_next = *slot;
|
||||
var->hash = cmd_line_hash_from_string(string);
|
||||
var->string = push_str8_copy(arena, string);
|
||||
var->value_strings = values;
|
||||
StringJoin join = {0};
|
||||
join.pre = str8_lit("");
|
||||
join.sep = str8_lit(",");
|
||||
join.post = str8_lit("");
|
||||
var->value_string = str8_list_join(arena, &var->value_strings, &join);
|
||||
*slot = var;
|
||||
cmd_line_push_opt(&cmd_line->options, var);
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
internal CmdLine
|
||||
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
{
|
||||
CmdLine parsed = {0};
|
||||
parsed.exe_name = command_line.first->string;
|
||||
|
||||
// NOTE(rjf): Set up config option table.
|
||||
{
|
||||
parsed.option_table_size = 4096;
|
||||
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
||||
}
|
||||
|
||||
// NOTE(rjf): Parse command line.
|
||||
B32 after_passthrough_option = 0;
|
||||
B32 first_passthrough = 1;
|
||||
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
||||
{
|
||||
next = node->next;
|
||||
String8 option_name = node->string;
|
||||
|
||||
// NOTE(rjf): Look at --, -, or / (only on Windows) at the start of an
|
||||
// argument to determine if it's a flag option. All arguments after a
|
||||
// single "--" (with no trailing string on the command line will be
|
||||
// considered as input files.
|
||||
B32 is_option = 1;
|
||||
if(after_passthrough_option == 0)
|
||||
{
|
||||
if(str8_match(node->string, str8_lit("--"), 0))
|
||||
{
|
||||
after_passthrough_option = 1;
|
||||
is_option = 0;
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 2);
|
||||
}
|
||||
else if(str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else if(operating_system_from_context() == OperatingSystem_Windows &&
|
||||
str8_match(str8_prefix(node->string, 1), str8_lit("/"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
}
|
||||
|
||||
// NOTE(rjf): This string is an option.
|
||||
if(is_option)
|
||||
{
|
||||
B32 has_arguments = 0;
|
||||
U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
||||
U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
||||
U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2);
|
||||
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
|
||||
if(arg_signifier_position < option_name.size)
|
||||
{
|
||||
has_arguments = 1;
|
||||
}
|
||||
option_name = str8_prefix(option_name, arg_signifier_position);
|
||||
|
||||
String8List arguments = {0};
|
||||
|
||||
// NOTE(rjf): Parse arguments.
|
||||
if(has_arguments)
|
||||
{
|
||||
for(String8Node *n = node; n; n = n->next)
|
||||
{
|
||||
next = n->next;
|
||||
|
||||
String8 string = n->string;
|
||||
if(n == node)
|
||||
{
|
||||
string = arg_portion_this_string;
|
||||
}
|
||||
|
||||
U8 splits[] = { ',' };
|
||||
String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
||||
for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next)
|
||||
{
|
||||
str8_list_push(arena, &arguments, sub_arg->string);
|
||||
}
|
||||
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
||||
(n != node || arg_portion_this_string.size != 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(rjf): Register config variable.
|
||||
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
|
||||
}
|
||||
|
||||
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
||||
// handled by tool-specific code.
|
||||
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
|
||||
{
|
||||
str8_list_push(arena, &parsed.inputs, node->string);
|
||||
after_passthrough_option = 1;
|
||||
first_passthrough = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: fill argc/argv
|
||||
parsed.argc = command_line.node_count;
|
||||
parsed.argv = push_array(arena, char *, parsed.argc);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for(String8Node *n = command_line.first; n != 0; n = n->next)
|
||||
{
|
||||
parsed.argv[idx] = (char *)push_str8_copy(arena, n->string).str;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
internal CmdLineOpt *
|
||||
cmd_line_opt_from_string(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
return cmd_line_opt_from_slot(cmd_line_slot_from_string(cmd_line, name), name);
|
||||
}
|
||||
|
||||
internal String8List
|
||||
cmd_line_strings(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8List result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_strings;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cmd_line_string(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
String8 result = {0};
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
if(var != 0)
|
||||
{
|
||||
result = var->value_string;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
return(var != 0);
|
||||
}
|
||||
|
||||
internal B32
|
||||
cmd_line_has_argument(CmdLine *cmd_line, String8 name)
|
||||
{
|
||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||
return(var != 0 && var->value_strings.node_count > 0);
|
||||
}
|
||||
56
src/metagen/metagen_base/metagen_base_command_line.h
Normal file
56
src/metagen/metagen_base/metagen_base_command_line.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_COMMAND_LINE_H
|
||||
#define BASE_COMMAND_LINE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parsed Command Line Types
|
||||
|
||||
typedef struct CmdLineOpt CmdLineOpt;
|
||||
struct CmdLineOpt
|
||||
{
|
||||
CmdLineOpt *next;
|
||||
CmdLineOpt *hash_next;
|
||||
U64 hash;
|
||||
String8 string;
|
||||
String8List value_strings;
|
||||
String8 value_string;
|
||||
};
|
||||
|
||||
typedef struct CmdLineOptList CmdLineOptList;
|
||||
struct CmdLineOptList
|
||||
{
|
||||
U64 count;
|
||||
CmdLineOpt *first;
|
||||
CmdLineOpt *last;
|
||||
};
|
||||
|
||||
typedef struct CmdLine CmdLine;
|
||||
struct CmdLine
|
||||
{
|
||||
String8 exe_name;
|
||||
CmdLineOptList options;
|
||||
String8List inputs;
|
||||
U64 option_table_size;
|
||||
CmdLineOpt **option_table;
|
||||
U64 argc;
|
||||
char **argv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(rjf): Command Line Option Parsing
|
||||
|
||||
internal U64 cmd_line_hash_from_string(String8 string);
|
||||
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
||||
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
||||
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
||||
internal CmdLineOpt* cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values);
|
||||
internal CmdLine cmd_line_from_string_list(Arena *arena, String8List arguments);
|
||||
internal CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name);
|
||||
internal String8List cmd_line_strings(CmdLine *cmd_line, String8 name);
|
||||
internal String8 cmd_line_string(CmdLine *cmd_line, String8 name);
|
||||
internal B32 cmd_line_has_flag(CmdLine *cmd_line, String8 name);
|
||||
internal B32 cmd_line_has_argument(CmdLine *cmd_line, String8 name);
|
||||
|
||||
#endif // BASE_COMMAND_LINE_H
|
||||
247
src/metagen/metagen_base/metagen_base_context_cracking.h
Normal file
247
src/metagen/metagen_base/metagen_base_context_cracking.h
Normal file
@ -0,0 +1,247 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_CONTEXT_CRACKING_H
|
||||
#define BASE_CONTEXT_CRACKING_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Clang OS/Arch Cracking
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
# define COMPILER_CLANG 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# elif defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define OS_MAC 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MSVC OS/Arch Cracking
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
# define COMPILER_MSVC 1
|
||||
|
||||
# if _MSC_VER >= 1920
|
||||
# define COMPILER_MSVC_YEAR 2019
|
||||
# elif _MSC_VER >= 1910
|
||||
# define COMPILER_MSVC_YEAR 2017
|
||||
# elif _MSC_VER >= 1900
|
||||
# define COMPILER_MSVC_YEAR 2015
|
||||
# elif _MSC_VER >= 1800
|
||||
# define COMPILER_MSVC_YEAR 2013
|
||||
# elif _MSC_VER >= 1700
|
||||
# define COMPILER_MSVC_YEAR 2012
|
||||
# elif _MSC_VER >= 1600
|
||||
# define COMPILER_MSVC_YEAR 2010
|
||||
# elif _MSC_VER >= 1500
|
||||
# define COMPILER_MSVC_YEAR 2008
|
||||
# elif _MSC_VER >= 1400
|
||||
# define COMPILER_MSVC_YEAR 2005
|
||||
# else
|
||||
# define COMPILER_MSVC_YEAR 0
|
||||
# endif
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(_M_AMD64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(_M_IX86)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(_M_ARM64)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(_M_ARM)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: GCC OS/Arch Cracking
|
||||
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
|
||||
# define COMPILER_GCC 1
|
||||
|
||||
# if defined(__gnu_linux__) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
# else
|
||||
# error This compiler/OS combo is not supported.
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(i386) || defined(__i386) || defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM32 1
|
||||
# else
|
||||
# error Architecture not supported.
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error Compiler not supported.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Arch Cracking
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
# define ARCH_64BIT 1
|
||||
#elif defined(ARCH_X86)
|
||||
# define ARCH_32BIT 1
|
||||
#endif
|
||||
|
||||
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
|
||||
# define ARCH_LITTLE_ENDIAN 1
|
||||
#else
|
||||
# error Endianness of this architecture not understood by context cracker.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Language Cracking
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# define LANG_CPP 1
|
||||
#else
|
||||
# define LANG_C 1
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Build Option Cracking
|
||||
|
||||
#if !defined(BUILD_DEBUG)
|
||||
# define BUILD_DEBUG 1
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
||||
# define BUILD_SUPPLEMENTARY_UNIT 0
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_ENTRY_DEFINING_UNIT)
|
||||
# define BUILD_ENTRY_DEFINING_UNIT 1
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_CONSOLE_INTERFACE)
|
||||
# define BUILD_CONSOLE_INTERFACE 0
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_MAJOR)
|
||||
# define BUILD_VERSION_MAJOR 0
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_MINOR)
|
||||
# define BUILD_VERSION_MINOR 9
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_PATCH)
|
||||
# define BUILD_VERSION_PATCH 14
|
||||
#endif
|
||||
|
||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
||||
#if BUILD_DEBUG
|
||||
# define BUILD_MODE_STRING_LITERAL_APPEND " [Debug]"
|
||||
#else
|
||||
# define BUILD_MODE_STRING_LITERAL_APPEND ""
|
||||
#endif
|
||||
#if defined(BUILD_GIT_HASH)
|
||||
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND " [" BUILD_GIT_HASH "]"
|
||||
#else
|
||||
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND ""
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_TITLE)
|
||||
# define BUILD_TITLE "Untitled"
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_RELEASE_PHASE_STRING_LITERAL)
|
||||
# define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL)
|
||||
# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGamesExt/raddebugger/issues"
|
||||
#endif
|
||||
|
||||
#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zero All Undefined Options
|
||||
|
||||
#if !defined(ARCH_32BIT)
|
||||
# define ARCH_32BIT 0
|
||||
#endif
|
||||
#if !defined(ARCH_64BIT)
|
||||
# define ARCH_64BIT 0
|
||||
#endif
|
||||
#if !defined(ARCH_X64)
|
||||
# define ARCH_X64 0
|
||||
#endif
|
||||
#if !defined(ARCH_X86)
|
||||
# define ARCH_X86 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM64)
|
||||
# define ARCH_ARM64 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM32)
|
||||
# define ARCH_ARM32 0
|
||||
#endif
|
||||
#if !defined(COMPILER_MSVC)
|
||||
# define COMPILER_MSVC 0
|
||||
#endif
|
||||
#if !defined(COMPILER_GCC)
|
||||
# define COMPILER_GCC 0
|
||||
#endif
|
||||
#if !defined(COMPILER_CLANG)
|
||||
# define COMPILER_CLANG 0
|
||||
#endif
|
||||
#if !defined(OS_WINDOWS)
|
||||
# define OS_WINDOWS 0
|
||||
#endif
|
||||
#if !defined(OS_LINUX)
|
||||
# define OS_LINUX 0
|
||||
#endif
|
||||
#if !defined(OS_MAC)
|
||||
# define OS_MAC 0
|
||||
#endif
|
||||
#if !defined(LANG_CPP)
|
||||
# define LANG_CPP 0
|
||||
#endif
|
||||
#if !defined(LANG_C)
|
||||
# define LANG_C 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unsupported Errors
|
||||
|
||||
#if ARCH_X86
|
||||
# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported.
|
||||
#endif
|
||||
#if !ARCH_X64
|
||||
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
|
||||
#endif
|
||||
|
||||
#endif // BASE_CONTEXT_CRACKING_H
|
||||
604
src/metagen/metagen_base/metagen_base_core.c
Normal file
604
src/metagen/metagen_base/metagen_base_core.c
Normal file
@ -0,0 +1,604 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Safe Casts
|
||||
|
||||
internal U16
|
||||
safe_cast_u16(U32 x)
|
||||
{
|
||||
AssertAlways(x <= max_U16);
|
||||
U16 result = (U16)x;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U32
|
||||
safe_cast_u32(U64 x)
|
||||
{
|
||||
AssertAlways(x <= max_U32);
|
||||
U32 result = (U32)x;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal S32
|
||||
safe_cast_s32(S64 x)
|
||||
{
|
||||
AssertAlways(x <= max_S32);
|
||||
S32 result = (S32)x;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Large Base Type Functions
|
||||
|
||||
internal U128
|
||||
u128_zero(void)
|
||||
{
|
||||
U128 v = {0};
|
||||
return v;
|
||||
}
|
||||
|
||||
internal U128
|
||||
u128_make(U64 v0, U64 v1)
|
||||
{
|
||||
U128 v = {v0, v1};
|
||||
return v;
|
||||
}
|
||||
|
||||
internal B32
|
||||
u128_match(U128 a, U128 b)
|
||||
{
|
||||
return MemoryMatchStruct(&a, &b);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bit Patterns
|
||||
|
||||
internal U32
|
||||
u32_from_u64_saturate(U64 x){
|
||||
U32 x32 = (x > max_U32)?max_U32:(U32)x;
|
||||
return(x32);
|
||||
}
|
||||
|
||||
internal U64
|
||||
u64_up_to_pow2(U64 x){
|
||||
if (x == 0){
|
||||
x = 1;
|
||||
}
|
||||
else{
|
||||
x -= 1;
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 8);
|
||||
x |= (x >> 16);
|
||||
x |= (x >> 32);
|
||||
x += 1;
|
||||
}
|
||||
return(x);
|
||||
}
|
||||
|
||||
internal S32
|
||||
extend_sign32(U32 x, U32 size){
|
||||
U32 high_bit = size * 8;
|
||||
U32 shift = 32 - high_bit;
|
||||
S32 result = ((S32)x << shift) >> shift;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal S64
|
||||
extend_sign64(U64 x, U64 size){
|
||||
U64 high_bit = size * 8;
|
||||
U64 shift = 64 - high_bit;
|
||||
S64 result = ((S64)x << shift) >> shift;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal F32
|
||||
inf32(void){
|
||||
union { U32 u; F32 f; } x;
|
||||
x.u = exponent32;
|
||||
return(x.f);
|
||||
}
|
||||
|
||||
internal F32
|
||||
neg_inf32(void){
|
||||
union { U32 u; F32 f; } x;
|
||||
x.u = sign32 | exponent32;
|
||||
return(x.f);
|
||||
}
|
||||
|
||||
internal U16
|
||||
bswap_u16(U16 x)
|
||||
{
|
||||
U16 result = (((x & 0xFF00) >> 8) |
|
||||
((x & 0x00FF) << 8));
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U32
|
||||
bswap_u32(U32 x)
|
||||
{
|
||||
U32 result = (((x & 0xFF000000) >> 24) |
|
||||
((x & 0x00FF0000) >> 8) |
|
||||
((x & 0x0000FF00) << 8) |
|
||||
((x & 0x000000FF) << 24));
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
bswap_u64(U64 x)
|
||||
{
|
||||
// TODO(nick): naive bswap, replace with something that is faster like an intrinsic
|
||||
U64 result = (((x & 0xFF00000000000000ULL) >> 56) |
|
||||
((x & 0x00FF000000000000ULL) >> 40) |
|
||||
((x & 0x0000FF0000000000ULL) >> 24) |
|
||||
((x & 0x000000FF00000000ULL) >> 8) |
|
||||
((x & 0x00000000FF000000ULL) << 8) |
|
||||
((x & 0x0000000000FF0000ULL) << 24) |
|
||||
((x & 0x000000000000FF00ULL) << 40) |
|
||||
((x & 0x00000000000000FFULL) << 56));
|
||||
return result;
|
||||
}
|
||||
|
||||
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
|
||||
|
||||
internal U64
|
||||
count_bits_set32(U32 val)
|
||||
{
|
||||
return __popcnt(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set64(U64 val)
|
||||
{
|
||||
return __popcnt64(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz32(U32 mask)
|
||||
{
|
||||
unsigned long idx;
|
||||
_BitScanForward(&idx, mask);
|
||||
return idx;
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz64(U64 mask)
|
||||
{
|
||||
unsigned long idx;
|
||||
_BitScanForward64(&idx, mask);
|
||||
return idx;
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz32(U32 mask)
|
||||
{
|
||||
unsigned long idx;
|
||||
_BitScanReverse(&idx, mask);
|
||||
return 31 - idx;
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz64(U64 mask)
|
||||
{
|
||||
unsigned long idx;
|
||||
_BitScanReverse64(&idx, mask);
|
||||
return 63 - idx;
|
||||
}
|
||||
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
|
||||
internal U64
|
||||
count_bits_set32(U32 val)
|
||||
{
|
||||
return __builtin_popcount(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set64(U64 val)
|
||||
{
|
||||
return __builtin_popcountll(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz32(U32 val)
|
||||
{
|
||||
return __builtin_ctz(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz32(U32 val)
|
||||
{
|
||||
return __builtin_clz(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz64(U64 val)
|
||||
{
|
||||
return __builtin_ctzll(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz64(U64 val)
|
||||
{
|
||||
return __builtin_clzll(val);
|
||||
}
|
||||
|
||||
#else
|
||||
# error "Bit intrinsic functions not defined for this compiler."
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Enum -> Sign
|
||||
|
||||
internal S32
|
||||
sign_from_side_S32(Side side){
|
||||
return((side == Side_Min)?-1:1);
|
||||
}
|
||||
|
||||
internal F32
|
||||
sign_from_side_F32(Side side){
|
||||
return((side == Side_Min)?-1.f:1.f);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Memory Functions
|
||||
|
||||
internal B32
|
||||
memory_is_zero(void *ptr, U64 size){
|
||||
B32 result = 1;
|
||||
|
||||
// break down size
|
||||
U64 extra = (size&0x7);
|
||||
U64 count8 = (size >> 3);
|
||||
|
||||
// check with 8-byte stride
|
||||
U64 *p64 = (U64*)ptr;
|
||||
if(result)
|
||||
{
|
||||
for (U64 i = 0; i < count8; i += 1, p64 += 1){
|
||||
if (*p64 != 0){
|
||||
result = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check extra
|
||||
if(result)
|
||||
{
|
||||
U8 *p8 = (U8*)p64;
|
||||
for (U64 i = 0; i < extra; i += 1, p8 += 1){
|
||||
if (*p8 != 0){
|
||||
result = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:;
|
||||
return(result);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text 2D Coordinate/Range Functions
|
||||
|
||||
internal TxtPt
|
||||
txt_pt(S64 line, S64 column)
|
||||
{
|
||||
TxtPt p = {0};
|
||||
p.line = line;
|
||||
p.column = column;
|
||||
return p;
|
||||
}
|
||||
|
||||
internal B32
|
||||
txt_pt_match(TxtPt a, TxtPt b)
|
||||
{
|
||||
return a.line == b.line && a.column == b.column;
|
||||
}
|
||||
|
||||
internal B32
|
||||
txt_pt_less_than(TxtPt a, TxtPt b)
|
||||
{
|
||||
B32 result = 0;
|
||||
if(a.line < b.line)
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
else if(a.line == b.line)
|
||||
{
|
||||
result = a.column < b.column;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal TxtPt
|
||||
txt_pt_min(TxtPt a, TxtPt b)
|
||||
{
|
||||
TxtPt result = b;
|
||||
if(txt_pt_less_than(a, b))
|
||||
{
|
||||
result = a;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal TxtPt
|
||||
txt_pt_max(TxtPt a, TxtPt b)
|
||||
{
|
||||
TxtPt result = a;
|
||||
if(txt_pt_less_than(a, b))
|
||||
{
|
||||
result = b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal TxtRng
|
||||
txt_rng(TxtPt min, TxtPt max)
|
||||
{
|
||||
TxtRng range = {0};
|
||||
if(txt_pt_less_than(min, max))
|
||||
{
|
||||
range.min = min;
|
||||
range.max = max;
|
||||
}
|
||||
else
|
||||
{
|
||||
range.min = max;
|
||||
range.max = min;
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
internal TxtRng
|
||||
txt_rng_intersect(TxtRng a, TxtRng b)
|
||||
{
|
||||
TxtRng result = {0};
|
||||
result.min = txt_pt_max(a.min, b.min);
|
||||
result.max = txt_pt_min(a.max, b.max);
|
||||
if(txt_pt_less_than(result.max, result.min))
|
||||
{
|
||||
MemoryZeroStruct(&result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal TxtRng
|
||||
txt_rng_union(TxtRng a, TxtRng b)
|
||||
{
|
||||
TxtRng result = {0};
|
||||
result.min = txt_pt_min(a.min, b.min);
|
||||
result.max = txt_pt_max(a.max, b.max);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
txt_rng_contains(TxtRng r, TxtPt pt)
|
||||
{
|
||||
B32 result = ((txt_pt_less_than(r.min, pt) || txt_pt_match(r.min, pt)) &&
|
||||
txt_pt_less_than(pt, r.max));
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Toolchain/Environment Enum Functions
|
||||
|
||||
internal U64
|
||||
bit_size_from_arch(Arch arch)
|
||||
{
|
||||
// TODO(rjf): metacode
|
||||
U64 arch_bitsize = 0;
|
||||
switch(arch)
|
||||
{
|
||||
case Arch_x64: arch_bitsize = 64; break;
|
||||
case Arch_x86: arch_bitsize = 32; break;
|
||||
case Arch_arm64: arch_bitsize = 64; break;
|
||||
case Arch_arm32: arch_bitsize = 32; break;
|
||||
default: break;
|
||||
}
|
||||
return arch_bitsize;
|
||||
}
|
||||
|
||||
internal U64
|
||||
max_instruction_size_from_arch(Arch arch)
|
||||
{
|
||||
// TODO(rjf): make this real
|
||||
return 64;
|
||||
}
|
||||
|
||||
internal OperatingSystem
|
||||
operating_system_from_context(void){
|
||||
OperatingSystem os = OperatingSystem_Null;
|
||||
#if OS_WINDOWS
|
||||
os = OperatingSystem_Windows;
|
||||
#elif OS_LINUX
|
||||
os = OperatingSystem_Linux;
|
||||
#elif OS_MAC
|
||||
os = OperatingSystem_Mac;
|
||||
#endif
|
||||
return os;
|
||||
}
|
||||
|
||||
internal Arch
|
||||
arch_from_context(void){
|
||||
Arch arch = Arch_Null;
|
||||
#if ARCH_X64
|
||||
arch = Arch_x64;
|
||||
#elif ARCH_X86
|
||||
arch = Arch_x86;
|
||||
#elif ARCH_ARM64
|
||||
arch = Arch_arm64;
|
||||
#elif ARCH_ARM32
|
||||
arch = Arch_arm32;
|
||||
#endif
|
||||
return arch;
|
||||
}
|
||||
|
||||
internal Compiler
|
||||
compiler_from_context(void){
|
||||
Compiler compiler = Compiler_Null;
|
||||
#if COMPILER_MSVC
|
||||
compiler = Compiler_msvc;
|
||||
#elif COMPILER_GCC
|
||||
compiler = Compiler_gcc;
|
||||
#elif COMPILER_CLANG
|
||||
compiler = Compiler_clang;
|
||||
#endif
|
||||
return compiler;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Functions
|
||||
|
||||
internal DenseTime
|
||||
dense_time_from_date_time(DateTime date_time){
|
||||
DenseTime result = 0;
|
||||
result += date_time.year;
|
||||
result *= 12;
|
||||
result += date_time.mon;
|
||||
result *= 31;
|
||||
result += date_time.day;
|
||||
result *= 24;
|
||||
result += date_time.hour;
|
||||
result *= 60;
|
||||
result += date_time.min;
|
||||
result *= 61;
|
||||
result += date_time.sec;
|
||||
result *= 1000;
|
||||
result += date_time.msec;
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal DateTime
|
||||
date_time_from_dense_time(DenseTime time){
|
||||
DateTime result = {0};
|
||||
result.msec = time%1000;
|
||||
time /= 1000;
|
||||
result.sec = time%61;
|
||||
time /= 61;
|
||||
result.min = time%60;
|
||||
time /= 60;
|
||||
result.hour = time%24;
|
||||
time /= 24;
|
||||
result.day = time%31;
|
||||
time /= 31;
|
||||
result.mon = time%12;
|
||||
time /= 12;
|
||||
Assert(time <= max_U32);
|
||||
result.year = (U32)time;
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal DateTime
|
||||
date_time_from_micro_seconds(U64 time){
|
||||
DateTime result = {0};
|
||||
result.micro_sec = time%1000;
|
||||
time /= 1000;
|
||||
result.msec = time%1000;
|
||||
time /= 1000;
|
||||
result.sec = time%60;
|
||||
time /= 60;
|
||||
result.min = time%60;
|
||||
time /= 60;
|
||||
result.hour = time%24;
|
||||
time /= 24;
|
||||
result.day = time%31;
|
||||
time /= 31;
|
||||
result.mon = time%12;
|
||||
time /= 12;
|
||||
Assert(time <= max_U32);
|
||||
result.year = (U32)time;
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal DateTime
|
||||
date_time_from_unix_time(U64 unix_time)
|
||||
{
|
||||
DateTime date = {0};
|
||||
date.year = 1970;
|
||||
date.day = 1 + (unix_time / 86400);
|
||||
date.sec = (U32)unix_time % 60;
|
||||
date.min = (U32)(unix_time / 60) % 60;
|
||||
date.hour = (U32)(unix_time / 3600) % 24;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
for(date.month = 0; date.month < 12; ++date.month)
|
||||
{
|
||||
U64 c = 0;
|
||||
switch(date.month)
|
||||
{
|
||||
case Month_Jan: c = 31; break;
|
||||
case Month_Feb:
|
||||
{
|
||||
if((date.year % 4 == 0) && ((date.year % 100) != 0 || (date.year % 400) == 0))
|
||||
{
|
||||
c = 29;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = 28;
|
||||
}
|
||||
} break;
|
||||
case Month_Mar: c = 31; break;
|
||||
case Month_Apr: c = 30; break;
|
||||
case Month_May: c = 31; break;
|
||||
case Month_Jun: c = 30; break;
|
||||
case Month_Jul: c = 31; break;
|
||||
case Month_Aug: c = 31; break;
|
||||
case Month_Sep: c = 30; break;
|
||||
case Month_Oct: c = 31; break;
|
||||
case Month_Nov: c = 30; break;
|
||||
case Month_Dec: c = 31; break;
|
||||
default: InvalidPath;
|
||||
}
|
||||
if(date.day <= c)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
date.day -= c;
|
||||
}
|
||||
++date.year;
|
||||
}
|
||||
exit:;
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
|
||||
|
||||
internal U64
|
||||
ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
|
||||
{
|
||||
Assert(src_data_size <= ring_size);
|
||||
{
|
||||
U64 ring_off = ring_pos%ring_size;
|
||||
U64 bytes_before_split = ring_size-ring_off;
|
||||
U64 pre_split_bytes = Min(bytes_before_split, src_data_size);
|
||||
U64 pst_split_bytes = src_data_size-pre_split_bytes;
|
||||
void *pre_split_data = src_data;
|
||||
void *pst_split_data = ((U8 *)src_data + pre_split_bytes);
|
||||
MemoryCopy(ring_base+ring_off, pre_split_data, pre_split_bytes);
|
||||
MemoryCopy(ring_base+0, pst_split_data, pst_split_bytes);
|
||||
}
|
||||
return src_data_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
|
||||
{
|
||||
Assert(read_size <= ring_size);
|
||||
{
|
||||
U64 ring_off = ring_pos%ring_size;
|
||||
U64 bytes_before_split = ring_size-ring_off;
|
||||
U64 pre_split_bytes = Min(bytes_before_split, read_size);
|
||||
U64 pst_split_bytes = read_size-pre_split_bytes;
|
||||
MemoryCopy(dst_data, ring_base+ring_off, pre_split_bytes);
|
||||
MemoryCopy((U8 *)dst_data + pre_split_bytes, ring_base+0, pst_split_bytes);
|
||||
}
|
||||
return read_size;
|
||||
}
|
||||
888
src/metagen/metagen_base/metagen_base_core.h
Normal file
888
src/metagen/metagen_base/metagen_base_core.h
Normal file
@ -0,0 +1,888 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_CORE_H
|
||||
#define BASE_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Foreign Includes
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Codebase Keywords
|
||||
|
||||
#define internal static
|
||||
#define global static
|
||||
#define local_persist static
|
||||
|
||||
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
|
||||
# pragma section(".rdata$", read)
|
||||
# define read_only __declspec(allocate(".rdata$"))
|
||||
#elif (COMPILER_CLANG && OS_LINUX)
|
||||
# define read_only __attribute__((section(".rodata")))
|
||||
#else
|
||||
// NOTE(rjf): I don't know of a useful way to do this in GCC land.
|
||||
// __attribute__((section(".rodata"))) looked promising, but it introduces a
|
||||
// strange warning about malformed section attributes, and it doesn't look
|
||||
// like writing to that section reliably produces access violations, strangely
|
||||
// enough. (It does on Clang)
|
||||
# define read_only
|
||||
#endif
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# define thread_static __declspec(thread)
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
# define thread_static __thread
|
||||
#endif
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# define force_inline __forceinline
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
# define force_inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Linkage Keyword Macros
|
||||
|
||||
#if OS_WINDOWS
|
||||
# define shared_function C_LINKAGE __declspec(dllexport)
|
||||
#else
|
||||
# define shared_function C_LINKAGE
|
||||
#endif
|
||||
|
||||
#if LANG_CPP
|
||||
# define C_LINKAGE_BEGIN extern "C"{
|
||||
# define C_LINKAGE_END }
|
||||
# define C_LINKAGE extern "C"
|
||||
#else
|
||||
# define C_LINKAGE_BEGIN
|
||||
# define C_LINKAGE_END
|
||||
# define C_LINKAGE
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Units
|
||||
|
||||
#define KB(n) (((U64)(n)) << 10)
|
||||
#define MB(n) (((U64)(n)) << 20)
|
||||
#define GB(n) (((U64)(n)) << 30)
|
||||
#define TB(n) (((U64)(n)) << 40)
|
||||
#define Thousand(n) ((n)*1000)
|
||||
#define Million(n) ((n)*1000000)
|
||||
#define Billion(n) ((n)*1000000000)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Branch Predictor Hints
|
||||
|
||||
#if defined(__clang__)
|
||||
# define Expect(expr, val) __builtin_expect((expr), (val))
|
||||
#else
|
||||
# define Expect(expr, val) (expr)
|
||||
#endif
|
||||
|
||||
#define Likely(expr) Expect(expr,1)
|
||||
#define Unlikely(expr) Expect(expr,0)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Clamps, Mins, Maxes
|
||||
|
||||
#define Min(A,B) (((A)<(B))?(A):(B))
|
||||
#define Max(A,B) (((A)>(B))?(A):(B))
|
||||
#define ClampTop(A,X) Min(A,X)
|
||||
#define ClampBot(X,B) Max(X,B)
|
||||
#define Clamp(A,X,B) (((X)<(A))?(A):((X)>(B))?(B):(X))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type -> Alignment
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# define AlignOf(T) __alignof(T)
|
||||
#elif COMPILER_CLANG
|
||||
# define AlignOf(T) __alignof(T)
|
||||
#elif COMPILER_GCC
|
||||
# define AlignOf(T) __alignof__(T)
|
||||
#else
|
||||
# error AlignOf not defined for this compiler.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Member Offsets
|
||||
|
||||
#define Member(T,m) (((T*)0)->m)
|
||||
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
|
||||
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
|
||||
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: For-Loop Construct Macros
|
||||
|
||||
#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end))
|
||||
#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
|
||||
|
||||
#define EachIndex(it, count) (U64 it = 0; it < (count); it += 1)
|
||||
#define EachElement(it, array) (U64 it = 0; it < ArrayCount(array); it += 1)
|
||||
#define EachEnumVal(type, it) (type it = (type)0; it < type##_COUNT; it = (type)(it+1))
|
||||
#define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Memory Operation Macros
|
||||
|
||||
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
|
||||
#define MemorySet(dst, byte, size) memset((dst), (byte), (size))
|
||||
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
|
||||
#define MemoryStrlen(ptr) strlen(ptr)
|
||||
|
||||
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d)))
|
||||
#define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d))
|
||||
#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),sizeof(*(d))*(c))
|
||||
|
||||
#define MemoryZero(s,z) memset((s),0,(z))
|
||||
#define MemoryZeroStruct(s) MemoryZero((s),sizeof(*(s)))
|
||||
#define MemoryZeroArray(a) MemoryZero((a),sizeof(a))
|
||||
#define MemoryZeroTyped(m,c) MemoryZero((m),sizeof(*(m))*(c))
|
||||
|
||||
#define MemoryMatch(a,b,z) (MemoryCompare((a),(b),(z)) == 0)
|
||||
#define MemoryMatchStruct(a,b) MemoryMatch((a),(b),sizeof(*(a)))
|
||||
#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a))
|
||||
|
||||
#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) )
|
||||
#define MemoryConsume(T,p,e) ( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) )
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asserts
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# define Trap() __debugbreak()
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
# define Trap() __builtin_trap()
|
||||
#else
|
||||
# error Unknown trap intrinsic for this compiler.
|
||||
#endif
|
||||
|
||||
#define AssertAlways(x) do{if(!(x)) {Trap();}}while(0)
|
||||
#if BUILD_DEBUG
|
||||
# define Assert(x) AssertAlways(x)
|
||||
#else
|
||||
# define Assert(x) (void)(x)
|
||||
#endif
|
||||
#define InvalidPath Assert(!"Invalid Path!")
|
||||
#define NotImplemented Assert(!"Not Implemented!")
|
||||
#define NoOp ((void)0)
|
||||
#define StaticAssert(C, ID) global U8 Glue(ID, __LINE__)[(C)?1:-1]
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Atomic Operations
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# include <intrin.h>
|
||||
# if ARCH_X64
|
||||
# define ins_atomic_u64_eval(x) *((volatile U64 *)(x))
|
||||
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
|
||||
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c)
|
||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((volatile __int64 *)(x),(k),(c))
|
||||
# define ins_atomic_u32_eval(x) *((volatile U32 *)(x))
|
||||
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)x)
|
||||
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
|
||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
|
||||
# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
|
||||
# else
|
||||
# error Atomic intrinsics not defined for this compiler / architecture combination.
|
||||
# endif
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
# define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
|
||||
# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
|
||||
# define ins_atomic_u64_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u64_add_eval(x,c) (__atomic_fetch_add((volatile U64 *)(x), c, __ATOMIC_SEQ_CST) + (c))
|
||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((volatile U64 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
|
||||
# define ins_atomic_u32_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u32_inc_eval(x) (__atomic_fetch_add((volatile U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
|
||||
# define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((volatile U32 *)(x), c, __ATOMIC_SEQ_CST) + (c))
|
||||
# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((volatile U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
|
||||
#else
|
||||
# error Atomic intrinsics not defined for this compiler / architecture.
|
||||
#endif
|
||||
|
||||
#if ARCH_64BIT
|
||||
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u64_eval_cond_assign((volatile U64 *)(x), (U64)(k), (U64)(c))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile U64 *)(x), (U64)(c))
|
||||
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u64_eval((volatile U64 *)x)
|
||||
#elif ARCH_32BIT
|
||||
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u32_eval_cond_assign((volatile U32 *)(x), (U32)(k), (U32)(c))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u32_eval_assign((volatile U32 *)(x), (U32)(c))
|
||||
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u32_eval((volatile U32 *)x)
|
||||
#else
|
||||
# error Atomic intrinsics for pointers not defined for this architecture.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Linked List Building Macros
|
||||
|
||||
//- rjf: linked list macro helpers
|
||||
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
|
||||
#define SetNil(nil,p) ((p) = nil)
|
||||
|
||||
//- rjf: doubly-linked-lists
|
||||
#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
|
||||
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
|
||||
CheckNil(nil,p) ? \
|
||||
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
|
||||
((p)==(l)) ? \
|
||||
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
|
||||
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
|
||||
#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev)
|
||||
#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next)
|
||||
#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
|
||||
((n) == (l) ? (l) = (l)->prev : (0)),\
|
||||
(CheckNil(nil,(n)->prev) ? (0) :\
|
||||
((n)->prev->next = (n)->next)),\
|
||||
(CheckNil(nil,(n)->next) ? (0) :\
|
||||
((n)->next->prev = (n)->prev)))
|
||||
|
||||
//- rjf: singly-linked, doubly-headed lists (queues)
|
||||
#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
|
||||
#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||
((n)->next=(f),(f)=(n)))
|
||||
#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
|
||||
(SetNil(nil,f),SetNil(nil,l)):\
|
||||
((f)=(f)->next))
|
||||
|
||||
//- rjf: singly-linked, singly-headed lists (stacks)
|
||||
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
|
||||
#define SLLStackPop_N(f,next) ((f)=(f)->next)
|
||||
|
||||
//- rjf: doubly-linked-list helpers
|
||||
#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
||||
#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
||||
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
||||
#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev)
|
||||
|
||||
//- rjf: singly-linked, doubly-headed list helpers
|
||||
#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next)
|
||||
#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next)
|
||||
#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next)
|
||||
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next)
|
||||
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next)
|
||||
#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next)
|
||||
|
||||
//- rjf: singly-linked, singly-headed list helpers
|
||||
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
|
||||
#define SLLStackPop(f) SLLStackPop_N(f,next)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Address Sanitizer Markup
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# if defined(__SANITIZE_ADDRESS__)
|
||||
# define ASAN_ENABLED 1
|
||||
# define NO_ASAN __declspec(no_sanitize_address)
|
||||
# else
|
||||
# define NO_ASAN
|
||||
# endif
|
||||
#elif COMPILER_CLANG
|
||||
# if defined(__has_feature)
|
||||
# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
# define ASAN_ENABLED 1
|
||||
# endif
|
||||
# endif
|
||||
# define NO_ASAN __attribute__((no_sanitize("address")))
|
||||
#else
|
||||
# define NO_ASAN
|
||||
#endif
|
||||
|
||||
#if ASAN_ENABLED
|
||||
#pragma comment(lib, "clang_rt.asan-x86_64.lib")
|
||||
C_LINKAGE void __asan_poison_memory_region(void const volatile *addr, size_t size);
|
||||
C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
|
||||
# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size))
|
||||
# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size))
|
||||
#else
|
||||
# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
|
||||
# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Misc. Helper Macros
|
||||
|
||||
#define Stringify_(S) #S
|
||||
#define Stringify(S) Stringify_(S)
|
||||
|
||||
#define Glue_(A,B) A##B
|
||||
#define Glue(A,B) Glue_(A,B)
|
||||
|
||||
#define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b))
|
||||
|
||||
#define Swap(T,a,b) do{T t__ = a; a = b; b = t__;}while(0)
|
||||
|
||||
#if ARCH_64BIT
|
||||
# define IntFromPtr(ptr) ((U64)(ptr))
|
||||
#elif ARCH_32BIT
|
||||
# define IntFromPtr(ptr) ((U32)(ptr))
|
||||
#else
|
||||
# error Missing pointer-to-integer cast for this architecture.
|
||||
#endif
|
||||
#define PtrFromInt(i) (void*)((U8*)0 + (i))
|
||||
|
||||
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b));
|
||||
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
|
||||
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
|
||||
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
|
||||
#define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0)
|
||||
#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0)
|
||||
|
||||
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
|
||||
|
||||
#if LANG_CPP
|
||||
# define zero_struct {}
|
||||
#else
|
||||
# define zero_struct {0}
|
||||
#endif
|
||||
|
||||
#if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015
|
||||
# define this_function_name "unknown"
|
||||
#else
|
||||
# define this_function_name __func__
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Types
|
||||
|
||||
typedef uint8_t U8;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef uint64_t U64;
|
||||
typedef int8_t S8;
|
||||
typedef int16_t S16;
|
||||
typedef int32_t S32;
|
||||
typedef int64_t S64;
|
||||
typedef S8 B8;
|
||||
typedef S16 B16;
|
||||
typedef S32 B32;
|
||||
typedef S64 B64;
|
||||
typedef float F32;
|
||||
typedef double F64;
|
||||
typedef void VoidProc(void);
|
||||
typedef struct U128 U128;
|
||||
struct U128
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Spaces
|
||||
|
||||
typedef enum Dimension
|
||||
{
|
||||
Dimension_X,
|
||||
Dimension_Y,
|
||||
Dimension_Z,
|
||||
Dimension_W,
|
||||
}
|
||||
Dimension;
|
||||
|
||||
typedef enum Side
|
||||
{
|
||||
Side_Invalid = -1,
|
||||
Side_Min,
|
||||
Side_Max,
|
||||
Side_COUNT,
|
||||
}
|
||||
Side;
|
||||
#define side_flip(s) ((Side)(!(s)))
|
||||
|
||||
typedef enum Axis2
|
||||
{
|
||||
Axis2_Invalid = -1,
|
||||
Axis2_X,
|
||||
Axis2_Y,
|
||||
Axis2_COUNT,
|
||||
}
|
||||
Axis2;
|
||||
#define axis2_flip(a) ((Axis2)(!(a)))
|
||||
|
||||
typedef enum Corner
|
||||
{
|
||||
Corner_Invalid = -1,
|
||||
Corner_00,
|
||||
Corner_01,
|
||||
Corner_10,
|
||||
Corner_11,
|
||||
Corner_COUNT
|
||||
}
|
||||
Corner;
|
||||
|
||||
typedef enum Dir2
|
||||
{
|
||||
Dir2_Invalid = -1,
|
||||
Dir2_Left,
|
||||
Dir2_Up,
|
||||
Dir2_Right,
|
||||
Dir2_Down,
|
||||
Dir2_COUNT
|
||||
}
|
||||
Dir2;
|
||||
#define axis2_from_dir2(d) (((d) & 1) ? Axis2_Y : Axis2_X)
|
||||
#define side_from_dir2(d) (((d) < Dir2_Right) ? Side_Min : Side_Max)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Toolchain/Environment Enums
|
||||
|
||||
typedef enum OperatingSystem
|
||||
{
|
||||
OperatingSystem_Null,
|
||||
OperatingSystem_Windows,
|
||||
OperatingSystem_Linux,
|
||||
OperatingSystem_Mac,
|
||||
OperatingSystem_COUNT,
|
||||
}
|
||||
OperatingSystem;
|
||||
|
||||
typedef enum ImageType
|
||||
{
|
||||
Image_Null,
|
||||
Image_CoffPe,
|
||||
Image_Elf32,
|
||||
Image_Elf64,
|
||||
Image_Macho
|
||||
} ImageType;
|
||||
|
||||
typedef enum Arch
|
||||
{
|
||||
Arch_Null,
|
||||
Arch_x64,
|
||||
Arch_x86,
|
||||
Arch_arm64,
|
||||
Arch_arm32,
|
||||
Arch_COUNT,
|
||||
}
|
||||
Arch;
|
||||
|
||||
typedef enum Compiler
|
||||
{
|
||||
Compiler_Null,
|
||||
Compiler_msvc,
|
||||
Compiler_gcc,
|
||||
Compiler_clang,
|
||||
Compiler_COUNT,
|
||||
}
|
||||
Compiler;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text 2D Coordinates & Ranges
|
||||
|
||||
typedef struct TxtPt TxtPt;
|
||||
struct TxtPt
|
||||
{
|
||||
S64 line;
|
||||
S64 column;
|
||||
};
|
||||
|
||||
typedef struct TxtRng TxtRng;
|
||||
struct TxtRng
|
||||
{
|
||||
TxtPt min;
|
||||
TxtPt max;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Globally Unique Ids
|
||||
|
||||
typedef union Guid Guid;
|
||||
union Guid
|
||||
{
|
||||
struct
|
||||
{
|
||||
U32 data1;
|
||||
U16 data2;
|
||||
U16 data3;
|
||||
U8 data4[8];
|
||||
};
|
||||
U8 v[16];
|
||||
};
|
||||
StaticAssert(sizeof(Guid) == 16, g_guid_size_check);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Arrays
|
||||
|
||||
typedef struct U16Array U16Array;
|
||||
struct U16Array
|
||||
{
|
||||
U64 count;
|
||||
U16 *v;
|
||||
};
|
||||
typedef struct U32Array U32Array;
|
||||
struct U32Array
|
||||
{
|
||||
U64 count;
|
||||
U32 *v;
|
||||
};
|
||||
typedef struct U64Array U64Array;
|
||||
struct U64Array
|
||||
{
|
||||
U64 count;
|
||||
U64 *v;
|
||||
};
|
||||
typedef struct U128Array U128Array;
|
||||
struct U128Array
|
||||
{
|
||||
U64 count;
|
||||
U128 *v;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Constants
|
||||
|
||||
global U32 sign32 = 0x80000000;
|
||||
global U32 exponent32 = 0x7F800000;
|
||||
global U32 mantissa32 = 0x007FFFFF;
|
||||
|
||||
global F32 big_golden32 = 1.61803398875f;
|
||||
global F32 small_golden32 = 0.61803398875f;
|
||||
|
||||
global F32 pi32 = 3.1415926535897f;
|
||||
|
||||
global F64 machine_epsilon64 = 4.94065645841247e-324;
|
||||
|
||||
global U64 max_U64 = 0xffffffffffffffffull;
|
||||
global U32 max_U32 = 0xffffffff;
|
||||
global U16 max_U16 = 0xffff;
|
||||
global U8 max_U8 = 0xff;
|
||||
|
||||
global S64 max_S64 = (S64)0x7fffffffffffffffull;
|
||||
global S32 max_S32 = (S32)0x7fffffff;
|
||||
global S16 max_S16 = (S16)0x7fff;
|
||||
global S8 max_S8 = (S8)0x7f;
|
||||
|
||||
global S64 min_S64 = (S64)0xffffffffffffffffull;
|
||||
global S32 min_S32 = (S32)0xffffffff;
|
||||
global S16 min_S16 = (S16)0xffff;
|
||||
global S8 min_S8 = (S8)0xff;
|
||||
|
||||
global const U32 bitmask1 = 0x00000001;
|
||||
global const U32 bitmask2 = 0x00000003;
|
||||
global const U32 bitmask3 = 0x00000007;
|
||||
global const U32 bitmask4 = 0x0000000f;
|
||||
global const U32 bitmask5 = 0x0000001f;
|
||||
global const U32 bitmask6 = 0x0000003f;
|
||||
global const U32 bitmask7 = 0x0000007f;
|
||||
global const U32 bitmask8 = 0x000000ff;
|
||||
global const U32 bitmask9 = 0x000001ff;
|
||||
global const U32 bitmask10 = 0x000003ff;
|
||||
global const U32 bitmask11 = 0x000007ff;
|
||||
global const U32 bitmask12 = 0x00000fff;
|
||||
global const U32 bitmask13 = 0x00001fff;
|
||||
global const U32 bitmask14 = 0x00003fff;
|
||||
global const U32 bitmask15 = 0x00007fff;
|
||||
global const U32 bitmask16 = 0x0000ffff;
|
||||
global const U32 bitmask17 = 0x0001ffff;
|
||||
global const U32 bitmask18 = 0x0003ffff;
|
||||
global const U32 bitmask19 = 0x0007ffff;
|
||||
global const U32 bitmask20 = 0x000fffff;
|
||||
global const U32 bitmask21 = 0x001fffff;
|
||||
global const U32 bitmask22 = 0x003fffff;
|
||||
global const U32 bitmask23 = 0x007fffff;
|
||||
global const U32 bitmask24 = 0x00ffffff;
|
||||
global const U32 bitmask25 = 0x01ffffff;
|
||||
global const U32 bitmask26 = 0x03ffffff;
|
||||
global const U32 bitmask27 = 0x07ffffff;
|
||||
global const U32 bitmask28 = 0x0fffffff;
|
||||
global const U32 bitmask29 = 0x1fffffff;
|
||||
global const U32 bitmask30 = 0x3fffffff;
|
||||
global const U32 bitmask31 = 0x7fffffff;
|
||||
global const U32 bitmask32 = 0xffffffff;
|
||||
|
||||
global const U64 bitmask33 = 0x00000001ffffffffull;
|
||||
global const U64 bitmask34 = 0x00000003ffffffffull;
|
||||
global const U64 bitmask35 = 0x00000007ffffffffull;
|
||||
global const U64 bitmask36 = 0x0000000fffffffffull;
|
||||
global const U64 bitmask37 = 0x0000001fffffffffull;
|
||||
global const U64 bitmask38 = 0x0000003fffffffffull;
|
||||
global const U64 bitmask39 = 0x0000007fffffffffull;
|
||||
global const U64 bitmask40 = 0x000000ffffffffffull;
|
||||
global const U64 bitmask41 = 0x000001ffffffffffull;
|
||||
global const U64 bitmask42 = 0x000003ffffffffffull;
|
||||
global const U64 bitmask43 = 0x000007ffffffffffull;
|
||||
global const U64 bitmask44 = 0x00000fffffffffffull;
|
||||
global const U64 bitmask45 = 0x00001fffffffffffull;
|
||||
global const U64 bitmask46 = 0x00003fffffffffffull;
|
||||
global const U64 bitmask47 = 0x00007fffffffffffull;
|
||||
global const U64 bitmask48 = 0x0000ffffffffffffull;
|
||||
global const U64 bitmask49 = 0x0001ffffffffffffull;
|
||||
global const U64 bitmask50 = 0x0003ffffffffffffull;
|
||||
global const U64 bitmask51 = 0x0007ffffffffffffull;
|
||||
global const U64 bitmask52 = 0x000fffffffffffffull;
|
||||
global const U64 bitmask53 = 0x001fffffffffffffull;
|
||||
global const U64 bitmask54 = 0x003fffffffffffffull;
|
||||
global const U64 bitmask55 = 0x007fffffffffffffull;
|
||||
global const U64 bitmask56 = 0x00ffffffffffffffull;
|
||||
global const U64 bitmask57 = 0x01ffffffffffffffull;
|
||||
global const U64 bitmask58 = 0x03ffffffffffffffull;
|
||||
global const U64 bitmask59 = 0x07ffffffffffffffull;
|
||||
global const U64 bitmask60 = 0x0fffffffffffffffull;
|
||||
global const U64 bitmask61 = 0x1fffffffffffffffull;
|
||||
global const U64 bitmask62 = 0x3fffffffffffffffull;
|
||||
global const U64 bitmask63 = 0x7fffffffffffffffull;
|
||||
global const U64 bitmask64 = 0xffffffffffffffffull;
|
||||
|
||||
global const U32 bit1 = (1<<0);
|
||||
global const U32 bit2 = (1<<1);
|
||||
global const U32 bit3 = (1<<2);
|
||||
global const U32 bit4 = (1<<3);
|
||||
global const U32 bit5 = (1<<4);
|
||||
global const U32 bit6 = (1<<5);
|
||||
global const U32 bit7 = (1<<6);
|
||||
global const U32 bit8 = (1<<7);
|
||||
global const U32 bit9 = (1<<8);
|
||||
global const U32 bit10 = (1<<9);
|
||||
global const U32 bit11 = (1<<10);
|
||||
global const U32 bit12 = (1<<11);
|
||||
global const U32 bit13 = (1<<12);
|
||||
global const U32 bit14 = (1<<13);
|
||||
global const U32 bit15 = (1<<14);
|
||||
global const U32 bit16 = (1<<15);
|
||||
global const U32 bit17 = (1<<16);
|
||||
global const U32 bit18 = (1<<17);
|
||||
global const U32 bit19 = (1<<18);
|
||||
global const U32 bit20 = (1<<19);
|
||||
global const U32 bit21 = (1<<20);
|
||||
global const U32 bit22 = (1<<21);
|
||||
global const U32 bit23 = (1<<22);
|
||||
global const U32 bit24 = (1<<23);
|
||||
global const U32 bit25 = (1<<24);
|
||||
global const U32 bit26 = (1<<25);
|
||||
global const U32 bit27 = (1<<26);
|
||||
global const U32 bit28 = (1<<27);
|
||||
global const U32 bit29 = (1<<28);
|
||||
global const U32 bit30 = (1<<29);
|
||||
global const U32 bit31 = (1<<30);
|
||||
global const U32 bit32 = (1<<31);
|
||||
|
||||
global const U64 bit33 = (1ull<<32);
|
||||
global const U64 bit34 = (1ull<<33);
|
||||
global const U64 bit35 = (1ull<<34);
|
||||
global const U64 bit36 = (1ull<<35);
|
||||
global const U64 bit37 = (1ull<<36);
|
||||
global const U64 bit38 = (1ull<<37);
|
||||
global const U64 bit39 = (1ull<<38);
|
||||
global const U64 bit40 = (1ull<<39);
|
||||
global const U64 bit41 = (1ull<<40);
|
||||
global const U64 bit42 = (1ull<<41);
|
||||
global const U64 bit43 = (1ull<<42);
|
||||
global const U64 bit44 = (1ull<<43);
|
||||
global const U64 bit45 = (1ull<<44);
|
||||
global const U64 bit46 = (1ull<<45);
|
||||
global const U64 bit47 = (1ull<<46);
|
||||
global const U64 bit48 = (1ull<<47);
|
||||
global const U64 bit49 = (1ull<<48);
|
||||
global const U64 bit50 = (1ull<<49);
|
||||
global const U64 bit51 = (1ull<<50);
|
||||
global const U64 bit52 = (1ull<<51);
|
||||
global const U64 bit53 = (1ull<<52);
|
||||
global const U64 bit54 = (1ull<<53);
|
||||
global const U64 bit55 = (1ull<<54);
|
||||
global const U64 bit56 = (1ull<<55);
|
||||
global const U64 bit57 = (1ull<<56);
|
||||
global const U64 bit58 = (1ull<<57);
|
||||
global const U64 bit59 = (1ull<<58);
|
||||
global const U64 bit60 = (1ull<<59);
|
||||
global const U64 bit61 = (1ull<<60);
|
||||
global const U64 bit62 = (1ull<<61);
|
||||
global const U64 bit63 = (1ull<<62);
|
||||
global const U64 bit64 = (1ull<<63);
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Time
|
||||
|
||||
typedef enum WeekDay
|
||||
{
|
||||
WeekDay_Sun,
|
||||
WeekDay_Mon,
|
||||
WeekDay_Tue,
|
||||
WeekDay_Wed,
|
||||
WeekDay_Thu,
|
||||
WeekDay_Fri,
|
||||
WeekDay_Sat,
|
||||
WeekDay_COUNT,
|
||||
}
|
||||
WeekDay;
|
||||
|
||||
typedef enum Month
|
||||
{
|
||||
Month_Jan,
|
||||
Month_Feb,
|
||||
Month_Mar,
|
||||
Month_Apr,
|
||||
Month_May,
|
||||
Month_Jun,
|
||||
Month_Jul,
|
||||
Month_Aug,
|
||||
Month_Sep,
|
||||
Month_Oct,
|
||||
Month_Nov,
|
||||
Month_Dec,
|
||||
Month_COUNT,
|
||||
}
|
||||
Month;
|
||||
|
||||
typedef struct DateTime DateTime;
|
||||
struct DateTime
|
||||
{
|
||||
U16 micro_sec; // [0,999]
|
||||
U16 msec; // [0,999]
|
||||
U16 sec; // [0,60]
|
||||
U16 min; // [0,59]
|
||||
U16 hour; // [0,24]
|
||||
U16 day; // [0,30]
|
||||
union
|
||||
{
|
||||
WeekDay week_day;
|
||||
U32 wday;
|
||||
};
|
||||
union
|
||||
{
|
||||
Month month;
|
||||
U32 mon;
|
||||
};
|
||||
U32 year; // 1 = 1 CE, 0 = 1 BC
|
||||
};
|
||||
|
||||
typedef U64 DenseTime;
|
||||
|
||||
////////////////////////////////
|
||||
//~ allen: Files
|
||||
|
||||
typedef U32 FilePropertyFlags;
|
||||
enum
|
||||
{
|
||||
FilePropertyFlag_IsFolder = (1 << 0),
|
||||
};
|
||||
|
||||
typedef struct FileProperties FileProperties;
|
||||
struct FileProperties
|
||||
{
|
||||
U64 size;
|
||||
DenseTime modified;
|
||||
DenseTime created;
|
||||
FilePropertyFlags flags;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Safe Casts
|
||||
|
||||
internal U16 safe_cast_u16(U32 x);
|
||||
internal U32 safe_cast_u32(U64 x);
|
||||
internal S32 safe_cast_s32(S64 x);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Large Base Type Functions
|
||||
|
||||
internal U128 u128_zero(void);
|
||||
internal U128 u128_make(U64 v0, U64 v1);
|
||||
internal B32 u128_match(U128 a, U128 b);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bit Patterns
|
||||
|
||||
internal U32 u32_from_u64_saturate(U64 x);
|
||||
internal U64 u64_up_to_pow2(U64 x);
|
||||
internal S32 extend_sign32(U32 x, U32 size);
|
||||
internal S64 extend_sign64(U64 x, U64 size);
|
||||
|
||||
internal F32 inf32(void);
|
||||
internal F32 neg_inf32(void);
|
||||
|
||||
internal U16 bswap_u16(U16 x);
|
||||
internal U32 bswap_u32(U32 x);
|
||||
internal U64 bswap_u64(U64 x);
|
||||
|
||||
#if ARCH_LITTLE_ENDIAN
|
||||
# define from_be_u16(x) bswap_u16(x)
|
||||
# define from_be_u32(x) bswap_u32(x)
|
||||
# define from_be_u64(x) bswap_u64(x)
|
||||
#else
|
||||
# define from_be_u16(x) (x)
|
||||
# define from_be_u32(x) (x)
|
||||
# define from_be_u64(x) (x)
|
||||
#endif
|
||||
|
||||
internal U64 count_bits_set32(U32 val);
|
||||
internal U64 count_bits_set64(U64 val);
|
||||
|
||||
internal U64 ctz32(U32 val);
|
||||
internal U64 ctz64(U64 val);
|
||||
internal U64 clz32(U32 val);
|
||||
internal U64 clz64(U64 val);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Enum -> Sign
|
||||
|
||||
internal S32 sign_from_side_S32(Side side);
|
||||
internal F32 sign_from_side_F32(Side side);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Memory Functions
|
||||
|
||||
internal B32 memory_is_zero(void *ptr, U64 size);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text 2D Coordinate/Range Functions
|
||||
|
||||
internal TxtPt txt_pt(S64 line, S64 column);
|
||||
internal B32 txt_pt_match(TxtPt a, TxtPt b);
|
||||
internal B32 txt_pt_less_than(TxtPt a, TxtPt b);
|
||||
internal TxtPt txt_pt_min(TxtPt a, TxtPt b);
|
||||
internal TxtPt txt_pt_max(TxtPt a, TxtPt b);
|
||||
internal TxtRng txt_rng(TxtPt min, TxtPt max);
|
||||
internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b);
|
||||
internal TxtRng txt_rng_union(TxtRng a, TxtRng b);
|
||||
internal B32 txt_rng_contains(TxtRng r, TxtPt pt);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Toolchain/Environment Enum Functions
|
||||
|
||||
internal U64 bit_size_from_arch(Arch arch);
|
||||
internal U64 max_instruction_size_from_arch(Arch arch);
|
||||
|
||||
internal OperatingSystem operating_system_from_context(void);
|
||||
internal Arch arch_from_context(void);
|
||||
internal Compiler compiler_from_context(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Functions
|
||||
|
||||
internal DenseTime dense_time_from_date_time(DateTime date_time);
|
||||
internal DateTime date_time_from_dense_time(DenseTime time);
|
||||
internal DateTime date_time_from_micro_seconds(U64 time);
|
||||
internal DateTime date_time_from_unix_time(U64 unix_time);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
|
||||
|
||||
internal U64 ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size);
|
||||
internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size);
|
||||
#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
||||
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Sorts
|
||||
|
||||
#define quick_sort(ptr, count, element_size, cmp_function) qsort((ptr), (count), (element_size), (int (*)(const void *, const void *))(cmp_function))
|
||||
|
||||
#endif // BASE_CORE_H
|
||||
130
src/metagen/metagen_base/metagen_base_entry_point.c
Normal file
130
src/metagen/metagen_base/metagen_base_entry_point.c
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
global U64 global_update_tick_idx = 0;
|
||||
|
||||
internal void
|
||||
main_thread_base_entry_point(int arguments_count, char **arguments)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
ThreadNameF("[main thread]");
|
||||
|
||||
//- rjf: set up telemetry
|
||||
#if PROFILE_TELEMETRY
|
||||
local_persist char tm_data[MB(64)];
|
||||
tmLoadLibrary(TM_RELEASE);
|
||||
tmSetMaxThreadCount(256);
|
||||
tmInitialize(sizeof(tm_data), tm_data);
|
||||
#endif
|
||||
|
||||
//- rjf: parse command line
|
||||
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, arguments_count, arguments);
|
||||
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
|
||||
|
||||
//- rjf: begin captures
|
||||
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
|
||||
if(capture)
|
||||
{
|
||||
ProfBeginCapture(arguments[0]);
|
||||
}
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
tmMessage(0, TMMF_ICON_NOTE, BUILD_TITLE);
|
||||
#endif
|
||||
|
||||
//- rjf: initialize all included layers
|
||||
#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
|
||||
async_init(&cmdline);
|
||||
#endif
|
||||
#if defined(RDI_FROM_PDB_H) && !defined(P2R_INIT_MANUAL)
|
||||
p2r_init();
|
||||
#endif
|
||||
#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL)
|
||||
hs_init();
|
||||
#endif
|
||||
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
|
||||
fs_init();
|
||||
#endif
|
||||
#if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL)
|
||||
txt_init();
|
||||
#endif
|
||||
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
|
||||
mtx_init();
|
||||
#endif
|
||||
#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL)
|
||||
dasm_init();
|
||||
#endif
|
||||
#if defined(DBGI_H) && !defined(DI_INIT_MANUAL)
|
||||
di_init();
|
||||
#endif
|
||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
||||
dmn_init();
|
||||
#endif
|
||||
#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL)
|
||||
ctrl_init();
|
||||
#endif
|
||||
#if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL)
|
||||
os_gfx_init();
|
||||
#endif
|
||||
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
|
||||
fp_init();
|
||||
#endif
|
||||
#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL)
|
||||
r_init(&cmdline);
|
||||
#endif
|
||||
#if defined(TEXTURE_CACHE_H) && !defined(TEX_INIT_MANUAL)
|
||||
tex_init();
|
||||
#endif
|
||||
#if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL)
|
||||
geo_init();
|
||||
#endif
|
||||
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
|
||||
fnt_init();
|
||||
#endif
|
||||
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
|
||||
d_init();
|
||||
#endif
|
||||
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
|
||||
rd_init(&cmdline);
|
||||
#endif
|
||||
|
||||
//- rjf: call into entry point
|
||||
entry_point(&cmdline);
|
||||
|
||||
//- rjf: end captures
|
||||
if(capture)
|
||||
{
|
||||
ProfEndCapture();
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params)
|
||||
{
|
||||
TCTX tctx;
|
||||
tctx_init_and_equip(&tctx);
|
||||
entry_point(params);
|
||||
tctx_release();
|
||||
}
|
||||
|
||||
internal U64
|
||||
update_tick_idx(void)
|
||||
{
|
||||
U64 result = ins_atomic_u64_eval(&global_update_tick_idx);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
update(void)
|
||||
{
|
||||
ProfTick(0);
|
||||
ins_atomic_u64_inc_eval(&global_update_tick_idx);
|
||||
#if OS_FEATURE_GRAPHICAL
|
||||
B32 result = frame();
|
||||
#else
|
||||
B32 result = 0;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
12
src/metagen/metagen_base/metagen_base_entry_point.h
Normal file
12
src/metagen/metagen_base/metagen_base_entry_point.h
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_ENTRY_POINT_H
|
||||
#define BASE_ENTRY_POINT_H
|
||||
|
||||
internal void main_thread_base_entry_point(int argc, char **argv);
|
||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
||||
internal U64 update_tick_idx(void);
|
||||
internal B32 update(void);
|
||||
|
||||
#endif // BASE_ENTRY_POINT_H
|
||||
20
src/metagen/metagen_base/metagen_base_inc.c
Normal file
20
src/metagen/metagen_base/metagen_base_inc.c
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#undef MARKUP_LAYER_COLOR
|
||||
#define MARKUP_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
||||
|
||||
#include "metagen_base_core.c"
|
||||
#include "metagen_base_profile.c"
|
||||
#include "metagen_base_arena.c"
|
||||
#include "metagen_base_math.c"
|
||||
#include "metagen_base_strings.c"
|
||||
#include "metagen_base_thread_context.c"
|
||||
#include "metagen_base_command_line.c"
|
||||
#include "metagen_base_markup.c"
|
||||
#include "metagen_base_meta.c"
|
||||
#include "metagen_base_log.c"
|
||||
#include "metagen_base_entry_point.c"
|
||||
24
src/metagen/metagen_base/metagen_base_inc.h
Normal file
24
src/metagen/metagen_base/metagen_base_inc.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_INC_H
|
||||
#define BASE_INC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Base Includes
|
||||
|
||||
#include "metagen_base_context_cracking.h"
|
||||
|
||||
#include "metagen_base_core.h"
|
||||
#include "metagen_base_profile.h"
|
||||
#include "metagen_base_arena.h"
|
||||
#include "metagen_base_math.h"
|
||||
#include "metagen_base_strings.h"
|
||||
#include "metagen_base_thread_context.h"
|
||||
#include "metagen_base_command_line.h"
|
||||
#include "metagen_base_markup.h"
|
||||
#include "metagen_base_meta.h"
|
||||
#include "metagen_base_log.h"
|
||||
#include "metagen_base_entry_point.h"
|
||||
|
||||
#endif // BASE_INC_H
|
||||
103
src/metagen/metagen_base/metagen_base_log.c
Normal file
103
src/metagen/metagen_base/metagen_base_log.c
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals/Thread-Locals
|
||||
|
||||
C_LINKAGE thread_static Log *log_active;
|
||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
||||
C_LINKAGE thread_static Log *log_active = 0;
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Creation/Selection
|
||||
|
||||
internal Log *
|
||||
log_alloc(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
Log *log = push_array(arena, Log, 1);
|
||||
log->arena = arena;
|
||||
return log;
|
||||
}
|
||||
|
||||
internal void
|
||||
log_release(Log *log)
|
||||
{
|
||||
arena_release(log->arena);
|
||||
}
|
||||
|
||||
internal void
|
||||
log_select(Log *log)
|
||||
{
|
||||
log_active = log;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Building/Clearing
|
||||
|
||||
internal void
|
||||
log_msg(LogMsgKind kind, String8 string)
|
||||
{
|
||||
if(log_active != 0 && log_active->top_scope != 0)
|
||||
{
|
||||
String8 string_copy = push_str8_copy(log_active->arena, string);
|
||||
str8_list_push(log_active->arena, &log_active->top_scope->strings[kind], string_copy);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
log_msgf(LogMsgKind kind, char *fmt, ...)
|
||||
{
|
||||
if(log_active != 0)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
log_msg(kind, string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Scopes
|
||||
|
||||
internal void
|
||||
log_scope_begin(void)
|
||||
{
|
||||
if(log_active != 0)
|
||||
{
|
||||
U64 pos = arena_pos(log_active->arena);
|
||||
LogScope *scope = push_array(log_active->arena, LogScope, 1);
|
||||
scope->pos = pos;
|
||||
SLLStackPush(log_active->top_scope, scope);
|
||||
}
|
||||
}
|
||||
|
||||
internal LogScopeResult
|
||||
log_scope_end(Arena *arena)
|
||||
{
|
||||
LogScopeResult result = {0};
|
||||
if(log_active != 0)
|
||||
{
|
||||
LogScope *scope = log_active->top_scope;
|
||||
if(scope != 0)
|
||||
{
|
||||
SLLStackPop(log_active->top_scope);
|
||||
if(arena != 0)
|
||||
{
|
||||
for EachEnumVal(LogMsgKind, kind)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 result_unindented = str8_list_join(scratch.arena, &scope->strings[kind], 0);
|
||||
result.strings[kind] = indented_from_string(arena, result_unindented);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
arena_pop_to(log_active->arena, scope->pos);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
65
src/metagen/metagen_base/metagen_base_log.h
Normal file
65
src/metagen/metagen_base/metagen_base_log.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_LOG_H
|
||||
#define BASE_LOG_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Types
|
||||
|
||||
typedef enum LogMsgKind
|
||||
{
|
||||
LogMsgKind_Info,
|
||||
LogMsgKind_UserError,
|
||||
LogMsgKind_COUNT
|
||||
}
|
||||
LogMsgKind;
|
||||
|
||||
typedef struct LogScope LogScope;
|
||||
struct LogScope
|
||||
{
|
||||
LogScope *next;
|
||||
U64 pos;
|
||||
String8List strings[LogMsgKind_COUNT];
|
||||
};
|
||||
|
||||
typedef struct LogScopeResult LogScopeResult;
|
||||
struct LogScopeResult
|
||||
{
|
||||
String8 strings[LogMsgKind_COUNT];
|
||||
};
|
||||
|
||||
typedef struct Log Log;
|
||||
struct Log
|
||||
{
|
||||
Arena *arena;
|
||||
LogScope *top_scope;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Creation/Selection
|
||||
|
||||
internal Log *log_alloc(void);
|
||||
internal void log_release(Log *log);
|
||||
internal void log_select(Log *log);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Building
|
||||
|
||||
internal void log_msg(LogMsgKind kind, String8 string);
|
||||
internal void log_msgf(LogMsgKind kind, char *fmt, ...);
|
||||
#define log_info(s) log_msg(LogMsgKind_Info, (s))
|
||||
#define log_infof(fmt, ...) log_msgf(LogMsgKind_Info, (fmt), __VA_ARGS__)
|
||||
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
|
||||
#define log_user_errorf(fmt, ...) log_msgf(LogMsgKind_UserError, (fmt), __VA_ARGS__)
|
||||
|
||||
#define LogInfoNamedBlock(s) DeferLoop(log_infof("%S:\n{\n", (s)), log_infof("}\n"))
|
||||
#define LogInfoNamedBlockF(fmt, ...) DeferLoop((log_infof(fmt, __VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n"))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Log Scopes
|
||||
|
||||
internal void log_scope_begin(void);
|
||||
internal LogScopeResult log_scope_end(Arena *arena);
|
||||
|
||||
#endif // BASE_LOG_H
|
||||
21
src/metagen/metagen_base/metagen_base_markup.c
Normal file
21
src/metagen/metagen_base/metagen_base_markup.c
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
set_thread_name(String8 string)
|
||||
{
|
||||
ProfThreadName("%.*s", str8_varg(string));
|
||||
os_set_thread_name(string);
|
||||
}
|
||||
|
||||
internal void
|
||||
set_thread_namef(char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
set_thread_name(string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
12
src/metagen/metagen_base/metagen_base_markup.h
Normal file
12
src/metagen/metagen_base/metagen_base_markup.h
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_MARKUP_H
|
||||
#define BASE_MARKUP_H
|
||||
|
||||
internal void set_thread_name(String8 string);
|
||||
internal void set_thread_namef(char *fmt, ...);
|
||||
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__))
|
||||
#define ThreadName(str) (set_thread_name(str))
|
||||
|
||||
#endif // BASE_MARKUP_H
|
||||
659
src/metagen/metagen_base/metagen_base_math.c
Normal file
659
src/metagen/metagen_base/metagen_base_math.c
Normal file
@ -0,0 +1,659 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scalar Ops
|
||||
|
||||
internal F32
|
||||
mix_1f32(F32 a, F32 b, F32 t)
|
||||
{
|
||||
F32 c = (a + (b-a) * Clamp(0.f, t, 1.f));
|
||||
return c;
|
||||
}
|
||||
|
||||
internal F64
|
||||
mix_1f64(F64 a, F64 b, F64 t)
|
||||
{
|
||||
F64 c = (a + (b-a) * Clamp(0.0, t, 1.0));
|
||||
return c;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Vector Ops
|
||||
|
||||
internal Vec2F32 vec_2f32(F32 x, F32 y) {Vec2F32 v = {x, y}; return v;}
|
||||
internal Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x+b.x, a.y+b.y}; return c;}
|
||||
internal Vec2F32 sub_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x-b.x, a.y-b.y}; return c;}
|
||||
internal Vec2F32 mul_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x*b.x, a.y*b.y}; return c;}
|
||||
internal Vec2F32 div_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x/b.x, a.y/b.y}; return c;}
|
||||
internal Vec2F32 scale_2f32(Vec2F32 v, F32 s) {Vec2F32 c = {v.x*s, v.y*s}; return c;}
|
||||
internal F32 dot_2f32(Vec2F32 a, Vec2F32 b) {F32 c = a.x*b.x + a.y*b.y; return c;}
|
||||
internal F32 length_squared_2f32(Vec2F32 v) {F32 c = v.x*v.x + v.y*v.y; return c;}
|
||||
internal F32 length_2f32(Vec2F32 v) {F32 c = sqrt_f32(v.x*v.x + v.y*v.y); return c;}
|
||||
internal Vec2F32 normalize_2f32(Vec2F32 v) {v = scale_2f32(v, 1.f/length_2f32(v)); return v;}
|
||||
internal Vec2F32 mix_2f32(Vec2F32 a, Vec2F32 b, F32 t) {Vec2F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t)}; return c;}
|
||||
|
||||
internal Vec2S64 vec_2s64(S64 x, S64 y) {Vec2S64 v = {x, y}; return v;}
|
||||
internal Vec2S64 add_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x+b.x, a.y+b.y}; return c;}
|
||||
internal Vec2S64 sub_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x-b.x, a.y-b.y}; return c;}
|
||||
internal Vec2S64 mul_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x*b.x, a.y*b.y}; return c;}
|
||||
internal Vec2S64 div_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x/b.x, a.y/b.y}; return c;}
|
||||
internal Vec2S64 scale_2s64(Vec2S64 v, S64 s) {Vec2S64 c = {v.x*s, v.y*s}; return c;}
|
||||
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b) {S64 c = a.x*b.x + a.y*b.y; return c;}
|
||||
internal S64 length_squared_2s64(Vec2S64 v) {S64 c = v.x*v.x + v.y*v.y; return c;}
|
||||
internal S64 length_2s64(Vec2S64 v) {S64 c = (S64)sqrt_f64((F64)(v.x*v.x + v.y*v.y)); return c;}
|
||||
internal Vec2S64 normalize_2s64(Vec2S64 v) {v = scale_2s64(v, (S64)(1.f/length_2s64(v))); return v;}
|
||||
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t) {Vec2S64 c = {(S64)mix_1f32((F32)a.x, (F32)b.x, t), (S64)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
||||
|
||||
internal Vec2S32 vec_2s32(S32 x, S32 y) {Vec2S32 v = {x, y}; return v;}
|
||||
internal Vec2S32 add_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x+b.x, a.y+b.y}; return c;}
|
||||
internal Vec2S32 sub_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x-b.x, a.y-b.y}; return c;}
|
||||
internal Vec2S32 mul_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x*b.x, a.y*b.y}; return c;}
|
||||
internal Vec2S32 div_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x/b.x, a.y/b.y}; return c;}
|
||||
internal Vec2S32 scale_2s32(Vec2S32 v, S32 s) {Vec2S32 c = {v.x*s, v.y*s}; return c;}
|
||||
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b) {S32 c = a.x*b.x + a.y*b.y; return c;}
|
||||
internal S32 length_squared_2s32(Vec2S32 v) {S32 c = v.x*v.x + v.y*v.y; return c;}
|
||||
internal S32 length_2s32(Vec2S32 v) {S32 c = (S32)sqrt_f32((F32)v.x*(F32)v.x + (F32)v.y*(F32)v.y); return c;}
|
||||
internal Vec2S32 normalize_2s32(Vec2S32 v) {v = scale_2s32(v, (S32)(1.f/length_2s32(v))); return v;}
|
||||
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t) {Vec2S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
||||
|
||||
internal Vec2S16 vec_2s16(S16 x, S16 y) {Vec2S16 v = {x, y}; return v;}
|
||||
internal Vec2S16 add_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x+b.x), (S16)(a.y+b.y)}; return c;}
|
||||
internal Vec2S16 sub_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x-b.x), (S16)(a.y-b.y)}; return c;}
|
||||
internal Vec2S16 mul_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x*b.x), (S16)(a.y*b.y)}; return c;}
|
||||
internal Vec2S16 div_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x/b.x), (S16)(a.y/b.y)}; return c;}
|
||||
internal Vec2S16 scale_2s16(Vec2S16 v, S16 s) {Vec2S16 c = {(S16)(v.x*s), (S16)(v.y*s)}; return c;}
|
||||
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b) {S16 c = a.x*b.x + a.y*b.y; return c;}
|
||||
internal S16 length_squared_2s16(Vec2S16 v) {S16 c = v.x*v.x + v.y*v.y; return c;}
|
||||
internal S16 length_2s16(Vec2S16 v) {S16 c = (S16)sqrt_f32((F32)(v.x*v.x + v.y*v.y)); return c;}
|
||||
internal Vec2S16 normalize_2s16(Vec2S16 v) {v = scale_2s16(v, (S16)(1.f/length_2s16(v))); return v;}
|
||||
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t) {Vec2S16 c = {(S16)mix_1f32((F32)a.x, (F32)b.x, t), (S16)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
||||
|
||||
internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z) {Vec3F32 v = {x, y, z}; return v;}
|
||||
internal Vec3F32 add_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;}
|
||||
internal Vec3F32 sub_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x-b.x, a.y-b.y, a.z-b.z}; return c;}
|
||||
internal Vec3F32 mul_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x*b.x, a.y*b.y, a.z*b.z}; return c;}
|
||||
internal Vec3F32 div_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x/b.x, a.y/b.y, a.z/b.z}; return c;}
|
||||
internal Vec3F32 scale_3f32(Vec3F32 v, F32 s) {Vec3F32 c = {v.x*s, v.y*s, v.z*s}; return c;}
|
||||
internal F32 dot_3f32(Vec3F32 a, Vec3F32 b) {F32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;}
|
||||
internal F32 length_squared_3f32(Vec3F32 v) {F32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;}
|
||||
internal F32 length_3f32(Vec3F32 v) {F32 c = sqrt_f32(v.x*v.x + v.y*v.y + v.z*v.z); return c;}
|
||||
internal Vec3F32 normalize_3f32(Vec3F32 v) {v = scale_3f32(v, 1.f/length_3f32(v)); return v;}
|
||||
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t) {Vec3F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t)}; return c;}
|
||||
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
||||
|
||||
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z) {Vec3S32 v = {x, y, z}; return v;}
|
||||
internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;}
|
||||
internal Vec3S32 sub_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x-b.x, a.y-b.y, a.z-b.z}; return c;}
|
||||
internal Vec3S32 mul_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x*b.x, a.y*b.y, a.z*b.z}; return c;}
|
||||
internal Vec3S32 div_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x/b.x, a.y/b.y, a.z/b.z}; return c;}
|
||||
internal Vec3S32 scale_3s32(Vec3S32 v, S32 s) {Vec3S32 c = {v.x*s, v.y*s, v.z*s}; return c;}
|
||||
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;}
|
||||
internal S32 length_squared_3s32(Vec3S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;}
|
||||
internal S32 length_3s32(Vec3S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z)); return c;}
|
||||
internal Vec3S32 normalize_3s32(Vec3S32 v) {v = scale_3s32(v, (S32)(1.f/length_3s32(v))); return v;}
|
||||
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t) {Vec3S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t)}; return c;}
|
||||
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
||||
|
||||
internal Vec4F32 vec_4f32(F32 x, F32 y, F32 z, F32 w) {Vec4F32 v = {x, y, z, w}; return v;}
|
||||
internal Vec4F32 add_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w}; return c;}
|
||||
internal Vec4F32 sub_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w}; return c;}
|
||||
internal Vec4F32 mul_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return c;}
|
||||
internal Vec4F32 div_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return c;}
|
||||
internal Vec4F32 scale_4f32(Vec4F32 v, F32 s) {Vec4F32 c = {v.x*s, v.y*s, v.z*s, v.w*s}; return c;}
|
||||
internal F32 dot_4f32(Vec4F32 a, Vec4F32 b) {F32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;}
|
||||
internal F32 length_squared_4f32(Vec4F32 v) {F32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;}
|
||||
internal F32 length_4f32(Vec4F32 v) {F32 c = sqrt_f32(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w); return c;}
|
||||
internal Vec4F32 normalize_4f32(Vec4F32 v) {v = scale_4f32(v, 1.f/length_4f32(v)); return v;}
|
||||
internal Vec4F32 mix_4f32(Vec4F32 a, Vec4F32 b, F32 t) {Vec4F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t), mix_1f32(a.w, b.w, t)}; return c;}
|
||||
|
||||
internal Vec4S32 vec_4s32(S32 x, S32 y, S32 z, S32 w) {Vec4S32 v = {x, y, z, w}; return v;}
|
||||
internal Vec4S32 add_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w}; return c;}
|
||||
internal Vec4S32 sub_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w}; return c;}
|
||||
internal Vec4S32 mul_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return c;}
|
||||
internal Vec4S32 div_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return c;}
|
||||
internal Vec4S32 scale_4s32(Vec4S32 v, S32 s) {Vec4S32 c = {v.x*s, v.y*s, v.z*s, v.w*s}; return c;}
|
||||
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;}
|
||||
internal S32 length_squared_4s32(Vec4S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;}
|
||||
internal S32 length_4s32(Vec4S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w)); return c;}
|
||||
internal Vec4S32 normalize_4s32(Vec4S32 v) {v = scale_4s32(v, (S32)(1.f/length_4s32(v))); return v;}
|
||||
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t) {Vec4S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t), (S32)mix_1f32((F32)a.w, (F32)b.w, t)}; return c;}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Matrix Ops
|
||||
|
||||
internal Mat3x3F32
|
||||
mat_3x3f32(F32 diagonal)
|
||||
{
|
||||
Mat3x3F32 result = {0};
|
||||
result.v[0][0] = diagonal;
|
||||
result.v[1][1] = diagonal;
|
||||
result.v[2][2] = diagonal;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Mat3x3F32
|
||||
make_translate_3x3f32(Vec2F32 delta)
|
||||
{
|
||||
Mat3x3F32 mat = mat_3x3f32(1.f);
|
||||
mat.v[2][0] = delta.x;
|
||||
mat.v[2][1] = delta.y;
|
||||
return mat;
|
||||
}
|
||||
|
||||
internal Mat3x3F32
|
||||
make_scale_3x3f32(Vec2F32 scale)
|
||||
{
|
||||
Mat3x3F32 mat = mat_3x3f32(1.f);
|
||||
mat.v[0][0] = scale.x;
|
||||
mat.v[1][1] = scale.y;
|
||||
return mat;
|
||||
}
|
||||
|
||||
internal Mat3x3F32
|
||||
mul_3x3f32(Mat3x3F32 a, Mat3x3F32 b)
|
||||
{
|
||||
Mat3x3F32 c = {0};
|
||||
for(int j = 0; j < 3; j += 1)
|
||||
{
|
||||
for(int i = 0; i < 3; i += 1)
|
||||
{
|
||||
c.v[i][j] = (a.v[0][j]*b.v[i][0] +
|
||||
a.v[1][j]*b.v[i][1] +
|
||||
a.v[2][j]*b.v[i][2]);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
mat_4x4f32(F32 diagonal)
|
||||
{
|
||||
Mat4x4F32 result = {0};
|
||||
result.v[0][0] = diagonal;
|
||||
result.v[1][1] = diagonal;
|
||||
result.v[2][2] = diagonal;
|
||||
result.v[3][3] = diagonal;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
make_translate_4x4f32(Vec3F32 delta)
|
||||
{
|
||||
Mat4x4F32 result = mat_4x4f32(1.f);
|
||||
result.v[3][0] = delta.x;
|
||||
result.v[3][1] = delta.y;
|
||||
result.v[3][2] = delta.z;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
make_scale_4x4f32(Vec3F32 scale)
|
||||
{
|
||||
Mat4x4F32 result = mat_4x4f32(1.f);
|
||||
result.v[0][0] = scale.x;
|
||||
result.v[1][1] = scale.y;
|
||||
result.v[2][2] = scale.z;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
make_perspective_4x4f32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z)
|
||||
{
|
||||
Mat4x4F32 result = mat_4x4f32(1.f);
|
||||
F32 tan_theta_over_2 = tan_f32(fov / 2);
|
||||
result.v[0][0] = 1.f / tan_theta_over_2;
|
||||
result.v[1][1] = aspect_ratio / tan_theta_over_2;
|
||||
result.v[2][3] = 1.f;
|
||||
result.v[2][2] = -(near_z + far_z) / (near_z - far_z);
|
||||
result.v[3][2] = (2.f * near_z * far_z) / (near_z - far_z);
|
||||
result.v[3][3] = 0.f;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
make_orthographic_4x4f32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z)
|
||||
{
|
||||
Mat4x4F32 result = mat_4x4f32(1.f);
|
||||
|
||||
result.v[0][0] = 2.f / (right - left);
|
||||
result.v[1][1] = 2.f / (top - bottom);
|
||||
result.v[2][2] = 2.f / (far_z - near_z);
|
||||
result.v[3][3] = 1.f;
|
||||
|
||||
result.v[3][0] = (left + right) / (left - right);
|
||||
result.v[3][1] = (bottom + top) / (bottom - top);
|
||||
result.v[3][2] = (near_z + far_z) / (near_z - far_z);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
make_look_at_4x4f32(Vec3F32 eye, Vec3F32 center, Vec3F32 up)
|
||||
{
|
||||
Mat4x4F32 result;
|
||||
Vec3F32 f = normalize_3f32(sub_3f32(eye, center));
|
||||
Vec3F32 s = normalize_3f32(cross_3f32(f, up));
|
||||
Vec3F32 u = cross_3f32(s, f);
|
||||
result.v[0][0] = s.x;
|
||||
result.v[0][1] = u.x;
|
||||
result.v[0][2] = -f.x;
|
||||
result.v[0][3] = 0.0f;
|
||||
result.v[1][0] = s.y;
|
||||
result.v[1][1] = u.y;
|
||||
result.v[1][2] = -f.y;
|
||||
result.v[1][3] = 0.0f;
|
||||
result.v[2][0] = s.z;
|
||||
result.v[2][1] = u.z;
|
||||
result.v[2][2] = -f.z;
|
||||
result.v[2][3] = 0.0f;
|
||||
result.v[3][0] = -dot_3f32(s, eye);
|
||||
result.v[3][1] = -dot_3f32(u, eye);
|
||||
result.v[3][2] = dot_3f32(f, eye);
|
||||
result.v[3][3] = 1.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
make_rotate_4x4f32(Vec3F32 axis, F32 turns)
|
||||
{
|
||||
Mat4x4F32 result = mat_4x4f32(1.f);
|
||||
axis = normalize_3f32(axis);
|
||||
F32 sin_theta = sin_f32(turns);
|
||||
F32 cos_theta = cos_f32(turns);
|
||||
F32 cos_value = 1.f - cos_theta;
|
||||
result.v[0][0] = (axis.x * axis.x * cos_value) + cos_theta;
|
||||
result.v[0][1] = (axis.x * axis.y * cos_value) + (axis.z * sin_theta);
|
||||
result.v[0][2] = (axis.x * axis.z * cos_value) - (axis.y * sin_theta);
|
||||
result.v[1][0] = (axis.y * axis.x * cos_value) - (axis.z * sin_theta);
|
||||
result.v[1][1] = (axis.y * axis.y * cos_value) + cos_theta;
|
||||
result.v[1][2] = (axis.y * axis.z * cos_value) + (axis.x * sin_theta);
|
||||
result.v[2][0] = (axis.z * axis.x * cos_value) + (axis.y * sin_theta);
|
||||
result.v[2][1] = (axis.z * axis.y * cos_value) - (axis.x * sin_theta);
|
||||
result.v[2][2] = (axis.z * axis.z * cos_value) + cos_theta;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b)
|
||||
{
|
||||
Mat4x4F32 c = {0};
|
||||
for(int j = 0; j < 4; j += 1)
|
||||
{
|
||||
for(int i = 0; i < 4; i += 1)
|
||||
{
|
||||
c.v[i][j] = (a.v[0][j]*b.v[i][0] +
|
||||
a.v[1][j]*b.v[i][1] +
|
||||
a.v[2][j]*b.v[i][2] +
|
||||
a.v[3][j]*b.v[i][3]);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
scale_4x4f32(Mat4x4F32 m, F32 scale)
|
||||
{
|
||||
for(int j = 0; j < 4; j += 1)
|
||||
{
|
||||
for(int i = 0; i < 4; i += 1)
|
||||
{
|
||||
m.v[i][j] *= scale;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
inverse_4x4f32(Mat4x4F32 m)
|
||||
{
|
||||
F32 coef00 = m.v[2][2] * m.v[3][3] - m.v[3][2] * m.v[2][3];
|
||||
F32 coef02 = m.v[1][2] * m.v[3][3] - m.v[3][2] * m.v[1][3];
|
||||
F32 coef03 = m.v[1][2] * m.v[2][3] - m.v[2][2] * m.v[1][3];
|
||||
F32 coef04 = m.v[2][1] * m.v[3][3] - m.v[3][1] * m.v[2][3];
|
||||
F32 coef06 = m.v[1][1] * m.v[3][3] - m.v[3][1] * m.v[1][3];
|
||||
F32 coef07 = m.v[1][1] * m.v[2][3] - m.v[2][1] * m.v[1][3];
|
||||
F32 coef08 = m.v[2][1] * m.v[3][2] - m.v[3][1] * m.v[2][2];
|
||||
F32 coef10 = m.v[1][1] * m.v[3][2] - m.v[3][1] * m.v[1][2];
|
||||
F32 coef11 = m.v[1][1] * m.v[2][2] - m.v[2][1] * m.v[1][2];
|
||||
F32 coef12 = m.v[2][0] * m.v[3][3] - m.v[3][0] * m.v[2][3];
|
||||
F32 coef14 = m.v[1][0] * m.v[3][3] - m.v[3][0] * m.v[1][3];
|
||||
F32 coef15 = m.v[1][0] * m.v[2][3] - m.v[2][0] * m.v[1][3];
|
||||
F32 coef16 = m.v[2][0] * m.v[3][2] - m.v[3][0] * m.v[2][2];
|
||||
F32 coef18 = m.v[1][0] * m.v[3][2] - m.v[3][0] * m.v[1][2];
|
||||
F32 coef19 = m.v[1][0] * m.v[2][2] - m.v[2][0] * m.v[1][2];
|
||||
F32 coef20 = m.v[2][0] * m.v[3][1] - m.v[3][0] * m.v[2][1];
|
||||
F32 coef22 = m.v[1][0] * m.v[3][1] - m.v[3][0] * m.v[1][1];
|
||||
F32 coef23 = m.v[1][0] * m.v[2][1] - m.v[2][0] * m.v[1][1];
|
||||
|
||||
Vec4F32 fac0 = { coef00, coef00, coef02, coef03 };
|
||||
Vec4F32 fac1 = { coef04, coef04, coef06, coef07 };
|
||||
Vec4F32 fac2 = { coef08, coef08, coef10, coef11 };
|
||||
Vec4F32 fac3 = { coef12, coef12, coef14, coef15 };
|
||||
Vec4F32 fac4 = { coef16, coef16, coef18, coef19 };
|
||||
Vec4F32 fac5 = { coef20, coef20, coef22, coef23 };
|
||||
|
||||
Vec4F32 vec0 = { m.v[1][0], m.v[0][0], m.v[0][0], m.v[0][0] };
|
||||
Vec4F32 vec1 = { m.v[1][1], m.v[0][1], m.v[0][1], m.v[0][1] };
|
||||
Vec4F32 vec2 = { m.v[1][2], m.v[0][2], m.v[0][2], m.v[0][2] };
|
||||
Vec4F32 vec3 = { m.v[1][3], m.v[0][3], m.v[0][3], m.v[0][3] };
|
||||
|
||||
Vec4F32 inv0 = add_4f32(sub_4f32(mul_4f32(vec1, fac0), mul_4f32(vec2, fac1)), mul_4f32(vec3, fac2));
|
||||
Vec4F32 inv1 = add_4f32(sub_4f32(mul_4f32(vec0, fac0), mul_4f32(vec2, fac3)), mul_4f32(vec3, fac4));
|
||||
Vec4F32 inv2 = add_4f32(sub_4f32(mul_4f32(vec0, fac1), mul_4f32(vec1, fac3)), mul_4f32(vec3, fac5));
|
||||
Vec4F32 inv3 = add_4f32(sub_4f32(mul_4f32(vec0, fac2), mul_4f32(vec1, fac4)), mul_4f32(vec2, fac5));
|
||||
|
||||
Vec4F32 sign_a = { +1, -1, +1, -1 };
|
||||
Vec4F32 sign_b = { -1, +1, -1, +1 };
|
||||
|
||||
Mat4x4F32 inverse;
|
||||
for(U32 i = 0; i < 4; i += 1)
|
||||
{
|
||||
inverse.v[0][i] = inv0.v[i] * sign_a.v[i];
|
||||
inverse.v[1][i] = inv1.v[i] * sign_b.v[i];
|
||||
inverse.v[2][i] = inv2.v[i] * sign_a.v[i];
|
||||
inverse.v[3][i] = inv3.v[i] * sign_b.v[i];
|
||||
}
|
||||
|
||||
Vec4F32 row0 = { inverse.v[0][0], inverse.v[1][0], inverse.v[2][0], inverse.v[3][0] };
|
||||
Vec4F32 m0 = { m.v[0][0], m.v[0][1], m.v[0][2], m.v[0][3] };
|
||||
Vec4F32 dot0 = mul_4f32(m0, row0);
|
||||
F32 dot1 = (dot0.x + dot0.y) + (dot0.z + dot0.w);
|
||||
|
||||
F32 one_over_det = 1 / dot1;
|
||||
|
||||
return scale_4x4f32(inverse, one_over_det);
|
||||
}
|
||||
|
||||
internal Mat4x4F32
|
||||
derotate_4x4f32(Mat4x4F32 mat)
|
||||
{
|
||||
Vec3F32 scale =
|
||||
{
|
||||
length_3f32(v3f32(mat.v[0][0], mat.v[0][1], mat.v[0][2])),
|
||||
length_3f32(v3f32(mat.v[1][0], mat.v[1][1], mat.v[1][2])),
|
||||
length_3f32(v3f32(mat.v[2][0], mat.v[2][1], mat.v[2][2])),
|
||||
};
|
||||
mat.v[0][0] = scale.x;
|
||||
mat.v[1][0] = 0.f;
|
||||
mat.v[2][0] = 0.f;
|
||||
mat.v[0][1] = 0.f;
|
||||
mat.v[1][1] = scale.y;
|
||||
mat.v[2][1] = 0.f;
|
||||
mat.v[0][2] = 0.f;
|
||||
mat.v[1][2] = 0.f;
|
||||
mat.v[2][2] = scale.z;
|
||||
return mat;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Range Ops
|
||||
|
||||
internal Rng1U32 rng_1u32(U32 min, U32 max) {Rng1U32 r = {min, max}; if(r.min > r.max) { Swap(U32, r.min, r.max); } return r;}
|
||||
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.max += x; return r;}
|
||||
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;}
|
||||
internal U32 center_1u32(Rng1U32 r) {U32 c = (r.min+r.max)/2; return c;}
|
||||
internal B32 contains_1u32(Rng1U32 r, U32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||
internal U32 dim_1u32(Rng1U32 r) {U32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
||||
internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||
internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||
internal U32 clamp_1u32(Rng1U32 r, U32 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||
|
||||
internal Rng1S32 rng_1s32(S32 min, S32 max) {Rng1S32 r = {min, max}; if(r.min > r.max) { Swap(S32, r.min, r.max); } return r;}
|
||||
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x) {r.min += x; r.max += x; return r;}
|
||||
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x) {r.min -= x; r.max += x; return r;}
|
||||
internal S32 center_1s32(Rng1S32 r) {S32 c = (r.min+r.max)/2; return c;}
|
||||
internal B32 contains_1s32(Rng1S32 r, S32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||
internal S32 dim_1s32(Rng1S32 r) {S32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
||||
internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||
internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||
internal S32 clamp_1s32(Rng1S32 r, S32 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||
|
||||
internal Rng1U64 rng_1u64(U64 min, U64 max) {Rng1U64 r = {min, max}; if(r.min > r.max) { Swap(U64, r.min, r.max); } return r;}
|
||||
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x) {r.min += x; r.max += x; return r;}
|
||||
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x) {r.min -= x; r.max += x; return r;}
|
||||
internal U64 center_1u64(Rng1U64 r) {U64 c = (r.min+r.max)/2; return c;}
|
||||
internal B32 contains_1u64(Rng1U64 r, U64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||
internal U64 dim_1u64(Rng1U64 r) {U64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
||||
internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||
internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||
internal U64 clamp_1u64(Rng1U64 r, U64 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||
|
||||
internal Rng1S64 rng_1s64(S64 min, S64 max) {Rng1S64 r = {min, max}; if(r.min > r.max) { Swap(S64, r.min, r.max); } return r;}
|
||||
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x) {r.min += x; r.max += x; return r;}
|
||||
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x) {r.min -= x; r.max += x; return r;}
|
||||
internal S64 center_1s64(Rng1S64 r) {S64 c = (r.min+r.max)/2; return c;}
|
||||
internal B32 contains_1s64(Rng1S64 r, S64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||
internal S64 dim_1s64(Rng1S64 r) {S64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
||||
internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||
internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||
internal S64 clamp_1s64(Rng1S64 r, S64 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||
|
||||
internal Rng1F32 rng_1f32(F32 min, F32 max) {Rng1F32 r = {min, max}; if(r.min > r.max) { Swap(F32, r.min, r.max); } return r;}
|
||||
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x) {r.min += x; r.max += x; return r;}
|
||||
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x) {r.min -= x; r.max += x; return r;}
|
||||
internal F32 center_1f32(Rng1F32 r) {F32 c = (r.min+r.max)/2; return c;}
|
||||
internal B32 contains_1f32(Rng1F32 r, F32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||
internal F32 dim_1f32(Rng1F32 r) {F32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
||||
internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||
internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||
internal F32 clamp_1f32(Rng1F32 r, F32 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||
|
||||
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max) {Rng2S16 r = {min, max}; return r;}
|
||||
internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x) {r.min = add_2s16(r.min, x); r.max = add_2s16(r.max, x); return r;}
|
||||
internal Rng2S16 pad_2s16(Rng2S16 r, S16 x) {Vec2S16 xv = {x, x}; r.min = sub_2s16(r.min, xv); r.max = add_2s16(r.max, xv); return r;}
|
||||
internal Vec2S16 center_2s16(Rng2S16 r) {Vec2S16 c = {(S16)((r.min.x+r.max.x)/2), (S16)((r.min.y+r.max.y)/2)}; return c;}
|
||||
internal B32 contains_2s16(Rng2S16 r, Vec2S16 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||
internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0)), (S16)(((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0))}; return dim;}
|
||||
internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||
internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||
|
||||
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max) {Rng2S32 r = {min, max}; return r;}
|
||||
internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x) {r.min = add_2s32(r.min, x); r.max = add_2s32(r.max, x); return r;}
|
||||
internal Rng2S32 pad_2s32(Rng2S32 r, S32 x) {Vec2S32 xv = {x, x}; r.min = sub_2s32(r.min, xv); r.max = add_2s32(r.max, xv); return r;}
|
||||
internal Vec2S32 center_2s32(Rng2S32 r) {Vec2S32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
||||
internal B32 contains_2s32(Rng2S32 r, Vec2S32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||
internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
|
||||
internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||
internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||
|
||||
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max) {Rng2S64 r = {min, max}; return r;}
|
||||
internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x) {r.min = add_2s64(r.min, x); r.max = add_2s64(r.max, x); return r;}
|
||||
internal Rng2S64 pad_2s64(Rng2S64 r, S64 x) {Vec2S64 xv = {x, x}; r.min = sub_2s64(r.min, xv); r.max = add_2s64(r.max, xv); return r;}
|
||||
internal Vec2S64 center_2s64(Rng2S64 r) {Vec2S64 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
||||
internal B32 contains_2s64(Rng2S64 r, Vec2S64 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||
internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
|
||||
internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||
internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||
|
||||
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max) {Rng2F32 r = {min, max}; return r;}
|
||||
internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x) {r.min = add_2f32(r.min, x); r.max = add_2f32(r.max, x); return r;}
|
||||
internal Rng2F32 pad_2f32(Rng2F32 r, F32 x) {Vec2F32 xv = {x, x}; r.min = sub_2f32(r.min, xv); r.max = add_2f32(r.max, xv); return r;}
|
||||
internal Vec2F32 center_2f32(Rng2F32 r) {Vec2F32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
||||
internal B32 contains_2f32(Rng2F32 r, Vec2F32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||
internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
|
||||
internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||
internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Miscellaneous Ops
|
||||
|
||||
internal Vec3F32
|
||||
hsv_from_rgb(Vec3F32 rgb)
|
||||
{
|
||||
F32 c_max = Max(rgb.x, Max(rgb.y, rgb.z));
|
||||
F32 c_min = Min(rgb.x, Min(rgb.y, rgb.z));
|
||||
F32 delta = c_max - c_min;
|
||||
F32 h = ((delta == 0.f) ? 0.f :
|
||||
(c_max == rgb.x) ? mod_f32((rgb.y - rgb.z)/delta + 6.f, 6.f) :
|
||||
(c_max == rgb.y) ? (rgb.z - rgb.x)/delta + 2.f :
|
||||
(c_max == rgb.z) ? (rgb.x - rgb.y)/delta + 4.f :
|
||||
0.f);
|
||||
F32 s = (c_max == 0.f) ? 0.f : (delta/c_max);
|
||||
F32 v = c_max;
|
||||
Vec3F32 hsv = {h/6.f, s, v};
|
||||
return hsv;
|
||||
}
|
||||
|
||||
internal Vec3F32
|
||||
rgb_from_hsv(Vec3F32 hsv)
|
||||
{
|
||||
F32 h = mod_f32(hsv.x * 360.f, 360.f);
|
||||
F32 s = hsv.y;
|
||||
F32 v = hsv.z;
|
||||
|
||||
F32 c = v*s;
|
||||
F32 x = c*(1.f - abs_f32(mod_f32(h/60.f, 2.f) - 1.f));
|
||||
F32 m = v - c;
|
||||
|
||||
F32 r = 0;
|
||||
F32 g = 0;
|
||||
F32 b = 0;
|
||||
|
||||
if ((h >= 0.f && h < 60.f) || (h >= 360.f && h < 420.f)){
|
||||
r = c;
|
||||
g = x;
|
||||
b = 0;
|
||||
}
|
||||
else if (h >= 60.f && h < 120.f){
|
||||
r = x;
|
||||
g = c;
|
||||
b = 0;
|
||||
}
|
||||
else if (h >= 120.f && h < 180.f){
|
||||
r = 0;
|
||||
g = c;
|
||||
b = x;
|
||||
}
|
||||
else if (h >= 180.f && h < 240.f){
|
||||
r = 0;
|
||||
g = x;
|
||||
b = c;
|
||||
}
|
||||
else if (h >= 240.f && h < 300.f){
|
||||
r = x;
|
||||
g = 0;
|
||||
b = c;
|
||||
}
|
||||
else if ((h >= 300.f && h <= 360.f) || (h >= -60.f && h <= 0.f)){
|
||||
r = c;
|
||||
g = 0;
|
||||
b = x;
|
||||
}
|
||||
|
||||
Vec3F32 rgb = {r + m, g + m, b + m};
|
||||
return(rgb);
|
||||
}
|
||||
|
||||
internal Vec4F32
|
||||
hsva_from_rgba(Vec4F32 rgba)
|
||||
{
|
||||
Vec3F32 rgb = v3f32(rgba.x, rgba.y, rgba.z);
|
||||
Vec3F32 hsv = hsv_from_rgb(rgb);
|
||||
Vec4F32 hsva = v4f32(hsv.x, hsv.y, hsv.z, rgba.w);
|
||||
return hsva;
|
||||
}
|
||||
|
||||
internal Vec4F32
|
||||
rgba_from_hsva(Vec4F32 hsva)
|
||||
{
|
||||
Vec3F32 hsv = v3f32(hsva.x, hsva.y, hsva.z);
|
||||
Vec3F32 rgb = rgb_from_hsv(hsv);
|
||||
Vec4F32 rgba = v4f32(rgb.x, rgb.y, rgb.z, hsva.w);
|
||||
return rgba;
|
||||
}
|
||||
|
||||
internal Vec4F32
|
||||
rgba_from_u32(U32 hex)
|
||||
{
|
||||
Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f,
|
||||
((hex&0x00ff0000)>>16)/255.f,
|
||||
((hex&0x0000ff00)>> 8)/255.f,
|
||||
((hex&0x000000ff)>> 0)/255.f);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U32
|
||||
u32_from_rgba(Vec4F32 rgba)
|
||||
{
|
||||
U32 result = 0;
|
||||
result |= ((U32)((U8)(rgba.x*255.f))) << 24;
|
||||
result |= ((U32)((U8)(rgba.y*255.f))) << 16;
|
||||
result |= ((U32)((U8)(rgba.z*255.f))) << 8;
|
||||
result |= ((U32)((U8)(rgba.w*255.f))) << 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: List Type Functions
|
||||
|
||||
internal void
|
||||
rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng)
|
||||
{
|
||||
Rng1U64Node *n = push_array(arena, Rng1U64Node, 1);
|
||||
MemoryCopyStruct(&n->v, &rng);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat)
|
||||
{
|
||||
if(to_concat->first)
|
||||
{
|
||||
if(list->first)
|
||||
{
|
||||
list->last->next = to_concat->first;
|
||||
list->last = to_concat->last;
|
||||
}
|
||||
else
|
||||
{
|
||||
list->first = to_concat->first;
|
||||
list->last = to_concat->last;
|
||||
}
|
||||
MemoryZeroStruct(to_concat);
|
||||
}
|
||||
}
|
||||
|
||||
internal Rng1U64Array
|
||||
rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
|
||||
{
|
||||
Rng1U64Array arr = {0};
|
||||
arr.count = list->count;
|
||||
arr.v = push_array_no_zero(arena, Rng1U64, arr.count);
|
||||
U64 idx = 0;
|
||||
for(Rng1U64Node *n = list->first; n != 0; n = n->next)
|
||||
{
|
||||
arr.v[idx] = n->v;
|
||||
idx += 1;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal void
|
||||
rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng)
|
||||
{
|
||||
Rng1S64Node *n = push_array(arena, Rng1S64Node, 1);
|
||||
MemoryCopyStruct(&n->v, &rng);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal Rng1S64Array
|
||||
rng1s64_array_from_list(Arena *arena, Rng1S64List *list)
|
||||
{
|
||||
Rng1S64Array arr = {0};
|
||||
arr.count = list->count;
|
||||
arr.v = push_array_no_zero(arena, Rng1S64, arr.count);
|
||||
U64 idx = 0;
|
||||
for(Rng1S64Node *n = list->first; n != 0; n = n->next)
|
||||
{
|
||||
arr.v[idx] = n->v;
|
||||
idx += 1;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
675
src/metagen/metagen_base/metagen_base_math.h
Normal file
675
src/metagen/metagen_base/metagen_base_math.h
Normal file
@ -0,0 +1,675 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_MATH_H
|
||||
#define BASE_MATH_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Vector Types
|
||||
|
||||
//- rjf: 2-vectors
|
||||
|
||||
typedef union Vec2F32 Vec2F32;
|
||||
union Vec2F32
|
||||
{
|
||||
struct
|
||||
{
|
||||
F32 x;
|
||||
F32 y;
|
||||
};
|
||||
F32 v[2];
|
||||
};
|
||||
|
||||
typedef union Vec2S64 Vec2S64;
|
||||
union Vec2S64
|
||||
{
|
||||
struct
|
||||
{
|
||||
S64 x;
|
||||
S64 y;
|
||||
};
|
||||
S64 v[2];
|
||||
};
|
||||
|
||||
typedef union Vec2S32 Vec2S32;
|
||||
union Vec2S32
|
||||
{
|
||||
struct
|
||||
{
|
||||
S32 x;
|
||||
S32 y;
|
||||
};
|
||||
S32 v[2];
|
||||
};
|
||||
|
||||
typedef union Vec2S16 Vec2S16;
|
||||
union Vec2S16
|
||||
{
|
||||
struct
|
||||
{
|
||||
S16 x;
|
||||
S16 y;
|
||||
};
|
||||
S16 v[2];
|
||||
};
|
||||
|
||||
//- rjf: 3-vectors
|
||||
|
||||
typedef union Vec3F32 Vec3F32;
|
||||
union Vec3F32
|
||||
{
|
||||
struct
|
||||
{
|
||||
F32 x;
|
||||
F32 y;
|
||||
F32 z;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec2F32 xy;
|
||||
F32 _z0;
|
||||
};
|
||||
struct
|
||||
{
|
||||
F32 _x0;
|
||||
Vec2F32 yz;
|
||||
};
|
||||
F32 v[3];
|
||||
};
|
||||
|
||||
typedef union Vec3S32 Vec3S32;
|
||||
union Vec3S32
|
||||
{
|
||||
struct
|
||||
{
|
||||
S32 x;
|
||||
S32 y;
|
||||
S32 z;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec2S32 xy;
|
||||
S32 _z0;
|
||||
};
|
||||
struct
|
||||
{
|
||||
S32 _x0;
|
||||
Vec2S32 yz;
|
||||
};
|
||||
S32 v[3];
|
||||
};
|
||||
|
||||
//- rjf: 4-vectors
|
||||
|
||||
typedef union Vec4F32 Vec4F32;
|
||||
union Vec4F32
|
||||
{
|
||||
struct
|
||||
{
|
||||
F32 x;
|
||||
F32 y;
|
||||
F32 z;
|
||||
F32 w;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec2F32 xy;
|
||||
Vec2F32 zw;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec3F32 xyz;
|
||||
F32 _z0;
|
||||
};
|
||||
struct
|
||||
{
|
||||
F32 _x0;
|
||||
Vec3F32 yzw;
|
||||
};
|
||||
F32 v[4];
|
||||
};
|
||||
|
||||
typedef union Vec4S32 Vec4S32;
|
||||
union Vec4S32
|
||||
{
|
||||
struct
|
||||
{
|
||||
S32 x;
|
||||
S32 y;
|
||||
S32 z;
|
||||
S32 w;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec2S32 xy;
|
||||
Vec2S32 zw;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec3S32 xyz;
|
||||
S32 _z0;
|
||||
};
|
||||
struct
|
||||
{
|
||||
S32 _x0;
|
||||
Vec3S32 yzw;
|
||||
};
|
||||
S32 v[4];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Matrix Types
|
||||
|
||||
typedef struct Mat3x3F32 Mat3x3F32;
|
||||
struct Mat3x3F32
|
||||
{
|
||||
F32 v[3][3];
|
||||
};
|
||||
|
||||
typedef struct Mat4x4F32 Mat4x4F32;
|
||||
struct Mat4x4F32
|
||||
{
|
||||
F32 v[4][4];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Range Types
|
||||
|
||||
//- rjf: 1-range
|
||||
|
||||
typedef union Rng1U32 Rng1U32;
|
||||
union Rng1U32
|
||||
{
|
||||
struct
|
||||
{
|
||||
U32 min;
|
||||
U32 max;
|
||||
};
|
||||
U32 v[2];
|
||||
};
|
||||
|
||||
typedef union Rng1S32 Rng1S32;
|
||||
union Rng1S32
|
||||
{
|
||||
struct
|
||||
{
|
||||
S32 min;
|
||||
S32 max;
|
||||
};
|
||||
S32 v[2];
|
||||
};
|
||||
|
||||
typedef union Rng1U64 Rng1U64;
|
||||
union Rng1U64
|
||||
{
|
||||
struct
|
||||
{
|
||||
U64 min;
|
||||
U64 max;
|
||||
};
|
||||
U64 v[2];
|
||||
};
|
||||
|
||||
typedef union Rng1S64 Rng1S64;
|
||||
union Rng1S64
|
||||
{
|
||||
struct
|
||||
{
|
||||
S64 min;
|
||||
S64 max;
|
||||
};
|
||||
S64 v[2];
|
||||
};
|
||||
|
||||
typedef union Rng1F32 Rng1F32;
|
||||
union Rng1F32
|
||||
{
|
||||
struct
|
||||
{
|
||||
F32 min;
|
||||
F32 max;
|
||||
};
|
||||
F32 v[2];
|
||||
};
|
||||
|
||||
//- rjf: 2-range (rectangles)
|
||||
|
||||
typedef union Rng2S16 Rng2S16;
|
||||
union Rng2S16
|
||||
{
|
||||
struct
|
||||
{
|
||||
Vec2S16 min;
|
||||
Vec2S16 max;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec2S16 p0;
|
||||
Vec2S16 p1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
S16 x0;
|
||||
S16 y0;
|
||||
S16 x1;
|
||||
S16 y1;
|
||||
};
|
||||
Vec2S16 v[2];
|
||||
};
|
||||
|
||||
typedef union Rng2S32 Rng2S32;
|
||||
union Rng2S32
|
||||
{
|
||||
struct
|
||||
{
|
||||
Vec2S32 min;
|
||||
Vec2S32 max;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec2S32 p0;
|
||||
Vec2S32 p1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
S32 x0;
|
||||
S32 y0;
|
||||
S32 x1;
|
||||
S32 y1;
|
||||
};
|
||||
Vec2S32 v[2];
|
||||
};
|
||||
|
||||
typedef union Rng2F32 Rng2F32;
|
||||
union Rng2F32
|
||||
{
|
||||
struct
|
||||
{
|
||||
Vec2F32 min;
|
||||
Vec2F32 max;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec2F32 p0;
|
||||
Vec2F32 p1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
F32 x0;
|
||||
F32 y0;
|
||||
F32 x1;
|
||||
F32 y1;
|
||||
};
|
||||
Vec2F32 v[2];
|
||||
};
|
||||
|
||||
typedef union Rng2S64 Rng2S64;
|
||||
union Rng2S64
|
||||
{
|
||||
struct
|
||||
{
|
||||
Vec2S64 min;
|
||||
Vec2S64 max;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Vec2S64 p0;
|
||||
Vec2S64 p1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
S64 x0;
|
||||
S64 y0;
|
||||
S64 x1;
|
||||
S64 y1;
|
||||
};
|
||||
Vec2S64 v[2];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: List Types
|
||||
|
||||
typedef struct Rng1U64Node Rng1U64Node;
|
||||
struct Rng1U64Node
|
||||
{
|
||||
Rng1U64Node *next;
|
||||
Rng1U64 v;
|
||||
};
|
||||
|
||||
typedef struct Rng1U64List Rng1U64List;
|
||||
struct Rng1U64List
|
||||
{
|
||||
U64 count;
|
||||
Rng1U64Node *first;
|
||||
Rng1U64Node *last;
|
||||
};
|
||||
|
||||
typedef struct Rng1U64Array Rng1U64Array;
|
||||
struct Rng1U64Array
|
||||
{
|
||||
Rng1U64 *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct Rng1S64Node Rng1S64Node;
|
||||
struct Rng1S64Node
|
||||
{
|
||||
Rng1S64Node *next;
|
||||
Rng1S64 v;
|
||||
};
|
||||
|
||||
typedef struct Rng1S64List Rng1S64List;
|
||||
struct Rng1S64List
|
||||
{
|
||||
Rng1S64Node *first;
|
||||
Rng1S64Node *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct Rng1S64Array Rng1S64Array;
|
||||
struct Rng1S64Array
|
||||
{
|
||||
Rng1S64 *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scalar Ops
|
||||
|
||||
#define abs_s64(v) (S64)llabs(v)
|
||||
|
||||
#define sqrt_f32(v) sqrtf(v)
|
||||
#define mod_f32(a, b) fmodf((a), (b))
|
||||
#define pow_f32(b, e) powf((b), (e))
|
||||
#define ceil_f32(v) ceilf(v)
|
||||
#define floor_f32(v) floorf(v)
|
||||
#define round_f32(v) roundf(v)
|
||||
#define abs_f32(v) fabsf(v)
|
||||
#define radians_from_turns_f32(v) ((v)*2*3.1415926535897f)
|
||||
#define turns_from_radians_f32(v) ((v)/2*3.1415926535897f)
|
||||
#define degrees_from_turns_f32(v) ((v)*360.f)
|
||||
#define turns_from_degrees_f32(v) ((v)/360.f)
|
||||
#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v)))
|
||||
#define radians_from_degrees_f32(v) (radians_from_turns_f32(turns_from_degrees_f32(v)))
|
||||
#define sin_f32(v) sinf(radians_from_turns_f32(v))
|
||||
#define cos_f32(v) cosf(radians_from_turns_f32(v))
|
||||
#define tan_f32(v) tanf(radians_from_turns_f32(v))
|
||||
|
||||
#define sqrt_f64(v) sqrt(v)
|
||||
#define mod_f64(a, b) fmod((a), (b))
|
||||
#define pow_f64(b, e) pow((b), (e))
|
||||
#define ceil_f64(v) ceil(v)
|
||||
#define floor_f64(v) floor(v)
|
||||
#define round_f64(v) round(v)
|
||||
#define abs_f64(v) fabs(v)
|
||||
#define radians_from_turns_f64(v) ((v)*2*3.1415926535897)
|
||||
#define turns_from_radians_f64(v) ((v)/2*3.1415926535897)
|
||||
#define degrees_from_turns_f64(v) ((v)*360.0)
|
||||
#define turns_from_degrees_f64(v) ((v)/360.0)
|
||||
#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v)))
|
||||
#define radians_from_degrees_f64(v) (radians_from_turns_f64(turns_from_degrees_f64(v)))
|
||||
#define sin_f64(v) sin(radians_from_turns_f64(v))
|
||||
#define cos_f64(v) cos(radians_from_turns_f64(v))
|
||||
#define tan_f64(v) tan(radians_from_turns_f64(v))
|
||||
|
||||
internal F32 mix_1f32(F32 a, F32 b, F32 t);
|
||||
internal F64 mix_1f64(F64 a, F64 b, F64 t);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Vector Ops
|
||||
|
||||
#define v2f32(x, y) vec_2f32((x), (y))
|
||||
internal Vec2F32 vec_2f32(F32 x, F32 y);
|
||||
internal Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b);
|
||||
internal Vec2F32 sub_2f32(Vec2F32 a, Vec2F32 b);
|
||||
internal Vec2F32 mul_2f32(Vec2F32 a, Vec2F32 b);
|
||||
internal Vec2F32 div_2f32(Vec2F32 a, Vec2F32 b);
|
||||
internal Vec2F32 scale_2f32(Vec2F32 v, F32 s);
|
||||
internal F32 dot_2f32(Vec2F32 a, Vec2F32 b);
|
||||
internal F32 length_squared_2f32(Vec2F32 v);
|
||||
internal F32 length_2f32(Vec2F32 v);
|
||||
internal Vec2F32 normalize_2f32(Vec2F32 v);
|
||||
internal Vec2F32 mix_2f32(Vec2F32 a, Vec2F32 b, F32 t);
|
||||
|
||||
#define v2s64(x, y) vec_2s64((x), (y))
|
||||
internal Vec2S64 vec_2s64(S64 x, S64 y);
|
||||
internal Vec2S64 add_2s64(Vec2S64 a, Vec2S64 b);
|
||||
internal Vec2S64 sub_2s64(Vec2S64 a, Vec2S64 b);
|
||||
internal Vec2S64 mul_2s64(Vec2S64 a, Vec2S64 b);
|
||||
internal Vec2S64 div_2s64(Vec2S64 a, Vec2S64 b);
|
||||
internal Vec2S64 scale_2s64(Vec2S64 v, S64 s);
|
||||
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b);
|
||||
internal S64 length_squared_2s64(Vec2S64 v);
|
||||
internal S64 length_2s64(Vec2S64 v);
|
||||
internal Vec2S64 normalize_2s64(Vec2S64 v);
|
||||
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t);
|
||||
|
||||
#define v2s32(x, y) vec_2s32((x), (y))
|
||||
internal Vec2S32 vec_2s32(S32 x, S32 y);
|
||||
internal Vec2S32 add_2s32(Vec2S32 a, Vec2S32 b);
|
||||
internal Vec2S32 sub_2s32(Vec2S32 a, Vec2S32 b);
|
||||
internal Vec2S32 mul_2s32(Vec2S32 a, Vec2S32 b);
|
||||
internal Vec2S32 div_2s32(Vec2S32 a, Vec2S32 b);
|
||||
internal Vec2S32 scale_2s32(Vec2S32 v, S32 s);
|
||||
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b);
|
||||
internal S32 length_squared_2s32(Vec2S32 v);
|
||||
internal S32 length_2s32(Vec2S32 v);
|
||||
internal Vec2S32 normalize_2s32(Vec2S32 v);
|
||||
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t);
|
||||
|
||||
#define v2s16(x, y) vec_2s16((x), (y))
|
||||
internal Vec2S16 vec_2s16(S16 x, S16 y);
|
||||
internal Vec2S16 add_2s16(Vec2S16 a, Vec2S16 b);
|
||||
internal Vec2S16 sub_2s16(Vec2S16 a, Vec2S16 b);
|
||||
internal Vec2S16 mul_2s16(Vec2S16 a, Vec2S16 b);
|
||||
internal Vec2S16 div_2s16(Vec2S16 a, Vec2S16 b);
|
||||
internal Vec2S16 scale_2s16(Vec2S16 v, S16 s);
|
||||
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b);
|
||||
internal S16 length_squared_2s16(Vec2S16 v);
|
||||
internal S16 length_2s16(Vec2S16 v);
|
||||
internal Vec2S16 normalize_2s16(Vec2S16 v);
|
||||
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t);
|
||||
|
||||
#define v3f32(x, y, z) vec_3f32((x), (y), (z))
|
||||
internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z);
|
||||
internal Vec3F32 add_3f32(Vec3F32 a, Vec3F32 b);
|
||||
internal Vec3F32 sub_3f32(Vec3F32 a, Vec3F32 b);
|
||||
internal Vec3F32 mul_3f32(Vec3F32 a, Vec3F32 b);
|
||||
internal Vec3F32 div_3f32(Vec3F32 a, Vec3F32 b);
|
||||
internal Vec3F32 scale_3f32(Vec3F32 v, F32 s);
|
||||
internal F32 dot_3f32(Vec3F32 a, Vec3F32 b);
|
||||
internal F32 length_squared_3f32(Vec3F32 v);
|
||||
internal F32 length_3f32(Vec3F32 v);
|
||||
internal Vec3F32 normalize_3f32(Vec3F32 v);
|
||||
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
|
||||
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b);
|
||||
|
||||
#define v3s32(x, y, z) vec_3s32((x), (y), (z))
|
||||
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z);
|
||||
internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b);
|
||||
internal Vec3S32 sub_3s32(Vec3S32 a, Vec3S32 b);
|
||||
internal Vec3S32 mul_3s32(Vec3S32 a, Vec3S32 b);
|
||||
internal Vec3S32 div_3s32(Vec3S32 a, Vec3S32 b);
|
||||
internal Vec3S32 scale_3s32(Vec3S32 v, S32 s);
|
||||
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b);
|
||||
internal S32 length_squared_3s32(Vec3S32 v);
|
||||
internal S32 length_3s32(Vec3S32 v);
|
||||
internal Vec3S32 normalize_3s32(Vec3S32 v);
|
||||
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t);
|
||||
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b);
|
||||
|
||||
#define v4f32(x, y, z, w) vec_4f32((x), (y), (z), (w))
|
||||
internal Vec4F32 vec_4f32(F32 x, F32 y, F32 z, F32 w);
|
||||
internal Vec4F32 add_4f32(Vec4F32 a, Vec4F32 b);
|
||||
internal Vec4F32 sub_4f32(Vec4F32 a, Vec4F32 b);
|
||||
internal Vec4F32 mul_4f32(Vec4F32 a, Vec4F32 b);
|
||||
internal Vec4F32 div_4f32(Vec4F32 a, Vec4F32 b);
|
||||
internal Vec4F32 scale_4f32(Vec4F32 v, F32 s);
|
||||
internal F32 dot_4f32(Vec4F32 a, Vec4F32 b);
|
||||
internal F32 length_squared_4f32(Vec4F32 v);
|
||||
internal F32 length_4f32(Vec4F32 v);
|
||||
internal Vec4F32 normalize_4f32(Vec4F32 v);
|
||||
internal Vec4F32 mix_4f32(Vec4F32 a, Vec4F32 b, F32 t);
|
||||
|
||||
#define v4s32(x, y, z, w) vec_4s32((x), (y), (z), (w))
|
||||
internal Vec4S32 vec_4s32(S32 x, S32 y, S32 z, S32 w);
|
||||
internal Vec4S32 add_4s32(Vec4S32 a, Vec4S32 b);
|
||||
internal Vec4S32 sub_4s32(Vec4S32 a, Vec4S32 b);
|
||||
internal Vec4S32 mul_4s32(Vec4S32 a, Vec4S32 b);
|
||||
internal Vec4S32 div_4s32(Vec4S32 a, Vec4S32 b);
|
||||
internal Vec4S32 scale_4s32(Vec4S32 v, S32 s);
|
||||
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b);
|
||||
internal S32 length_squared_4s32(Vec4S32 v);
|
||||
internal S32 length_4s32(Vec4S32 v);
|
||||
internal Vec4S32 normalize_4s32(Vec4S32 v);
|
||||
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Matrix Ops
|
||||
|
||||
internal Mat3x3F32 mat_3x3f32(F32 diagonal);
|
||||
internal Mat3x3F32 make_translate_3x3f32(Vec2F32 delta);
|
||||
internal Mat3x3F32 make_scale_3x3f32(Vec2F32 scale);
|
||||
internal Mat3x3F32 mul_3x3f32(Mat3x3F32 a, Mat3x3F32 b);
|
||||
|
||||
internal Mat4x4F32 mat_4x4f32(F32 diagonal);
|
||||
internal Mat4x4F32 make_translate_4x4f32(Vec3F32 delta);
|
||||
internal Mat4x4F32 make_scale_4x4f32(Vec3F32 scale);
|
||||
internal Mat4x4F32 make_perspective_4x4f32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z);
|
||||
internal Mat4x4F32 make_orthographic_4x4f32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z);
|
||||
internal Mat4x4F32 make_look_at_4x4f32(Vec3F32 eye, Vec3F32 center, Vec3F32 up);
|
||||
internal Mat4x4F32 make_rotate_4x4f32(Vec3F32 axis, F32 turns);
|
||||
internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b);
|
||||
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
|
||||
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
|
||||
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Range Ops
|
||||
|
||||
#define r1u32(min, max) rng_1u32((min), (max))
|
||||
internal Rng1U32 rng_1u32(U32 min, U32 max);
|
||||
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x);
|
||||
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x);
|
||||
internal U32 center_1u32(Rng1U32 r);
|
||||
internal B32 contains_1u32(Rng1U32 r, U32 x);
|
||||
internal U32 dim_1u32(Rng1U32 r);
|
||||
internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b);
|
||||
internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b);
|
||||
internal U32 clamp_1u32(Rng1U32 r, U32 v);
|
||||
|
||||
#define r1s32(min, max) rng_1s32((min), (max))
|
||||
internal Rng1S32 rng_1s32(S32 min, S32 max);
|
||||
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x);
|
||||
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x);
|
||||
internal S32 center_1s32(Rng1S32 r);
|
||||
internal B32 contains_1s32(Rng1S32 r, S32 x);
|
||||
internal S32 dim_1s32(Rng1S32 r);
|
||||
internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b);
|
||||
internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b);
|
||||
internal S32 clamp_1s32(Rng1S32 r, S32 v);
|
||||
|
||||
#define r1u64(min, max) rng_1u64((min), (max))
|
||||
internal Rng1U64 rng_1u64(U64 min, U64 max);
|
||||
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x);
|
||||
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x);
|
||||
internal U64 center_1u64(Rng1U64 r);
|
||||
internal B32 contains_1u64(Rng1U64 r, U64 x);
|
||||
internal U64 dim_1u64(Rng1U64 r);
|
||||
internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b);
|
||||
internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b);
|
||||
internal U64 clamp_1u64(Rng1U64 r, U64 v);
|
||||
|
||||
#define r1s64(min, max) rng_1s64((min), (max))
|
||||
internal Rng1S64 rng_1s64(S64 min, S64 max);
|
||||
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x);
|
||||
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x);
|
||||
internal S64 center_1s64(Rng1S64 r);
|
||||
internal B32 contains_1s64(Rng1S64 r, S64 x);
|
||||
internal S64 dim_1s64(Rng1S64 r);
|
||||
internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b);
|
||||
internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b);
|
||||
internal S64 clamp_1s64(Rng1S64 r, S64 v);
|
||||
|
||||
#define r1f32(min, max) rng_1f32((min), (max))
|
||||
internal Rng1F32 rng_1f32(F32 min, F32 max);
|
||||
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x);
|
||||
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x);
|
||||
internal F32 center_1f32(Rng1F32 r);
|
||||
internal B32 contains_1f32(Rng1F32 r, F32 x);
|
||||
internal F32 dim_1f32(Rng1F32 r);
|
||||
internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b);
|
||||
internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b);
|
||||
internal F32 clamp_1f32(Rng1F32 r, F32 v);
|
||||
|
||||
#define r2s16(min, max) rng_2s16((min), (max))
|
||||
#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w)))
|
||||
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
|
||||
internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x);
|
||||
internal Rng2S16 pad_2s16(Rng2S16 r, S16 x);
|
||||
internal Vec2S16 center_2s16(Rng2S16 r);
|
||||
internal B32 contains_2s16(Rng2S16 r, Vec2S16 x);
|
||||
internal Vec2S16 dim_2s16(Rng2S16 r);
|
||||
internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b);
|
||||
internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b);
|
||||
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v);
|
||||
|
||||
#define r2s32(min, max) rng_2s32((min), (max))
|
||||
#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w)))
|
||||
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
|
||||
internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x);
|
||||
internal Rng2S32 pad_2s32(Rng2S32 r, S32 x);
|
||||
internal Vec2S32 center_2s32(Rng2S32 r);
|
||||
internal B32 contains_2s32(Rng2S32 r, Vec2S32 x);
|
||||
internal Vec2S32 dim_2s32(Rng2S32 r);
|
||||
internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b);
|
||||
internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b);
|
||||
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v);
|
||||
|
||||
#define r2s64(min, max) rng_2s64((min), (max))
|
||||
#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w)))
|
||||
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
|
||||
internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x);
|
||||
internal Rng2S64 pad_2s64(Rng2S64 r, S64 x);
|
||||
internal Vec2S64 center_2s64(Rng2S64 r);
|
||||
internal B32 contains_2s64(Rng2S64 r, Vec2S64 x);
|
||||
internal Vec2S64 dim_2s64(Rng2S64 r);
|
||||
internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b);
|
||||
internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b);
|
||||
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v);
|
||||
|
||||
#define r2f32(min, max) rng_2f32((min), (max))
|
||||
#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w)))
|
||||
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
|
||||
internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x);
|
||||
internal Rng2F32 pad_2f32(Rng2F32 r, F32 x);
|
||||
internal Vec2F32 center_2f32(Rng2F32 r);
|
||||
internal B32 contains_2f32(Rng2F32 r, Vec2F32 x);
|
||||
internal Vec2F32 dim_2f32(Rng2F32 r);
|
||||
internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b);
|
||||
internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b);
|
||||
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Miscellaneous Ops
|
||||
|
||||
internal Vec3F32 hsv_from_rgb(Vec3F32 rgb);
|
||||
internal Vec3F32 rgb_from_hsv(Vec3F32 hsv);
|
||||
internal Vec4F32 hsva_from_rgba(Vec4F32 rgba);
|
||||
internal Vec4F32 rgba_from_hsva(Vec4F32 hsva);
|
||||
internal Vec4F32 rgba_from_u32(U32 hex);
|
||||
internal U32 u32_from_rgba(Vec4F32 rgba);
|
||||
|
||||
#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f }
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: List Type Functions
|
||||
|
||||
internal void rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
|
||||
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
|
||||
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
|
||||
|
||||
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
|
||||
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
|
||||
|
||||
#endif // BASE_MATH_H
|
||||
422
src/metagen/metagen_base/metagen_base_meta.c
Normal file
422
src/metagen/metagen_base/metagen_base_meta.c
Normal file
@ -0,0 +1,422 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info Lookups
|
||||
|
||||
internal Member *
|
||||
member_from_name(Type *type, String8 name)
|
||||
{
|
||||
Member *member = &member_nil;
|
||||
if(type->members != 0 && name.size != 0)
|
||||
{
|
||||
for(U64 idx = 0; idx < type->count; idx += 1)
|
||||
{
|
||||
if(str8_match(type->members[idx].name, name, 0))
|
||||
{
|
||||
member = &type->members[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return member;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info * Instance Operations
|
||||
|
||||
internal void
|
||||
typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
typedef struct RebaseTypeTask RebaseTypeTask;
|
||||
struct RebaseTypeTask
|
||||
{
|
||||
RebaseTypeTask *next;
|
||||
Type *type;
|
||||
U8 *ptr;
|
||||
};
|
||||
RebaseTypeTask start_task = {0, type, data.str};
|
||||
RebaseTypeTask *first_task = &start_task;
|
||||
RebaseTypeTask *last_task = first_task;
|
||||
for(RebaseTypeTask *t = first_task; t != 0; t = t->next)
|
||||
{
|
||||
switch(t->type->kind)
|
||||
{
|
||||
default:{}break;
|
||||
case TypeKind_Ptr:
|
||||
if(!(t->type->flags & TypeFlag_IsExternal))
|
||||
{
|
||||
*(U64 *)t->ptr = ((U64)(*(U8 **)t->ptr - (U8 *)base_ptr));
|
||||
}break;
|
||||
case TypeKind_Array:
|
||||
{
|
||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
||||
{
|
||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->ptr = t->ptr + t->type->direct->size * idx;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
}break;
|
||||
case TypeKind_Struct:
|
||||
{
|
||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
||||
{
|
||||
Member *member = &t->type->members[idx];
|
||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
||||
task->type = member->type;
|
||||
task->ptr = t->ptr + member->value;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal String8
|
||||
serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List strings = {0};
|
||||
str8_serial_begin(scratch.arena, &strings);
|
||||
{
|
||||
typedef struct SerializeTypeTask SerializeTypeTask;
|
||||
struct SerializeTypeTask
|
||||
{
|
||||
SerializeTypeTask *next;
|
||||
Type *type;
|
||||
U64 count;
|
||||
U8 *src;
|
||||
Type *containing_type;
|
||||
U8 *containing_ptr;
|
||||
B32 is_post_header;
|
||||
};
|
||||
SerializeTypeTask start_task = {0, type, 1, data.str};
|
||||
SerializeTypeTask *first_task = &start_task;
|
||||
SerializeTypeTask *last_task = first_task;
|
||||
for(SerializeTypeTask *t = first_task; t != 0; t = t->next)
|
||||
{
|
||||
switch(t->type->kind)
|
||||
{
|
||||
//- rjf: leaf -> just copy the data directly
|
||||
default:
|
||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
||||
{
|
||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
||||
}break;
|
||||
|
||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise just write as plain data
|
||||
case TypeKind_Ptr:
|
||||
{
|
||||
// rjf: unpack info about this pointer
|
||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
||||
{
|
||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
||||
{
|
||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: indexification -> subtract base, divide direct size, write index
|
||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
||||
{
|
||||
U64 ptr_value = 0;
|
||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
||||
U64 ptr_write_value = ((U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->indexify_base)/t->type->direct->size);
|
||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
||||
}
|
||||
|
||||
// rjf: offsetification -> subtract base, write offsets
|
||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
||||
{
|
||||
U64 ptr_value = 0;
|
||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
||||
U64 ptr_write_value = (U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->offsetify_base);
|
||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
||||
}
|
||||
|
||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
||||
// delimit our size, so push a new post-header task for pointer.
|
||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
||||
{
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type;
|
||||
task->count = t->count;
|
||||
task->src = t->src;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
task->is_post_header = 1;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
|
||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
||||
// destination contents
|
||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
||||
{
|
||||
// rjf: determine count of this pointer
|
||||
U64 count = 0;
|
||||
{
|
||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
||||
}
|
||||
|
||||
// rjf: push task
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = count;
|
||||
task->src = *(void **)t->src;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
|
||||
// rjf: catch-all: write pointer value
|
||||
else
|
||||
{
|
||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: arrays -> descend to underlying type, + count
|
||||
case TypeKind_Array:
|
||||
{
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = t->type->count;
|
||||
task->src = t->src;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}break;
|
||||
|
||||
//- rjf: struct -> descend to members
|
||||
case TypeKind_Struct:
|
||||
{
|
||||
U64 off = 0;
|
||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
||||
{
|
||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
||||
{
|
||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type->members[member_idx].type;
|
||||
task->count = 1;
|
||||
task->src = t->src + idx*t->type->size + t->type->members[member_idx].value;
|
||||
task->containing_type = t->type;
|
||||
task->containing_ptr = t->src;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: enum -> descend to basic type interpretation
|
||||
case TypeKind_Enum:
|
||||
{
|
||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = t->count;
|
||||
task->src = t->src;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
String8 result = str8_serial_end(arena, &strings);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
||||
{
|
||||
String8 result = {0};
|
||||
result.size = type->size;
|
||||
result.str = push_array(arena, U8, result.size);
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
typedef struct DeserializeTypeTask DeserializeTypeTask;
|
||||
struct DeserializeTypeTask
|
||||
{
|
||||
DeserializeTypeTask *next;
|
||||
Type *type;
|
||||
U64 count;
|
||||
U8 *dst;
|
||||
Type *containing_type;
|
||||
U8 *containing_ptr;
|
||||
B32 is_post_header;
|
||||
};
|
||||
U64 read_off = 0;
|
||||
DeserializeTypeTask start_task = {0, type, 1, result.str};
|
||||
DeserializeTypeTask *first_task = &start_task;
|
||||
DeserializeTypeTask *last_task = first_task;
|
||||
for(DeserializeTypeTask *t = first_task; t != 0; t = t->next)
|
||||
{
|
||||
U8 *t_src = data.str + read_off;
|
||||
switch(t->type->kind)
|
||||
{
|
||||
//- rjf: leaf -> copy the data directly
|
||||
default:
|
||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
||||
{
|
||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
||||
read_off += t->type->size*t->count;
|
||||
}break;
|
||||
|
||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise skip
|
||||
case TypeKind_Ptr:
|
||||
{
|
||||
// rjf: unpack info about this pointer
|
||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
||||
{
|
||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
||||
{
|
||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: indexification -> add base, multiply direct size
|
||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
||||
{
|
||||
U64 ptr_value = 0;
|
||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
||||
U64 ptr_write_value = (ptr_value + (U64)ptr_ref_info->indexify_base) * t->type->direct->size;
|
||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
||||
read_off += sizeof(ptr_value);
|
||||
}
|
||||
|
||||
// rjf: offsetification -> subtract base, write offsets
|
||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
||||
{
|
||||
U64 ptr_value = 0;
|
||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
||||
U64 ptr_write_value = ptr_value + (U64)ptr_ref_info->offsetify_base;
|
||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
||||
read_off += sizeof(ptr_value);
|
||||
}
|
||||
|
||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
||||
// delimit our size, so push a new post-header task for pointer.
|
||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
||||
{
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type;
|
||||
task->count = t->count;
|
||||
task->dst = t->dst;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
task->is_post_header = 1;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
|
||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
||||
// destination contents
|
||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
||||
{
|
||||
// rjf: determine count of this pointer
|
||||
U64 count = 0;
|
||||
{
|
||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
||||
}
|
||||
|
||||
// rjf: allocate buffer for pointer destination; write address into pointer value slot
|
||||
U64 ptr_dest_buffer_size = (count+1)*t->type->direct->size;
|
||||
U8 *ptr_dest_buffer = push_array(arena, U8, ptr_dest_buffer_size);
|
||||
MemoryCopy(t->dst, &ptr_dest_buffer, sizeof(ptr_dest_buffer));
|
||||
|
||||
// rjf: push task
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = count;
|
||||
task->dst = ptr_dest_buffer;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
|
||||
// rjf: catch-all: read pointer value
|
||||
else
|
||||
{
|
||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
||||
read_off += t->type->size*t->count;
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: arrays -> descend to underlying type, + count
|
||||
case TypeKind_Array:
|
||||
{
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = t->type->count;
|
||||
task->dst = t->dst;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}break;
|
||||
|
||||
//- rjf: struct -> descend to members
|
||||
case TypeKind_Struct:
|
||||
{
|
||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
||||
{
|
||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
||||
{
|
||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type->members[member_idx].type;
|
||||
task->count = 1;
|
||||
task->dst = t->dst + idx*t->type->size + t->type->members[member_idx].value;
|
||||
task->containing_type = t->type;
|
||||
task->containing_ptr = t->dst;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: enum -> descend to basic type interpretation
|
||||
case TypeKind_Enum:
|
||||
{
|
||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
||||
task->type = t->type->direct;
|
||||
task->count = t->count;
|
||||
task->dst = t->dst;
|
||||
task->containing_type = t->containing_type;
|
||||
task->containing_ptr = t->containing_ptr;
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
if(params->advance_out != 0)
|
||||
{
|
||||
params->advance_out[0] = read_off;
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 data_srlz = serialized_from_typed_data(scratch.arena, type, data, params);
|
||||
String8 data_copy = deserialized_from_typed_data(arena, type, data_srlz, params);
|
||||
scratch_end(scratch);
|
||||
return data_copy;
|
||||
}
|
||||
298
src/metagen/metagen_base/metagen_base_meta.h
Normal file
298
src/metagen/metagen_base/metagen_base_meta.h
Normal file
@ -0,0 +1,298 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_META_H
|
||||
#define BASE_META_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Meta Markup Features
|
||||
|
||||
#define EmbedFile(name, path)
|
||||
#define TweakB32(name, default) (TWEAK_##name)
|
||||
#define TweakF32(name, default, min, max) (TWEAK_##name)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tweak Info Tables
|
||||
|
||||
typedef struct TweakB32Info TweakB32Info;
|
||||
struct TweakB32Info
|
||||
{
|
||||
String8 name;
|
||||
B32 default_value;
|
||||
B32 *value_ptr;
|
||||
};
|
||||
|
||||
typedef struct TweakF32Info TweakF32Info;
|
||||
struct TweakF32Info
|
||||
{
|
||||
String8 name;
|
||||
F32 default_value;
|
||||
Rng1F32 value_range;
|
||||
F32 *value_ptr;
|
||||
};
|
||||
|
||||
typedef struct TweakB32InfoTable TweakB32InfoTable;
|
||||
struct TweakB32InfoTable
|
||||
{
|
||||
TweakB32Info *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct TweakF32InfoTable TweakF32InfoTable;
|
||||
struct TweakF32InfoTable
|
||||
{
|
||||
TweakF32Info *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct EmbedInfo EmbedInfo;
|
||||
struct EmbedInfo
|
||||
{
|
||||
String8 name;
|
||||
String8 *data;
|
||||
U128 *hash;
|
||||
};
|
||||
|
||||
typedef struct EmbedInfoTable EmbedInfoTable;
|
||||
struct EmbedInfoTable
|
||||
{
|
||||
EmbedInfo *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info Types
|
||||
|
||||
typedef enum TypeKind
|
||||
{
|
||||
TypeKind_Null,
|
||||
|
||||
// rjf: leaves
|
||||
TypeKind_Void, TypeKind_FirstLeaf = TypeKind_Void,
|
||||
TypeKind_U8,
|
||||
TypeKind_U16,
|
||||
TypeKind_U32,
|
||||
TypeKind_U64,
|
||||
TypeKind_S8,
|
||||
TypeKind_S16,
|
||||
TypeKind_S32,
|
||||
TypeKind_S64,
|
||||
TypeKind_B8,
|
||||
TypeKind_B16,
|
||||
TypeKind_B32,
|
||||
TypeKind_B64,
|
||||
TypeKind_F32,
|
||||
TypeKind_F64, TypeKind_LastLeaf = TypeKind_F64,
|
||||
|
||||
// rjf: operators
|
||||
TypeKind_Ptr,
|
||||
TypeKind_Array,
|
||||
|
||||
// rjf: user-defined-types
|
||||
TypeKind_Struct,
|
||||
TypeKind_Union,
|
||||
TypeKind_Enum,
|
||||
|
||||
TypeKind_COUNT
|
||||
}
|
||||
TypeKind;
|
||||
|
||||
typedef U32 TypeFlags;
|
||||
enum
|
||||
{
|
||||
TypeFlag_IsExternal = (1<<0),
|
||||
TypeFlag_IsPlainText = (1<<1),
|
||||
TypeFlag_IsCodeText = (1<<2),
|
||||
TypeFlag_IsPathText = (1<<3),
|
||||
};
|
||||
|
||||
typedef U32 MemberFlags;
|
||||
enum
|
||||
{
|
||||
MemberFlag_DoNotSerialize = (1<<0),
|
||||
};
|
||||
|
||||
typedef struct Type Type;
|
||||
typedef struct Member Member;
|
||||
struct Member
|
||||
{
|
||||
String8 name;
|
||||
String8 pretty_name;
|
||||
Type *type;
|
||||
U64 value;
|
||||
MemberFlags flags;
|
||||
};
|
||||
|
||||
typedef struct Type Type;
|
||||
struct Type
|
||||
{
|
||||
TypeKind kind;
|
||||
TypeFlags flags;
|
||||
U64 size;
|
||||
Type *direct;
|
||||
String8 name;
|
||||
String8 count_delimiter_name; // gathered from surrounding members, turns *->[1] into *->[N]
|
||||
U64 count;
|
||||
Member *members;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Serialization Parameters
|
||||
|
||||
typedef struct TypeSerializePtrRefInfo TypeSerializePtrRefInfo;
|
||||
struct TypeSerializePtrRefInfo
|
||||
{
|
||||
Type *type; // pointers to this
|
||||
void *indexify_base; // can be indexified using this
|
||||
void *offsetify_base; // can be offsetified using this
|
||||
void *nil_ptr; // is terminal if matching 0 or this
|
||||
};
|
||||
|
||||
typedef struct TypeSerializeParams TypeSerializeParams;
|
||||
struct TypeSerializeParams
|
||||
{
|
||||
U64 *advance_out;
|
||||
TypeSerializePtrRefInfo *ptr_ref_infos;
|
||||
U64 ptr_ref_infos_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Name -> Type Info
|
||||
|
||||
#define type(T) (&T##__type)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info Table Initializer Helpers
|
||||
|
||||
#define member_lit_comp(S, ti, m, ...) {str8_lit_comp(#m), {0}, (ti), OffsetOf(S, m), __VA_ARGS__}
|
||||
#define struct_members(S) read_only global Member S##__members[] =
|
||||
#define struct_type(S, ...) read_only global Type S##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#S), {0}, ArrayCount(S##__members), S##__members, __VA_ARGS__}
|
||||
#define named_struct_type(name, S, ...) read_only global Type name##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#name), {0}, ArrayCount(name##__members), name##__members, __VA_ARGS__}
|
||||
#define ptr_type(name, ti, ...) read_only global Type name = {TypeKind_Ptr, 0, sizeof(void *), (ti), __VA_ARGS__}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global Type type_nil = {TypeKind_Null, 0, 0, &type_nil};
|
||||
read_only global Member member_nil = {{0}, {0}, &type_nil};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Built-In Types
|
||||
|
||||
//- rjf: leaves
|
||||
read_only global Type void__type = {TypeKind_Void, 0, 0, &type_nil, str8_lit_comp("void")};
|
||||
read_only global Type U8__type = {TypeKind_U8, 0, sizeof(U8), &type_nil, str8_lit_comp("U8")};
|
||||
read_only global Type U16__type = {TypeKind_U16, 0, sizeof(U16), &type_nil, str8_lit_comp("U16")};
|
||||
read_only global Type U32__type = {TypeKind_U32, 0, sizeof(U32), &type_nil, str8_lit_comp("U32")};
|
||||
read_only global Type U64__type = {TypeKind_U64, 0, sizeof(U64), &type_nil, str8_lit_comp("U64")};
|
||||
read_only global Type S8__type = {TypeKind_S8, 0, sizeof(S8), &type_nil, str8_lit_comp("S8")};
|
||||
read_only global Type S16__type = {TypeKind_S16, 0, sizeof(S16), &type_nil, str8_lit_comp("S16")};
|
||||
read_only global Type S32__type = {TypeKind_S32, 0, sizeof(S32), &type_nil, str8_lit_comp("S32")};
|
||||
read_only global Type S64__type = {TypeKind_S64, 0, sizeof(S64), &type_nil, str8_lit_comp("S64")};
|
||||
read_only global Type B8__type = {TypeKind_B8, 0, sizeof(B8), &type_nil, str8_lit_comp("B8")};
|
||||
read_only global Type B16__type = {TypeKind_B16, 0, sizeof(B16), &type_nil, str8_lit_comp("B16")};
|
||||
read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, str8_lit_comp("B32")};
|
||||
read_only global Type B64__type = {TypeKind_B64, 0, sizeof(B64), &type_nil, str8_lit_comp("B64")};
|
||||
read_only global Type F32__type = {TypeKind_F32, 0, sizeof(F32), &type_nil, str8_lit_comp("F32")};
|
||||
read_only global Type F64__type = {TypeKind_F64, 0, sizeof(F64), &type_nil, str8_lit_comp("F64")};
|
||||
read_only global Type *type_kind_type_table[] =
|
||||
{
|
||||
&type_nil,
|
||||
type(void),
|
||||
type(U8),
|
||||
type(U16),
|
||||
type(U32),
|
||||
type(U64),
|
||||
type(S8),
|
||||
type(S16),
|
||||
type(S32),
|
||||
type(S64),
|
||||
type(B8),
|
||||
type(B16),
|
||||
type(B32),
|
||||
type(B64),
|
||||
type(F32),
|
||||
type(F64),
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
};
|
||||
|
||||
//- rjf: Rng1U64
|
||||
struct_members(Rng1U64)
|
||||
{
|
||||
member_lit_comp(Rng1U64, type(U64), min),
|
||||
member_lit_comp(Rng1U64, type(U64), max),
|
||||
};
|
||||
struct_type(Rng1U64);
|
||||
|
||||
//- rjf: String8
|
||||
ptr_type(String8__str_ptr_type, type(U8), str8_lit_comp("size"));
|
||||
struct_members(String8)
|
||||
{
|
||||
member_lit_comp(String8, &String8__str_ptr_type, str),
|
||||
member_lit_comp(String8, type(U64), size),
|
||||
};
|
||||
struct_type(String8);
|
||||
|
||||
//- rjf: String8Node
|
||||
extern Type String8Node__type;
|
||||
Type String8Node__ptr_type = {TypeKind_Ptr, 0, sizeof(void *), &String8Node__type};
|
||||
Member String8Node__members[] =
|
||||
{
|
||||
{str8_lit_comp("next"), {0}, &String8Node__ptr_type, OffsetOf(String8Node, next)},
|
||||
{str8_lit_comp("string"), {0}, type(String8), OffsetOf(String8Node, string)},
|
||||
};
|
||||
Type String8Node__type =
|
||||
{
|
||||
TypeKind_Struct,
|
||||
0,
|
||||
sizeof(String8Node),
|
||||
&type_nil,
|
||||
str8_lit_comp("String8Node"),
|
||||
{0},
|
||||
ArrayCount(String8Node__members),
|
||||
String8Node__members,
|
||||
};
|
||||
|
||||
//- rjf: String8List
|
||||
Member String8List__members[] =
|
||||
{
|
||||
{str8_lit_comp("first"), {0}, &String8Node__ptr_type, OffsetOf(String8List, first)},
|
||||
{str8_lit_comp("last"), {0}, &String8Node__ptr_type, OffsetOf(String8List, last), MemberFlag_DoNotSerialize},
|
||||
{str8_lit_comp("node_count"), {0}, type(U64), OffsetOf(String8List, node_count)},
|
||||
{str8_lit_comp("total_size"), {0}, type(U64), OffsetOf(String8List, total_size)},
|
||||
};
|
||||
Type String8List__type =
|
||||
{
|
||||
TypeKind_Struct,
|
||||
0,
|
||||
sizeof(String8List),
|
||||
&type_nil,
|
||||
str8_lit_comp("String8List"),
|
||||
{0},
|
||||
ArrayCount(String8List__members),
|
||||
String8List__members,
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info Lookups
|
||||
|
||||
internal Member *member_from_name(Type *type, String8 name);
|
||||
#define EachMember(T, it) (Member *it = (type(T))->members; it != 0 && it < (type(T))->members + (type(T))->count; it += 1)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Info * Instance Operations
|
||||
|
||||
internal void typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr);
|
||||
internal String8 serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
||||
internal String8 deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
||||
internal String8 deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
||||
#define struct_rebase_ptrs(T, ptr, base) typed_data_rebase_ptrs(type(T), str8_struct(ptr), (base))
|
||||
#define serialized_from_struct(arena, T, ptr, ...) serialized_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__})
|
||||
#define struct_from_serialized(arena, T, string, ...) (T *)deserialized_from_typed_data((arena), type(T), (string), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
||||
#define deep_copy_from_struct(arena, T, ptr, ...) (T *)deep_copy_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
||||
|
||||
#endif // BASE_META_H
|
||||
2
src/metagen/metagen_base/metagen_base_profile.c
Normal file
2
src/metagen/metagen_base/metagen_base_profile.c
Normal file
@ -0,0 +1,2 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
96
src/metagen/metagen_base/metagen_base_profile.h
Normal file
96
src/metagen/metagen_base/metagen_base_profile.h
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_PROFILE_H
|
||||
#define BASE_PROFILE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zero Settings
|
||||
|
||||
#if !defined(PROFILE_TELEMETRY)
|
||||
# define PROFILE_TELEMETRY 0
|
||||
#endif
|
||||
|
||||
#if !defined(MARKUP_LAYER_COLOR)
|
||||
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# include "rad_tm.h"
|
||||
# if OS_WINDOWS
|
||||
# pragma comment(lib, "rad_tm_win64.lib")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Telemetry Profile Defines
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
|
||||
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
|
||||
# define ProfTick(...) tmTick(0)
|
||||
# define ProfIsCapturing(...) tmRunning()
|
||||
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
|
||||
# define ProfEndCapture(...) tmClose(0)
|
||||
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
|
||||
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
|
||||
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
||||
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
||||
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
||||
# define ProfColor(color) tmZoneColorSticky(color)
|
||||
# define ProfBeginV(...) \
|
||||
if (TM_API_PTR) { \
|
||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
||||
Temp scratch = scratch_begin(0,0); \
|
||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
||||
TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \
|
||||
scratch_end(scratch); \
|
||||
}
|
||||
# define ProfNoteV(...) \
|
||||
if (TM_API_PTR) { \
|
||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
||||
Temp scratch = scratch_begin(0,0); \
|
||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
||||
TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \
|
||||
scratch_end(scratch); \
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zeroify Undefined Defines
|
||||
|
||||
#if !defined(ProfBegin)
|
||||
# define ProfBegin(...) (0)
|
||||
# define ProfBeginDynamic(...) (0)
|
||||
# define ProfEnd(...) (0)
|
||||
# define ProfTick(...) (0)
|
||||
# define ProfIsCapturing(...) (0)
|
||||
# define ProfBeginCapture(...) (0)
|
||||
# define ProfEndCapture(...) (0)
|
||||
# define ProfThreadName(...) (0)
|
||||
# define ProfMsg(...) (0)
|
||||
# define ProfBeginLockWait(...) (0)
|
||||
# define ProfEndLockWait(...) (0)
|
||||
# define ProfLockTake(...) (0)
|
||||
# define ProfLockDrop(...) (0)
|
||||
# define ProfColor(...) (0)
|
||||
# define ProfBeginV(...) (0)
|
||||
# define ProfNoteV(...) (0)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helper Wrappers
|
||||
|
||||
#define ProfBeginFunction(...) ProfBegin(this_function_name)
|
||||
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
|
||||
|
||||
#endif // BASE_PROFILE_H
|
||||
2446
src/metagen/metagen_base/metagen_base_strings.c
Normal file
2446
src/metagen/metagen_base/metagen_base_strings.c
Normal file
File diff suppressed because it is too large
Load Diff
412
src/metagen/metagen_base/metagen_base_strings.h
Normal file
412
src/metagen/metagen_base/metagen_base_strings.h
Normal file
@ -0,0 +1,412 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_STRINGS_H
|
||||
#define BASE_STRINGS_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Third Party Includes
|
||||
|
||||
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
||||
#include "../third_party/stb/stb_sprintf.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Types
|
||||
|
||||
typedef struct String8 String8;
|
||||
struct String8
|
||||
{
|
||||
U8 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String16 String16;
|
||||
struct String16
|
||||
{
|
||||
U16 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct String32 String32;
|
||||
struct String32
|
||||
{
|
||||
U32 *str;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List & Array Types
|
||||
|
||||
typedef struct String8Node String8Node;
|
||||
struct String8Node
|
||||
{
|
||||
String8Node *next;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct String8MetaNode String8MetaNode;
|
||||
struct String8MetaNode
|
||||
{
|
||||
String8MetaNode *next;
|
||||
String8Node *node;
|
||||
};
|
||||
|
||||
typedef struct String8List String8List;
|
||||
struct String8List
|
||||
{
|
||||
String8Node *first;
|
||||
String8Node *last;
|
||||
U64 node_count;
|
||||
U64 total_size;
|
||||
};
|
||||
|
||||
typedef struct String8Array String8Array;
|
||||
struct String8Array
|
||||
{
|
||||
String8 *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Matching, Splitting, & Joining Types
|
||||
|
||||
typedef U32 StringMatchFlags;
|
||||
enum
|
||||
{
|
||||
StringMatchFlag_CaseInsensitive = (1 << 0),
|
||||
StringMatchFlag_RightSideSloppy = (1 << 1),
|
||||
StringMatchFlag_SlashInsensitive = (1 << 2),
|
||||
};
|
||||
|
||||
typedef U32 StringSplitFlags;
|
||||
enum
|
||||
{
|
||||
StringSplitFlag_KeepEmpties = (1 << 0),
|
||||
};
|
||||
|
||||
typedef enum PathStyle
|
||||
{
|
||||
PathStyle_Null,
|
||||
PathStyle_Relative,
|
||||
PathStyle_WindowsAbsolute,
|
||||
PathStyle_UnixAbsolute,
|
||||
|
||||
#if OS_WINDOWS
|
||||
PathStyle_SystemAbsolute = PathStyle_WindowsAbsolute
|
||||
#elif OS_LINUX
|
||||
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
||||
#else
|
||||
# error "absolute path style is undefined for this OS"
|
||||
#endif
|
||||
}
|
||||
PathStyle;
|
||||
|
||||
typedef struct StringJoin StringJoin;
|
||||
struct StringJoin
|
||||
{
|
||||
String8 pre;
|
||||
String8 sep;
|
||||
String8 post;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Pair Types
|
||||
|
||||
typedef struct String8TxtPtPair String8TxtPtPair;
|
||||
struct String8TxtPtPair
|
||||
{
|
||||
String8 string;
|
||||
TxtPt pt;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF Decoding Types
|
||||
|
||||
typedef struct UnicodeDecode UnicodeDecode;
|
||||
struct UnicodeDecode
|
||||
{
|
||||
U32 inc;
|
||||
U32 codepoint;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Fuzzy Matching Types
|
||||
|
||||
typedef struct FuzzyMatchRangeNode FuzzyMatchRangeNode;
|
||||
struct FuzzyMatchRangeNode
|
||||
{
|
||||
FuzzyMatchRangeNode *next;
|
||||
Rng1U64 range;
|
||||
};
|
||||
|
||||
typedef struct FuzzyMatchRangeList FuzzyMatchRangeList;
|
||||
struct FuzzyMatchRangeList
|
||||
{
|
||||
FuzzyMatchRangeNode *first;
|
||||
FuzzyMatchRangeNode *last;
|
||||
U64 count;
|
||||
U64 needle_part_count;
|
||||
U64 total_dim;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Character Classification & Conversion Functions
|
||||
|
||||
internal B32 char_is_space(U8 c);
|
||||
internal B32 char_is_upper(U8 c);
|
||||
internal B32 char_is_lower(U8 c);
|
||||
internal B32 char_is_alpha(U8 c);
|
||||
internal B32 char_is_slash(U8 c);
|
||||
internal B32 char_is_digit(U8 c, U32 base);
|
||||
internal U8 char_to_lower(U8 c);
|
||||
internal U8 char_to_upper(U8 c);
|
||||
internal U8 char_to_correct_slash(U8 c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: C-String Measurement
|
||||
|
||||
internal U64 cstring8_length(U8 *c);
|
||||
internal U64 cstring16_length(U16 *c);
|
||||
internal U64 cstring32_length(U32 *c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Constructors
|
||||
|
||||
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
|
||||
#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,}
|
||||
#define str8_varg(S) (int)((S).size), ((S).str)
|
||||
|
||||
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
||||
#define str8_array_fixed(S) str8((U8*)(S), sizeof(S))
|
||||
#define str8_struct(S) str8((U8*)(S), sizeof(*(S)))
|
||||
|
||||
internal String8 str8(U8 *str, U64 size);
|
||||
internal String8 str8_range(U8 *first, U8 *one_past_last);
|
||||
internal String8 str8_zero(void);
|
||||
internal String16 str16(U16 *str, U64 size);
|
||||
internal String16 str16_range(U16 *first, U16 *one_past_last);
|
||||
internal String16 str16_zero(void);
|
||||
internal String32 str32(U32 *str, U64 size);
|
||||
internal String32 str32_range(U32 *first, U32 *one_past_last);
|
||||
internal String32 str32_zero(void);
|
||||
internal String8 str8_cstring(char *c);
|
||||
internal String16 str16_cstring(U16 *c);
|
||||
internal String32 str32_cstring(U32 *c);
|
||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||
internal String16 str16_cstring_capped(void *cstr, void *cap);
|
||||
internal String8 str8_cstring_capped_reverse(void *raw_start, void *raw_cap);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Stylization
|
||||
|
||||
internal String8 upper_from_str8(Arena *arena, String8 string);
|
||||
internal String8 lower_from_str8(Arena *arena, String8 string);
|
||||
internal String8 backslashed_from_str8(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Matching
|
||||
|
||||
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
||||
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Slicing
|
||||
|
||||
internal String8 str8_substr(String8 str, Rng1U64 range);
|
||||
internal String8 str8_prefix(String8 str, U64 size);
|
||||
internal String8 str8_skip(String8 str, U64 amt);
|
||||
internal String8 str8_postfix(String8 str, U64 size);
|
||||
internal String8 str8_chop(String8 str, U64 amt);
|
||||
internal String8 str8_skip_chop_whitespace(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Formatting & Copying
|
||||
|
||||
internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
|
||||
internal String8 push_str8_copy(Arena *arena, String8 s);
|
||||
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
|
||||
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Integer Conversions
|
||||
|
||||
//- rjf: string -> integer
|
||||
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
||||
internal B32 str8_is_integer(String8 string, U32 radix);
|
||||
|
||||
internal U64 u64_from_str8(String8 string, U32 radix);
|
||||
internal S64 s64_from_str8(String8 string, U32 radix);
|
||||
internal U32 u32_from_str8(String8 string, U32 radix);
|
||||
internal S32 s32_from_str8(String8 string, U32 radix);
|
||||
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
||||
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
||||
|
||||
//- rjf: integer -> string
|
||||
internal String8 str8_from_memory_size(Arena *arena, U64 size);
|
||||
internal String8 str8_from_count(Arena *arena, U64 count);
|
||||
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
|
||||
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
|
||||
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Float Conversions
|
||||
|
||||
internal F64 f64_from_str8(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String List Construction Functions
|
||||
|
||||
internal String8Node* str8_list_push_node(String8List *list, String8Node *node);
|
||||
internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string);
|
||||
internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node);
|
||||
internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string);
|
||||
internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string);
|
||||
internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
||||
internal void str8_list_concat_in_place(String8List *list, String8List *to_push);
|
||||
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
|
||||
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
||||
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
||||
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Splitting & Joining
|
||||
|
||||
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
||||
internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags);
|
||||
internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags);
|
||||
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
||||
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf; String Arrays
|
||||
|
||||
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
||||
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Path Helpers
|
||||
|
||||
internal String8 str8_chop_last_slash(String8 string);
|
||||
internal String8 str8_skip_last_slash(String8 string);
|
||||
internal String8 str8_chop_last_dot(String8 string);
|
||||
internal String8 str8_skip_last_dot(String8 string);
|
||||
|
||||
internal PathStyle path_style_from_str8(String8 string);
|
||||
internal String8List str8_split_path(Arena *arena, String8 string);
|
||||
internal void str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style);
|
||||
internal String8 str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style);
|
||||
|
||||
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||
|
||||
internal UnicodeDecode utf8_decode(U8 *str, U64 max);
|
||||
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
||||
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
||||
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
||||
internal U32 utf8_from_utf32_single(U8 *buffer, U32 character);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unicode String Conversions
|
||||
|
||||
internal String8 str8_from_16(Arena *arena, String16 in);
|
||||
internal String16 str16_from_8(Arena *arena, String8 in);
|
||||
internal String8 str8_from_32(Arena *arena, String32 in);
|
||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||
|
||||
////////////////////////////////
|
||||
//~ String -> Enum Conversions
|
||||
|
||||
internal OperatingSystem operating_system_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
internal String8 string_from_dimension(Dimension dimension);
|
||||
internal String8 string_from_side(Side side);
|
||||
internal String8 string_from_operating_system(OperatingSystem os);
|
||||
internal String8 string_from_arch(Arch arch);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Types -> String
|
||||
|
||||
internal String8 string_from_week_day(WeekDay week_day);
|
||||
internal String8 string_from_month(Month month);
|
||||
internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Globally Unique Ids
|
||||
|
||||
internal String8 string_from_guid(Arena *arena, Guid guid);
|
||||
internal B32 try_guid_from_string(String8 string, Guid *guid_out);
|
||||
internal Guid guid_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Text Indentation
|
||||
|
||||
internal String8 indented_from_string(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Escaping
|
||||
|
||||
internal String8 escaped_from_raw_str8(Arena *arena, String8 string);
|
||||
internal String8 raw_from_escaped_str8(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Wrapping
|
||||
|
||||
internal String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <-> Color
|
||||
|
||||
internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba);
|
||||
internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Fuzzy Matching
|
||||
|
||||
internal FuzzyMatchRangeList fuzzy_match_find(Arena *arena, String8 needle, String8 haystack);
|
||||
internal FuzzyMatchRangeList fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Serialization Helpers
|
||||
|
||||
internal void str8_serial_begin(Arena *arena, String8List *srl);
|
||||
internal String8 str8_serial_end(Arena *arena, String8List *srl);
|
||||
internal void str8_serial_write_to_dst(String8List *srl, void *out);
|
||||
internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 align);
|
||||
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
|
||||
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
|
||||
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
|
||||
internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
|
||||
internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
|
||||
internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
|
||||
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
||||
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
||||
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
||||
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
|
||||
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Deserialization Helpers
|
||||
|
||||
internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity);
|
||||
internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val);
|
||||
internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);
|
||||
internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
|
||||
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
|
||||
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
||||
internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out);
|
||||
internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out);
|
||||
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
||||
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1)
|
||||
|
||||
#endif // BASE_STRINGS_H
|
||||
87
src/metagen/metagen_base/metagen_base_thread_context.c
Normal file
87
src/metagen/metagen_base/metagen_base_thread_context.c
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context Functions
|
||||
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
||||
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
||||
#endif
|
||||
|
||||
internal void
|
||||
tctx_init_and_equip(TCTX *tctx){
|
||||
MemoryZeroStruct(tctx);
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
*arena_ptr = arena_alloc();
|
||||
}
|
||||
tctx_thread_local = tctx;
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_release(void)
|
||||
{
|
||||
for(U64 i = 0; i < ArrayCount(tctx_thread_local->arenas); i += 1)
|
||||
{
|
||||
arena_release(tctx_thread_local->arenas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal TCTX*
|
||||
tctx_get_equipped(void){
|
||||
return(tctx_thread_local);
|
||||
}
|
||||
|
||||
internal Arena*
|
||||
tctx_get_scratch(Arena **conflicts, U64 count){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
|
||||
Arena *result = 0;
|
||||
Arena **arena_ptr = tctx->arenas;
|
||||
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||
Arena **conflict_ptr = conflicts;
|
||||
B32 has_conflict = 0;
|
||||
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
|
||||
if (*arena_ptr == *conflict_ptr){
|
||||
has_conflict = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_conflict){
|
||||
result = *arena_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_set_thread_name(String8 string){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
|
||||
MemoryCopy(tctx->thread_name, string.str, size);
|
||||
tctx->thread_name_size = size;
|
||||
}
|
||||
|
||||
internal String8
|
||||
tctx_get_thread_name(void){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_write_srcloc(char *file_name, U64 line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
tctx->file_name = file_name;
|
||||
tctx->line_number = line_number;
|
||||
}
|
||||
|
||||
internal void
|
||||
tctx_read_srcloc(char **file_name, U64 *line_number){
|
||||
TCTX *tctx = tctx_get_equipped();
|
||||
*file_name = tctx->file_name;
|
||||
*line_number = tctx->line_number;
|
||||
}
|
||||
41
src/metagen/metagen_base/metagen_base_thread_context.h
Normal file
41
src/metagen/metagen_base/metagen_base_thread_context.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_THREAD_CONTEXT_H
|
||||
#define BASE_THREAD_CONTEXT_H
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context
|
||||
|
||||
typedef struct TCTX TCTX;
|
||||
struct TCTX
|
||||
{
|
||||
Arena *arenas[2];
|
||||
|
||||
U8 thread_name[32];
|
||||
U64 thread_name_size;
|
||||
|
||||
char *file_name;
|
||||
U64 line_number;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Thread Context Functions
|
||||
|
||||
internal void tctx_init_and_equip(TCTX *tctx);
|
||||
internal void tctx_release(void);
|
||||
internal TCTX* tctx_get_equipped(void);
|
||||
|
||||
internal Arena* tctx_get_scratch(Arena **conflicts, U64 countt);
|
||||
|
||||
internal void tctx_set_thread_name(String8 name);
|
||||
internal String8 tctx_get_thread_name(void);
|
||||
|
||||
internal void tctx_write_srcloc(char *file_name, U64 line_number);
|
||||
internal void tctx_read_srcloc(char **file_name, U64 *line_number);
|
||||
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
|
||||
|
||||
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
||||
#define scratch_end(scratch) temp_end(scratch)
|
||||
|
||||
#endif // BASE_THREAD_CONTEXT_H
|
||||
652
src/metagen/metagen_main.c
Normal file
652
src/metagen/metagen_main.c
Normal file
@ -0,0 +1,652 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Build Options
|
||||
|
||||
#define BUILD_CONSOLE_INTERFACE 1
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Includes
|
||||
|
||||
//- rjf: headers
|
||||
#include "metagen_base/metagen_base_inc.h"
|
||||
#include "metagen_os/metagen_os_inc.h"
|
||||
#include "../mdesk/mdesk.h"
|
||||
#include "metagen.h"
|
||||
|
||||
//- rjf: impls
|
||||
#include "metagen_base/metagen_base_inc.c"
|
||||
#include "metagen_os/metagen_os_inc.c"
|
||||
#include "../mdesk/mdesk.c"
|
||||
#include "metagen.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entry Point
|
||||
|
||||
internal void
|
||||
entry_point(CmdLine *cmdline)
|
||||
{
|
||||
//////////////////////////////
|
||||
//- rjf: set up state
|
||||
//
|
||||
MG_MsgList msgs = {0};
|
||||
mg_arena = arena_alloc(.reserve_size = GB(64), .commit_size = MB(64));
|
||||
mg_state = push_array(mg_arena, MG_State, 1);
|
||||
mg_state->slots_count = 256;
|
||||
mg_state->slots = push_array(mg_arena, MG_LayerSlot, mg_state->slots_count);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: extract paths
|
||||
//
|
||||
String8 build_dir_path = os_get_process_info()->binary_path;
|
||||
String8 project_dir_path = str8_chop_last_slash(build_dir_path);
|
||||
String8 code_dir_path = push_str8f(mg_arena, "%S/src", project_dir_path);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: search code directories for all files to consider
|
||||
//
|
||||
String8List file_paths = {0};
|
||||
DeferLoop(printf("searching %.*s...", str8_varg(code_dir_path)), printf(" %i files found\n", (int)file_paths.node_count))
|
||||
{
|
||||
typedef struct Task Task;
|
||||
struct Task
|
||||
{
|
||||
Task *next;
|
||||
String8 path;
|
||||
};
|
||||
Task start_task = {0, code_dir_path};
|
||||
Task *first_task = &start_task;
|
||||
Task *last_task = &start_task;
|
||||
for(Task *task = first_task; task != 0; task = task->next)
|
||||
{
|
||||
OS_FileIter *it = os_file_iter_begin(mg_arena, task->path, 0);
|
||||
for(OS_FileInfo info = {0}; os_file_iter_next(mg_arena, it, &info);)
|
||||
{
|
||||
String8 file_path = push_str8f(mg_arena, "%S/%S", task->path, info.name);
|
||||
if(info.props.flags & FilePropertyFlag_IsFolder)
|
||||
{
|
||||
Task *next_task = push_array(mg_arena, Task, 1);
|
||||
SLLQueuePush(first_task, last_task, next_task);
|
||||
next_task->path = file_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_push(mg_arena, &file_paths, file_path);
|
||||
}
|
||||
}
|
||||
os_file_iter_end(it);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: parse all metadesk files
|
||||
//
|
||||
MG_FileParseList parses = {0};
|
||||
DeferLoop(printf("parsing metadesk..."), printf(" %i metadesk files parsed\n", (int)parses.count))
|
||||
{
|
||||
for(String8Node *n = file_paths.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 file_path = n->string;
|
||||
String8 file_ext = str8_skip_last_dot(file_path);
|
||||
if(str8_match(file_ext, str8_lit("mdesk"), 0))
|
||||
{
|
||||
String8 data = os_data_from_file_path(mg_arena, file_path);
|
||||
MD_TokenizeResult tokenize = md_tokenize_from_text(mg_arena, data);
|
||||
MD_ParseResult parse = md_parse_from_text_tokens(mg_arena, file_path, data, tokenize.tokens);
|
||||
for(MD_Msg *m = parse.msgs.first; m != 0; m = m->next)
|
||||
{
|
||||
TxtPt pt = mg_txt_pt_from_string_off(data, m->node->src_offset);
|
||||
String8 msg_kind_string = {0};
|
||||
switch(m->kind)
|
||||
{
|
||||
default:{}break;
|
||||
case MD_MsgKind_Note: {msg_kind_string = str8_lit("note");}break;
|
||||
case MD_MsgKind_Warning: {msg_kind_string = str8_lit("warning");}break;
|
||||
case MD_MsgKind_Error: {msg_kind_string = str8_lit("error");}break;
|
||||
case MD_MsgKind_FatalError: {msg_kind_string = str8_lit("fatal error");}break;
|
||||
}
|
||||
String8 location = push_str8f(mg_arena, "%S:%I64d:%I64d", file_path, pt.line, pt.column);
|
||||
MG_Msg dst_m = {location, msg_kind_string, m->string};
|
||||
mg_msg_list_push(mg_arena, &msgs, &dst_m);
|
||||
}
|
||||
MG_FileParseNode *parse_n = push_array(mg_arena, MG_FileParseNode, 1);
|
||||
SLLQueuePush(parses.first, parses.last, parse_n);
|
||||
parse_n->v.root = parse.root;
|
||||
parses.count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather tables
|
||||
//
|
||||
MG_Map table_grid_map = mg_push_map(mg_arena, 1024);
|
||||
MG_Map table_col_map = mg_push_map(mg_arena, 1024);
|
||||
U64 table_count = 0;
|
||||
DeferLoop(printf("gathering tables..."), printf(" %i tables found\n", (int)table_count))
|
||||
{
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
MD_Node *table_tag = md_tag_from_string(node, str8_lit("table"), 0);
|
||||
if(!md_node_is_nil(table_tag))
|
||||
{
|
||||
MG_NodeGrid *table = push_array(mg_arena, MG_NodeGrid, 1);
|
||||
MG_ColumnDescArray *col_descs = push_array(mg_arena, MG_ColumnDescArray, 1);
|
||||
*table = mg_node_grid_make_from_node(mg_arena, node);
|
||||
*col_descs = mg_column_desc_array_from_tag(mg_arena, table_tag);
|
||||
mg_map_insert_ptr(mg_arena, &table_grid_map, node->string, table);
|
||||
mg_map_insert_ptr(mg_arena, &table_col_map, node->string, col_descs);
|
||||
table_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather layer options
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
if(md_node_has_tag(node, str8_lit("option"), 0))
|
||||
{
|
||||
if(str8_match(node->string, str8_lit("library"), 0))
|
||||
{
|
||||
layer->is_library = 1;
|
||||
}
|
||||
}
|
||||
if(md_node_has_tag(node, str8_lit("gen_folder"), 0))
|
||||
{
|
||||
layer->gen_folder_name = node->string;
|
||||
}
|
||||
if(md_node_has_tag(node, str8_lit("h_name"), 0))
|
||||
{
|
||||
layer->h_name_override = node->string;
|
||||
}
|
||||
if(md_node_has_tag(node, str8_lit("c_name"), 0))
|
||||
{
|
||||
layer->c_name_override = node->string;
|
||||
}
|
||||
if(md_node_has_tag(node, str8_lit("h_header"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &layer->h_header, n->string);
|
||||
str8_list_push(mg_arena, &layer->h_header, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
if(md_node_has_tag(node, str8_lit("h_footer"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &layer->h_footer, n->string);
|
||||
str8_list_push(mg_arena, &layer->h_footer, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
if(md_node_has_tag(node, str8_lit("c_header"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &layer->c_header, n->string);
|
||||
str8_list_push(mg_arena, &layer->c_header, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
if(md_node_has_tag(node, str8_lit("c_footer"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &layer->c_footer, n->string);
|
||||
str8_list_push(mg_arena, &layer->c_footer, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate enums
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
MD_Node *tag = md_tag_from_string(node, str8_lit("enum"), 0);
|
||||
if(!md_node_is_nil(tag))
|
||||
{
|
||||
String8 enum_name = node->string;
|
||||
String8 enum_member_prefix = enum_name;
|
||||
if(str8_match(str8_postfix(enum_name, 5), str8_lit("Flags"), 0))
|
||||
{
|
||||
enum_member_prefix = str8_chop(enum_name, 1);
|
||||
}
|
||||
String8 enum_base_type_name = tag->first->string;
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
if(enum_base_type_name.size == 0)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "typedef enum %S\n{\n", enum_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "typedef %S %S;\n", enum_base_type_name, enum_name);
|
||||
str8_list_pushf(mg_arena, &layer->enums, "typedef enum %SEnum\n{\n", enum_name);
|
||||
}
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "%S_%S,\n", enum_member_prefix, n->string);
|
||||
}
|
||||
if(enum_base_type_name.size == 0)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "} %S;\n\n", enum_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "} %SEnum;\n\n", enum_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate xlists
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
MD_Node *tag = md_tag_from_string(node, str8_lit("xlist"), 0);
|
||||
if(!md_node_is_nil(tag))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
str8_list_pushf(mg_arena, &layer->enums, "#define %S \\\n", node->string);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "X(%S)\\\n", n->string);
|
||||
}
|
||||
str8_list_push(mg_arena, &layer->enums, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate structs
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
if(md_node_has_tag(node, str8_lit("struct"), 0))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
str8_list_pushf(mg_arena, &layer->structs, "typedef struct %S %S;\n", node->string, node->string);
|
||||
str8_list_pushf(mg_arena, &layer->structs, "struct %S\n{\n", node->string);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->structs, "%S;\n", n->string);
|
||||
}
|
||||
str8_list_pushf(mg_arena, &layer->structs, "};\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate data tables
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
MD_Node *tag = md_tag_from_string(node, str8_lit("data"), 0);
|
||||
if(!md_node_is_nil(tag))
|
||||
{
|
||||
String8 element_type = tag->first->string;
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
if(!md_node_has_tag(node, str8_lit("c_file"), 0))
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "extern %S %S[%I64u];\n", element_type, node->string, gen_strings.node_count);
|
||||
}
|
||||
str8_list_pushf(mg_arena, &layer->c_tables, "%S %S[%I64u] =\n{\n", element_type, node->string, gen_strings.node_count);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->c_tables, "%S,\n", n->string);
|
||||
}
|
||||
str8_list_push(mg_arena, &layer->c_tables, str8_lit("};\n\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate enum -> string mapping functions
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
MD_Node *tag = md_tag_from_string(node, str8_lit("enum2string_switch"), 0);
|
||||
if(!md_node_is_nil(tag))
|
||||
{
|
||||
String8 enum_type = tag->first->string;
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
str8_list_pushf(mg_arena, &layer->h_functions, "internal String8 %S(%S v);\n", node->string, enum_type);
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "internal String8\n%S(%S v)\n{\n", node->string, enum_type);
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "String8 result = str8_lit(\"<Unknown %S>\");\n", enum_type);
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "switch(v)\n");
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "{\n");
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "default:{}break;\n");
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "%S;\n", n->string);
|
||||
}
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "}\n");
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "return result;\n");
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "}\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate catch-all generations
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
MD_Node *tag = md_tag_from_string(node, str8_lit("gen"), 0);
|
||||
if(!md_node_is_nil(tag))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
B32 prefer_c_file = md_node_has_tag(node, str8_lit("c_file"), 0);
|
||||
String8List *out = prefer_c_file ? &layer->c_catchall : &layer->h_catchall;
|
||||
if(tag->first->string.size == 0){}
|
||||
else if(str8_match(tag->first->string, str8_lit("enums"), 0)) { out = &layer->enums; }
|
||||
else if(str8_match(tag->first->string, str8_lit("structs"), 0)) { out = &layer->structs; }
|
||||
else if(str8_match(tag->first->string, str8_lit("functions"), 0)) { out = prefer_c_file ? &layer->c_functions : &layer->h_functions; }
|
||||
else if(str8_match(tag->first->string, str8_lit("tables"), 0)) { out = prefer_c_file ? &layer->c_tables : &layer->h_tables; }
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 trimmed = str8_skip_chop_whitespace(n->string);
|
||||
str8_list_push(mg_arena, out, trimmed);
|
||||
str8_list_push(mg_arena, out, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather & generate all embeds
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
if(md_node_has_tag(node, str8_lit("embed_string"), 0))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8 embed_string = mg_c_string_literal_from_multiline_string(node->first->string);
|
||||
//str8_list_pushf(mg_arena, &layer->h_tables, "read_only global String8 %S =\nstr8_lit_comp(\n", node->string);
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "read_only global const char* %S =\n", node->string);
|
||||
str8_list_push (mg_arena, &layer->h_tables, embed_string);
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, ";\n");
|
||||
//str8_list_pushf(mg_arena, &layer->h_tables, ");\n\n");
|
||||
}
|
||||
if(md_node_has_tag(node, str8_lit("embed_file"), 0))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8 data = os_data_from_file_path(mg_arena, node->first->string);
|
||||
String8 embed_string = mg_c_array_literal_contents_from_data(data);
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "read_only global U8 %S__data[] =\n{\n", node->string);
|
||||
str8_list_push (mg_arena, &layer->h_tables, embed_string);
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "};\n\n");
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "read_only global String8 %S = {%S__data, sizeof(%S__data)};\n",
|
||||
node->string,
|
||||
node->string,
|
||||
node->string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate all markdown in build folder
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *file = n->v.root;
|
||||
for MD_EachNode(node, file->first)
|
||||
{
|
||||
//- rjf: generate markdown page
|
||||
if(md_node_has_tag(node, str8_lit("markdown"), 0))
|
||||
{
|
||||
String8List md_strs = {0};
|
||||
for(MD_Node *piece = node->first; !md_node_is_nil(piece); piece = piece->next)
|
||||
{
|
||||
if(md_node_has_tag(piece, str8_lit("title"), 0))
|
||||
{
|
||||
str8_list_pushf(mg_arena, &md_strs, "# %S\n\n", piece->string);
|
||||
}
|
||||
if(md_node_has_tag(piece, str8_lit("subtitle"), 0))
|
||||
{
|
||||
str8_list_pushf(mg_arena, &md_strs, "## %S\n\n", piece->string);
|
||||
}
|
||||
if(md_node_has_tag(piece, str8_lit("p"), 0))
|
||||
{
|
||||
String8 paragraph_text = piece->string;
|
||||
String8List paragraph_lines = mg_wrapped_lines_from_string(mg_arena, paragraph_text, 80, 80, 0);
|
||||
for(String8Node *n = paragraph_lines.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &md_strs, n->string);
|
||||
str8_list_push(mg_arena, &md_strs, str8_lit("\n"));
|
||||
}
|
||||
str8_list_push(mg_arena, &md_strs, str8_lit("\n"));
|
||||
}
|
||||
if(md_node_has_tag(piece, str8_lit("unordered_list"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), piece);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &md_strs, " - ");
|
||||
String8 item_text = n->string;
|
||||
String8List item_lines = mg_wrapped_lines_from_string(mg_arena, item_text, 80-3, 80, 3);
|
||||
for(String8Node *line_n = item_lines.first; line_n != 0; line_n = line_n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &md_strs, line_n->string);
|
||||
str8_list_pushf(mg_arena, &md_strs, "\n");
|
||||
}
|
||||
}
|
||||
str8_list_pushf(mg_arena, &md_strs, "\n");
|
||||
}
|
||||
}
|
||||
String8 output_path = push_str8f(mg_arena, "%S/%S.md", build_dir_path, node->string);
|
||||
FILE *file = fopen((char *)output_path.str, "w");
|
||||
for(String8Node *n = md_strs.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, file);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: write all layer output files
|
||||
//
|
||||
DeferLoop(printf("generating layer code..."), printf("\n"))
|
||||
{
|
||||
for(U64 slot_idx = 0; slot_idx < mg_state->slots_count; slot_idx += 1)
|
||||
{
|
||||
MG_LayerSlot *slot = &mg_state->slots[slot_idx];
|
||||
for(MG_LayerNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
MG_Layer *layer = &n->v;
|
||||
String8 layer_generated_folder = {0};
|
||||
if(layer->gen_folder_name.size != 0)
|
||||
{
|
||||
String8 gen_folder = layer->gen_folder_name;
|
||||
layer_generated_folder = push_str8f(mg_arena, "%S/%S", code_dir_path, gen_folder);
|
||||
}
|
||||
else
|
||||
{
|
||||
String8 gen_folder = str8_lit("generated");
|
||||
layer_generated_folder = push_str8f(mg_arena, "%S/%S/%S", code_dir_path, layer->key, gen_folder);
|
||||
}
|
||||
if(os_make_directory(layer_generated_folder))
|
||||
{
|
||||
String8List layer_key_parts = str8_split_path(mg_arena, layer->key);
|
||||
StringJoin join = {0};
|
||||
join.sep = str8_lit("_");
|
||||
String8 layer_key_filename = str8_list_join(mg_arena, &layer_key_parts, &join);
|
||||
String8 layer_key_filename_upper = upper_from_str8(mg_arena, layer_key_filename);
|
||||
String8 h_path = push_str8f(mg_arena, "%S/%S.meta.h", layer_generated_folder, layer_key_filename);
|
||||
String8 c_path = push_str8f(mg_arena, "%S/%S.meta.c", layer_generated_folder, layer_key_filename);
|
||||
if(layer->h_name_override.size != 0)
|
||||
{
|
||||
h_path = push_str8f(mg_arena, "%S/%S", layer_generated_folder, str8_skip_last_slash(layer->h_name_override));
|
||||
}
|
||||
if(layer->c_name_override.size != 0)
|
||||
{
|
||||
c_path = push_str8f(mg_arena, "%S/%S", layer_generated_folder, str8_skip_last_slash(layer->c_name_override));
|
||||
}
|
||||
{
|
||||
FILE *h = fopen((char *)h_path.str, "w");
|
||||
//fprintf(h, "// Copyright (c) 2024 Epic Games Tools\n");
|
||||
//fprintf(h, "// Licensed under the MIT license (https://opensource.org/license/mit/)\n\n");
|
||||
if(layer->h_header.first == 0)
|
||||
{
|
||||
fprintf(h, "//- GENERATED CODE\n\n");
|
||||
fprintf(h, "#ifndef %.*s_META_H\n", str8_varg(layer_key_filename_upper));
|
||||
fprintf(h, "#define %.*s_META_H\n\n", str8_varg(layer_key_filename_upper));
|
||||
}
|
||||
else for(String8Node *n = layer->h_header.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
for(String8Node *n = layer->enums.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
for(String8Node *n = layer->structs.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
for(String8Node *n = layer->h_catchall.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
for(String8Node *n = layer->h_functions.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
if(layer->h_tables.first != 0)
|
||||
{
|
||||
if(!layer->is_library)
|
||||
{
|
||||
//fprintf(h, "C_LINKAGE_BEGIN\n");
|
||||
}
|
||||
for(String8Node *n = layer->h_tables.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
fprintf(h, "\n");
|
||||
if(!layer->is_library)
|
||||
{
|
||||
//fprintf(h, "C_LINKAGE_END\n\n");
|
||||
}
|
||||
}
|
||||
if(layer->h_footer.first == 0)
|
||||
{
|
||||
fprintf(h, "#endif // %.*s_META_H\n", str8_varg(layer_key_filename_upper));
|
||||
}
|
||||
else for(String8Node *n = layer->h_footer.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
fclose(h);
|
||||
}
|
||||
{
|
||||
FILE *c = fopen((char *)c_path.str, "w");
|
||||
//fprintf(c, "// Copyright (c) 2024 Epic Games Tools\n");
|
||||
//fprintf(c, "// Licensed under the MIT license (https://opensource.org/license/mit/)\n\n");
|
||||
if(layer->c_header.first == 0)
|
||||
{
|
||||
fprintf(c, "//- GENERATED CODE\n\n");
|
||||
}
|
||||
else for(String8Node *n = layer->c_header.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
for(String8Node *n = layer->c_catchall.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
if(layer->c_tables.first != 0)
|
||||
{
|
||||
if(!layer->is_library)
|
||||
{
|
||||
//fprintf(c, "C_LINKAGE_BEGIN\n");
|
||||
}
|
||||
for(String8Node *n = layer->c_tables.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
if(!layer->is_library)
|
||||
{
|
||||
//fprintf(c, "C_LINKAGE_END\n\n");
|
||||
}
|
||||
}
|
||||
for(String8Node *n = layer->c_functions.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
if(layer->c_footer.first != 0)
|
||||
{
|
||||
for(String8Node *n = layer->c_footer.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
}
|
||||
fclose(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: write out all messages to stderr
|
||||
//
|
||||
for(MG_MsgNode *n = msgs.first; n != 0; n = n->next)
|
||||
{
|
||||
MG_Msg *msg = &n->v;
|
||||
fprintf(stderr, "%.*s: %.*s: %.*s\n", str8_varg(msg->location), str8_varg(msg->kind), str8_varg(msg->msg));
|
||||
}
|
||||
}
|
||||
1337
src/metagen/metagen_os/core/linux/metagen_os_core_linux.c
Normal file
1337
src/metagen/metagen_os/core/linux/metagen_os_core_linux.c
Normal file
File diff suppressed because it is too large
Load Diff
137
src/metagen/metagen_os/core/linux/metagen_os_core_linux.h
Normal file
137
src/metagen/metagen_os/core/linux/metagen_os_core_linux.h
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef OS_CORE_LINUX_H
|
||||
#define OS_CORE_LINUX_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Includes
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <features.h>
|
||||
#include <linux/limits.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
pid_t gettid(void);
|
||||
int pthread_setname_np(pthread_t thread, const char *name);
|
||||
int pthread_getname_np(pthread_t thread, char *name, size_t size);
|
||||
|
||||
typedef struct tm tm;
|
||||
typedef struct timespec timespec;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: File Iterator
|
||||
|
||||
typedef struct OS_LNX_FileIter OS_LNX_FileIter;
|
||||
struct OS_LNX_FileIter
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dp;
|
||||
String8 path;
|
||||
};
|
||||
StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(OS_LNX_FileIter), os_lnx_file_iter_size_check);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Safe Call Handler Chain
|
||||
|
||||
typedef struct OS_LNX_SafeCallChain OS_LNX_SafeCallChain;
|
||||
struct OS_LNX_SafeCallChain
|
||||
{
|
||||
OS_LNX_SafeCallChain *next;
|
||||
OS_ThreadFunctionType *fail_handler;
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entities
|
||||
|
||||
typedef enum OS_LNX_EntityKind
|
||||
{
|
||||
OS_LNX_EntityKind_Thread,
|
||||
OS_LNX_EntityKind_Mutex,
|
||||
OS_LNX_EntityKind_RWMutex,
|
||||
OS_LNX_EntityKind_ConditionVariable,
|
||||
}
|
||||
OS_LNX_EntityKind;
|
||||
|
||||
typedef struct OS_LNX_Entity OS_LNX_Entity;
|
||||
struct OS_LNX_Entity
|
||||
{
|
||||
OS_LNX_Entity *next;
|
||||
OS_LNX_EntityKind kind;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
pthread_t handle;
|
||||
OS_ThreadFunctionType *func;
|
||||
void *ptr;
|
||||
} thread;
|
||||
pthread_mutex_t mutex_handle;
|
||||
pthread_rwlock_t rwmutex_handle;
|
||||
struct
|
||||
{
|
||||
pthread_cond_t cond_handle;
|
||||
pthread_mutex_t rwlock_mutex_handle;
|
||||
} cv;
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: State
|
||||
|
||||
typedef struct OS_LNX_State OS_LNX_State;
|
||||
struct OS_LNX_State
|
||||
{
|
||||
Arena *arena;
|
||||
OS_SystemInfo system_info;
|
||||
OS_ProcessInfo process_info;
|
||||
pthread_mutex_t entity_mutex;
|
||||
Arena *entity_arena;
|
||||
OS_LNX_Entity *entity_free;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global OS_LNX_State os_lnx_state = {0};
|
||||
thread_static OS_LNX_SafeCallChain *os_lnx_safe_call_chain = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal DateTime os_lnx_date_time_from_tm(tm in, U32 msec);
|
||||
internal tm os_lnx_tm_from_date_time(DateTime dt);
|
||||
internal timespec os_lnx_timespec_from_date_time(DateTime dt);
|
||||
internal DenseTime os_lnx_dense_time_from_timespec(timespec in);
|
||||
internal FileProperties os_lnx_file_properties_from_stat(struct stat *s);
|
||||
internal void os_lnx_safe_call_sig_handler(int x);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entities
|
||||
|
||||
internal OS_LNX_Entity *os_lnx_entity_alloc(OS_LNX_EntityKind kind);
|
||||
internal void os_lnx_entity_release(OS_LNX_Entity *entity);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Entry Point
|
||||
|
||||
internal void *os_lnx_thread_entry_point(void *ptr);
|
||||
|
||||
#endif // OS_CORE_LINUX_H
|
||||
240
src/metagen/metagen_os/core/metagen_os_core.c
Normal file
240
src/metagen/metagen_os/core/metagen_os_core.c
Normal file
@ -0,0 +1,240 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Handle Type Functions (Helpers, Implemented Once)
|
||||
|
||||
internal OS_Handle
|
||||
os_handle_zero(void)
|
||||
{
|
||||
OS_Handle handle = {0};
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_handle_match(OS_Handle a, OS_Handle b)
|
||||
{
|
||||
return a.u64[0] == b.u64[0];
|
||||
}
|
||||
|
||||
internal void
|
||||
os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle)
|
||||
{
|
||||
OS_HandleNode *n = push_array(arena, OS_HandleNode, 1);
|
||||
n->v = handle;
|
||||
SLLQueuePush(handles->first, handles->last, n);
|
||||
handles->count += 1;
|
||||
}
|
||||
|
||||
internal OS_HandleArray
|
||||
os_handle_array_from_list(Arena *arena, OS_HandleList *list)
|
||||
{
|
||||
OS_HandleArray result = {0};
|
||||
result.count = list->count;
|
||||
result.v = push_array_no_zero(arena, OS_Handle, result.count);
|
||||
U64 idx = 0;
|
||||
for(OS_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
|
||||
{
|
||||
result.v[idx] = n->v;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once)
|
||||
|
||||
internal String8List
|
||||
os_string_list_from_argcv(Arena *arena, int argc, char **argv)
|
||||
{
|
||||
String8List result = {0};
|
||||
for(int i = 0; i < argc; i += 1)
|
||||
{
|
||||
String8 str = str8_cstring(argv[i]);
|
||||
str8_list_push(arena, &result, str);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
|
||||
|
||||
internal String8
|
||||
os_data_from_file_path(Arena *arena, String8 path)
|
||||
{
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path);
|
||||
FileProperties props = os_properties_from_file(file);
|
||||
String8 data = os_string_from_file_range(arena, file, r1u64(0, props.size));
|
||||
os_file_close(file);
|
||||
return data;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_write_data_to_file_path(String8 path, String8 data)
|
||||
{
|
||||
B32 good = 0;
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Write, path);
|
||||
if(!os_handle_match(file, os_handle_zero()))
|
||||
{
|
||||
good = 1;
|
||||
os_file_write(file, r1u64(0, data.size), data.str);
|
||||
os_file_close(file);
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_write_data_list_to_file_path(String8 path, String8List list)
|
||||
{
|
||||
B32 good = 0;
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Write, path);
|
||||
if(!os_handle_match(file, os_handle_zero()))
|
||||
{
|
||||
good = 1;
|
||||
U64 off = 0;
|
||||
for(String8Node *n = list.first; n != 0; n = n->next)
|
||||
{
|
||||
os_file_write(file, r1u64(off, off+n->string.size), n->string.str);
|
||||
off += n->string.size;
|
||||
}
|
||||
os_file_close(file);
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_append_data_to_file_path(String8 path, String8 data)
|
||||
{
|
||||
B32 good = 0;
|
||||
if(data.size != 0)
|
||||
{
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append, path);
|
||||
if(!os_handle_match(file, os_handle_zero()))
|
||||
{
|
||||
good = 1;
|
||||
U64 pos = os_properties_from_file(file).size;
|
||||
os_file_write(file, r1u64(pos, pos+data.size), data.str);
|
||||
os_file_close(file);
|
||||
}
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
internal OS_FileID
|
||||
os_id_from_file_path(String8 path)
|
||||
{
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path);
|
||||
OS_FileID id = os_id_from_file(file);
|
||||
os_file_close(file);
|
||||
return id;
|
||||
}
|
||||
|
||||
internal S64
|
||||
os_file_id_compare(OS_FileID a, OS_FileID b)
|
||||
{
|
||||
S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v));
|
||||
return cmp;
|
||||
}
|
||||
|
||||
internal String8
|
||||
os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range)
|
||||
{
|
||||
U64 pre_pos = arena_pos(arena);
|
||||
String8 result;
|
||||
result.size = dim_1u64(range);
|
||||
result.str = push_array_no_zero(arena, U8, result.size);
|
||||
U64 actual_read_size = os_file_read(file, range, result.str);
|
||||
if(actual_read_size < result.size)
|
||||
{
|
||||
arena_pop_to(arena, pre_pos + actual_read_size);
|
||||
result.size = actual_read_size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Launcher Helpers
|
||||
|
||||
internal OS_Handle
|
||||
os_cmd_line_launch(String8 string)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
U8 split_chars[] = {' '};
|
||||
String8List parts = str8_split(scratch.arena, string, split_chars, ArrayCount(split_chars), 0);
|
||||
OS_Handle handle = {0};
|
||||
if(parts.node_count != 0)
|
||||
{
|
||||
// rjf: unpack exe part
|
||||
String8 exe = parts.first->string;
|
||||
String8 exe_folder = str8_chop_last_slash(exe);
|
||||
if(exe_folder.size == 0)
|
||||
{
|
||||
exe_folder = os_get_current_path(scratch.arena);
|
||||
}
|
||||
|
||||
// rjf: find stdout delimiter
|
||||
String8Node *stdout_delimiter_n = 0;
|
||||
for(String8Node *n = parts.first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->string, str8_lit(">"), 0))
|
||||
{
|
||||
stdout_delimiter_n = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: read stdout path
|
||||
String8 stdout_path = {0};
|
||||
if(stdout_delimiter_n && stdout_delimiter_n->next)
|
||||
{
|
||||
stdout_path = stdout_delimiter_n->next->string;
|
||||
}
|
||||
|
||||
// rjf: open stdout handle
|
||||
OS_Handle stdout_handle = {0};
|
||||
if(stdout_path.size != 0)
|
||||
{
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Read, stdout_path);
|
||||
os_file_close(file);
|
||||
stdout_handle = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite|OS_AccessFlag_Inherited, stdout_path);
|
||||
}
|
||||
|
||||
// rjf: form command line
|
||||
String8List cmdline = {0};
|
||||
for(String8Node *n = parts.first; n != stdout_delimiter_n && n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(scratch.arena, &cmdline, n->string);
|
||||
}
|
||||
|
||||
// rjf: launch
|
||||
OS_ProcessLaunchParams params = {0};
|
||||
params.cmd_line = cmdline;
|
||||
params.path = exe_folder;
|
||||
params.inherit_env = 1;
|
||||
params.stdout_file = stdout_handle;
|
||||
handle = os_process_launch(¶ms);
|
||||
|
||||
// rjf: close stdout handle
|
||||
{
|
||||
if(stdout_path.size != 0)
|
||||
{
|
||||
os_file_close(stdout_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal OS_Handle
|
||||
os_cmd_line_launchf(char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
OS_Handle result = os_cmd_line_launch(string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
335
src/metagen/metagen_os/core/metagen_os_core.h
Normal file
335
src/metagen/metagen_os/core/metagen_os_core.h
Normal file
@ -0,0 +1,335 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef OS_CORE_H
|
||||
#define OS_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: System Info
|
||||
|
||||
typedef struct OS_SystemInfo OS_SystemInfo;
|
||||
struct OS_SystemInfo
|
||||
{
|
||||
U32 logical_processor_count;
|
||||
U64 page_size;
|
||||
U64 large_page_size;
|
||||
U64 allocation_granularity;
|
||||
String8 machine_name;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Info
|
||||
|
||||
typedef struct OS_ProcessInfo OS_ProcessInfo;
|
||||
struct OS_ProcessInfo
|
||||
{
|
||||
U32 pid;
|
||||
B32 large_pages_allowed;
|
||||
String8 binary_path;
|
||||
String8 initial_path;
|
||||
String8 user_program_data_path;
|
||||
String8List module_load_paths;
|
||||
String8List environment;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Access Flags
|
||||
|
||||
typedef U32 OS_AccessFlags;
|
||||
enum
|
||||
{
|
||||
OS_AccessFlag_Read = (1<<0),
|
||||
OS_AccessFlag_Write = (1<<1),
|
||||
OS_AccessFlag_Execute = (1<<2),
|
||||
OS_AccessFlag_Append = (1<<3),
|
||||
OS_AccessFlag_ShareRead = (1<<4),
|
||||
OS_AccessFlag_ShareWrite = (1<<5),
|
||||
OS_AccessFlag_Inherited = (1<<6),
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Files
|
||||
|
||||
typedef U32 OS_FileIterFlags;
|
||||
enum
|
||||
{
|
||||
OS_FileIterFlag_SkipFolders = (1 << 0),
|
||||
OS_FileIterFlag_SkipFiles = (1 << 1),
|
||||
OS_FileIterFlag_SkipHiddenFiles = (1 << 2),
|
||||
OS_FileIterFlag_Done = (1 << 31),
|
||||
};
|
||||
|
||||
typedef struct OS_FileIter OS_FileIter;
|
||||
struct OS_FileIter
|
||||
{
|
||||
OS_FileIterFlags flags;
|
||||
U8 memory[800];
|
||||
};
|
||||
|
||||
typedef struct OS_FileInfo OS_FileInfo;
|
||||
struct OS_FileInfo
|
||||
{
|
||||
String8 name;
|
||||
FileProperties props;
|
||||
};
|
||||
|
||||
// nick: on-disk file identifier
|
||||
typedef struct OS_FileID OS_FileID;
|
||||
struct OS_FileID
|
||||
{
|
||||
U64 v[3];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Handle Type
|
||||
|
||||
typedef struct OS_Handle OS_Handle;
|
||||
struct OS_Handle
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
typedef struct OS_HandleNode OS_HandleNode;
|
||||
struct OS_HandleNode
|
||||
{
|
||||
OS_HandleNode *next;
|
||||
OS_Handle v;
|
||||
};
|
||||
|
||||
typedef struct OS_HandleList OS_HandleList;
|
||||
struct OS_HandleList
|
||||
{
|
||||
OS_HandleNode *first;
|
||||
OS_HandleNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct OS_HandleArray OS_HandleArray;
|
||||
struct OS_HandleArray
|
||||
{
|
||||
OS_Handle *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Launch Parameters
|
||||
|
||||
typedef struct OS_ProcessLaunchParams OS_ProcessLaunchParams;
|
||||
struct OS_ProcessLaunchParams
|
||||
{
|
||||
String8List cmd_line;
|
||||
String8 path;
|
||||
String8List env;
|
||||
B32 inherit_env;
|
||||
B32 debug_subprocesses;
|
||||
B32 consoleless;
|
||||
OS_Handle stdout_file;
|
||||
OS_Handle stderr_file;
|
||||
OS_Handle stdin_file;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Types
|
||||
|
||||
typedef void OS_ThreadFunctionType(void *ptr);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Handle Type Functions (Helpers, Implemented Once)
|
||||
|
||||
internal OS_Handle os_handle_zero(void);
|
||||
internal B32 os_handle_match(OS_Handle a, OS_Handle b);
|
||||
internal void os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle);
|
||||
internal OS_HandleArray os_handle_array_from_list(Arena *arena, OS_HandleList *list);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once)
|
||||
|
||||
internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
|
||||
|
||||
internal String8 os_data_from_file_path(Arena *arena, String8 path);
|
||||
internal B32 os_write_data_to_file_path(String8 path, String8 data);
|
||||
internal B32 os_write_data_list_to_file_path(String8 path, String8List list);
|
||||
internal B32 os_append_data_to_file_path(String8 path, String8 data);
|
||||
internal OS_FileID os_id_from_file_path(String8 path);
|
||||
internal S64 os_file_id_compare(OS_FileID a, OS_FileID b);
|
||||
internal String8 os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Launcher Helpers
|
||||
|
||||
internal OS_Handle os_cmd_line_launch(String8 string);
|
||||
internal OS_Handle os_cmd_line_launchf(char *fmt, ...);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks System/Process Info (Implemented Per-OS)
|
||||
|
||||
internal OS_SystemInfo *os_get_system_info(void);
|
||||
internal OS_ProcessInfo *os_get_process_info(void);
|
||||
internal String8 os_get_current_path(Arena *arena);
|
||||
internal U32 os_get_process_start_time_unix(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS)
|
||||
|
||||
//- rjf: basic
|
||||
internal void *os_reserve(U64 size);
|
||||
internal B32 os_commit(void *ptr, U64 size);
|
||||
internal void os_decommit(void *ptr, U64 size);
|
||||
internal void os_release(void *ptr, U64 size);
|
||||
|
||||
//- rjf: large pages
|
||||
internal void *os_reserve_large(U64 size);
|
||||
internal B32 os_commit_large(void *ptr, U64 size);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Thread Info (Implemented Per-OS)
|
||||
|
||||
internal U32 os_tid(void);
|
||||
internal void os_set_thread_name(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Aborting (Implemented Per-OS)
|
||||
|
||||
internal void os_abort(S32 exit_code);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks File System (Implemented Per-OS)
|
||||
|
||||
//- rjf: files
|
||||
internal OS_Handle os_file_open(OS_AccessFlags flags, String8 path);
|
||||
internal void os_file_close(OS_Handle file);
|
||||
internal U64 os_file_read(OS_Handle file, Rng1U64 rng, void *out_data);
|
||||
#define os_file_read_struct(f, off, ptr) os_file_read((f), r1u64((off), (off)+sizeof(*(ptr))), (ptr))
|
||||
internal U64 os_file_write(OS_Handle file, Rng1U64 rng, void *data);
|
||||
internal B32 os_file_set_times(OS_Handle file, DateTime time);
|
||||
internal FileProperties os_properties_from_file(OS_Handle file);
|
||||
internal OS_FileID os_id_from_file(OS_Handle file);
|
||||
internal B32 os_file_reserve_size(OS_Handle file, U64 size);
|
||||
internal B32 os_delete_file_at_path(String8 path);
|
||||
internal B32 os_copy_file_path(String8 dst, String8 src);
|
||||
internal B32 os_move_file_path(String8 dst, String8 src);
|
||||
internal String8 os_full_path_from_path(Arena *arena, String8 path);
|
||||
internal B32 os_file_path_exists(String8 path);
|
||||
internal B32 os_folder_path_exists(String8 path);
|
||||
internal FileProperties os_properties_from_file_path(String8 path);
|
||||
|
||||
//- rjf: file maps
|
||||
internal OS_Handle os_file_map_open(OS_AccessFlags flags, OS_Handle file);
|
||||
internal void os_file_map_close(OS_Handle map);
|
||||
internal void * os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range);
|
||||
internal void os_file_map_view_close(OS_Handle map, void *ptr, Rng1U64 range);
|
||||
|
||||
//- rjf: directory iteration
|
||||
internal OS_FileIter *os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags);
|
||||
internal B32 os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out);
|
||||
internal void os_file_iter_end(OS_FileIter *iter);
|
||||
|
||||
//- rjf: directory creation
|
||||
internal B32 os_make_directory(String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Shared Memory (Implemented Per-OS)
|
||||
|
||||
internal OS_Handle os_shared_memory_alloc(U64 size, String8 name);
|
||||
internal OS_Handle os_shared_memory_open(String8 name);
|
||||
internal void os_shared_memory_close(OS_Handle handle);
|
||||
internal void * os_shared_memory_view_open(OS_Handle handle, Rng1U64 range);
|
||||
internal void os_shared_memory_view_close(OS_Handle handle, void *ptr, Rng1U64 range);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Time (Implemented Per-OS)
|
||||
|
||||
internal U64 os_now_microseconds(void);
|
||||
internal U32 os_now_unix(void);
|
||||
internal DateTime os_now_universal_time(void);
|
||||
internal DateTime os_universal_time_from_local(DateTime *local_time);
|
||||
internal DateTime os_local_time_from_universal(DateTime *universal_time);
|
||||
internal void os_sleep_milliseconds(U32 msec);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Child Processes (Implemented Per-OS)
|
||||
|
||||
internal OS_Handle os_process_launch(OS_ProcessLaunchParams *params);
|
||||
internal B32 os_process_join(OS_Handle handle, U64 endt_us);
|
||||
internal void os_process_detach(OS_Handle handle);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Threads (Implemented Per-OS)
|
||||
|
||||
internal OS_Handle os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params);
|
||||
internal B32 os_thread_join(OS_Handle handle, U64 endt_us);
|
||||
internal void os_thread_detach(OS_Handle handle);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS)
|
||||
|
||||
//- rjf: recursive mutexes
|
||||
internal OS_Handle os_mutex_alloc(void);
|
||||
internal void os_mutex_release(OS_Handle mutex);
|
||||
internal void os_mutex_take(OS_Handle mutex);
|
||||
internal void os_mutex_drop(OS_Handle mutex);
|
||||
|
||||
//- rjf: reader/writer mutexes
|
||||
internal OS_Handle os_rw_mutex_alloc(void);
|
||||
internal void os_rw_mutex_release(OS_Handle rw_mutex);
|
||||
internal void os_rw_mutex_take_r(OS_Handle mutex);
|
||||
internal void os_rw_mutex_drop_r(OS_Handle mutex);
|
||||
internal void os_rw_mutex_take_w(OS_Handle mutex);
|
||||
internal void os_rw_mutex_drop_w(OS_Handle mutex);
|
||||
|
||||
//- rjf: condition variables
|
||||
internal OS_Handle os_condition_variable_alloc(void);
|
||||
internal void os_condition_variable_release(OS_Handle cv);
|
||||
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
|
||||
internal B32 os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us);
|
||||
internal B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us);
|
||||
internal B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us);
|
||||
internal void os_condition_variable_signal(OS_Handle cv);
|
||||
internal void os_condition_variable_broadcast(OS_Handle cv);
|
||||
|
||||
//- rjf: cross-process semaphores
|
||||
internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name);
|
||||
internal void os_semaphore_release(OS_Handle semaphore);
|
||||
internal OS_Handle os_semaphore_open(String8 name);
|
||||
internal void os_semaphore_close(OS_Handle semaphore);
|
||||
internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us);
|
||||
internal void os_semaphore_drop(OS_Handle semaphore);
|
||||
|
||||
//- rjf: scope macros
|
||||
#define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex))
|
||||
#define OS_MutexScopeR(mutex) DeferLoop(os_rw_mutex_take_r(mutex), os_rw_mutex_drop_r(mutex))
|
||||
#define OS_MutexScopeW(mutex) DeferLoop(os_rw_mutex_take_w(mutex), os_rw_mutex_drop_w(mutex))
|
||||
#define OS_MutexScopeRWPromote(mutex) DeferLoop((os_rw_mutex_drop_r(mutex), os_rw_mutex_take_w(mutex)), (os_rw_mutex_drop_w(mutex), os_rw_mutex_take_r(mutex)))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS)
|
||||
|
||||
internal OS_Handle os_library_open(String8 path);
|
||||
internal void os_library_close(OS_Handle lib);
|
||||
internal VoidProc *os_library_load_proc(OS_Handle lib, String8 name);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Safe Calls (Implemented Per-OS)
|
||||
|
||||
internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks GUIDs (Implemented Per-OS)
|
||||
|
||||
internal Guid os_make_guid(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Entry Points (Implemented Per-OS)
|
||||
|
||||
// NOTE(rjf): The implementation of `os_core` will define low-level entry
|
||||
// points if BUILD_ENTRY_DEFINING_UNIT is defined to 1. These will call
|
||||
// into the standard codebase program entry points, named "entry_point".
|
||||
|
||||
#if BUILD_ENTRY_DEFINING_UNIT
|
||||
internal void entry_point(CmdLine *cmdline);
|
||||
#endif
|
||||
|
||||
#endif // OS_CORE_H
|
||||
1785
src/metagen/metagen_os/core/win32/metagen_os_core_win32.c
Normal file
1785
src/metagen/metagen_os/core/win32/metagen_os_core_win32.c
Normal file
File diff suppressed because it is too large
Load Diff
121
src/metagen/metagen_os/core/win32/metagen_os_core_win32.h
Normal file
121
src/metagen/metagen_os/core/win32/metagen_os_core_win32.h
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef OS_CORE_WIN32_H
|
||||
#define OS_CORE_WIN32_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Includes / Libraries
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <timeapi.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <Shlobj.h>
|
||||
#include <processthreadsapi.h>
|
||||
#pragma comment(lib, "user32")
|
||||
#pragma comment(lib, "winmm")
|
||||
#pragma comment(lib, "shell32")
|
||||
#pragma comment(lib, "advapi32")
|
||||
#pragma comment(lib, "rpcrt4")
|
||||
#pragma comment(lib, "shlwapi")
|
||||
#pragma comment(lib, "comctl32")
|
||||
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // this is required for loading correct comctl32 dll file
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: File Iterator Types
|
||||
|
||||
typedef struct OS_W32_FileIter OS_W32_FileIter;
|
||||
struct OS_W32_FileIter
|
||||
{
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATAW find_data;
|
||||
B32 is_volume_iter;
|
||||
String8Array drive_strings;
|
||||
U64 drive_strings_iter_idx;
|
||||
};
|
||||
StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(OS_W32_FileIter), file_iter_memory_size);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Types
|
||||
|
||||
typedef enum OS_W32_EntityKind
|
||||
{
|
||||
OS_W32_EntityKind_Null,
|
||||
OS_W32_EntityKind_Thread,
|
||||
OS_W32_EntityKind_Mutex,
|
||||
OS_W32_EntityKind_RWMutex,
|
||||
OS_W32_EntityKind_ConditionVariable,
|
||||
}
|
||||
OS_W32_EntityKind;
|
||||
|
||||
typedef struct OS_W32_Entity OS_W32_Entity;
|
||||
struct OS_W32_Entity
|
||||
{
|
||||
OS_W32_Entity *next;
|
||||
OS_W32_EntityKind kind;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
OS_ThreadFunctionType *func;
|
||||
void *ptr;
|
||||
HANDLE handle;
|
||||
DWORD tid;
|
||||
} thread;
|
||||
CRITICAL_SECTION mutex;
|
||||
SRWLOCK rw_mutex;
|
||||
CONDITION_VARIABLE cv;
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: State
|
||||
|
||||
typedef struct OS_W32_State OS_W32_State;
|
||||
struct OS_W32_State
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: info
|
||||
OS_SystemInfo system_info;
|
||||
OS_ProcessInfo process_info;
|
||||
U64 microsecond_resolution;
|
||||
|
||||
// rjf: entity storage
|
||||
CRITICAL_SECTION entity_mutex;
|
||||
Arena *entity_arena;
|
||||
OS_W32_Entity *entity_free;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global OS_W32_State os_w32_state = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: File Info Conversion Helpers
|
||||
|
||||
internal FilePropertyFlags os_w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes);
|
||||
internal void os_w32_file_properties_from_attribute_data(FileProperties *properties, WIN32_FILE_ATTRIBUTE_DATA *attributes);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Conversion Helpers
|
||||
|
||||
internal void os_w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in);
|
||||
internal void os_w32_system_time_from_date_time(SYSTEMTIME *out, DateTime *in);
|
||||
internal void os_w32_dense_time_from_file_time(DenseTime *out, FILETIME *in);
|
||||
internal U32 os_w32_sleep_ms_from_endt_us(U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entity Functions
|
||||
|
||||
internal OS_W32_Entity *os_w32_entity_alloc(OS_W32_EntityKind kind);
|
||||
internal void os_w32_entity_release(OS_W32_Entity *entity);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Thread Entry Point
|
||||
|
||||
internal DWORD os_w32_thread_entry_point(void *ptr);
|
||||
|
||||
#endif // OS_CORE_WIN32_H
|
||||
10
src/metagen/metagen_os/metagen_os_inc.c
Normal file
10
src/metagen/metagen_os/metagen_os_inc.c
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "metagen_os/core/metagen_os_core.c"
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "metagen_os/core/win32/metagen_os_core_win32.c"
|
||||
#else
|
||||
# error OS core layer not implemented for this operating system.
|
||||
#endif
|
||||
19
src/metagen/metagen_os/metagen_os_inc.h
Normal file
19
src/metagen/metagen_os/metagen_os_inc.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef OS_INC_H
|
||||
#define OS_INC_H
|
||||
|
||||
#if !defined(OS_FEATURE_GRAPHICAL)
|
||||
# define OS_FEATURE_GRAPHICAL 0
|
||||
#endif
|
||||
|
||||
#include "metagen_os/core/metagen_os_core.h"
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "metagen_os/core/win32/metagen_os_core_win32.h"
|
||||
#else
|
||||
# error OS core layer not implemented for this operating system.
|
||||
#endif
|
||||
|
||||
#endif // OS_INC_H
|
||||
@ -1,3 +1,5 @@
|
||||
//- GENERATED CODE
|
||||
|
||||
char * os_key_display_string[113] =
|
||||
{
|
||||
"Null",
|
||||
124
src/os/generated/os.meta.h
Normal file
124
src/os/generated/os.meta.h
Normal file
@ -0,0 +1,124 @@
|
||||
//- GENERATED CODE
|
||||
|
||||
#ifndef OS_META_H
|
||||
#define OS_META_H
|
||||
|
||||
typedef enum OS_Key
|
||||
{
|
||||
OS_Key_Null,
|
||||
OS_Key_Esc,
|
||||
OS_Key_F1,
|
||||
OS_Key_F2,
|
||||
OS_Key_F3,
|
||||
OS_Key_F4,
|
||||
OS_Key_F5,
|
||||
OS_Key_F6,
|
||||
OS_Key_F7,
|
||||
OS_Key_F8,
|
||||
OS_Key_F9,
|
||||
OS_Key_F10,
|
||||
OS_Key_F11,
|
||||
OS_Key_F12,
|
||||
OS_Key_F13,
|
||||
OS_Key_F14,
|
||||
OS_Key_F15,
|
||||
OS_Key_F16,
|
||||
OS_Key_F17,
|
||||
OS_Key_F18,
|
||||
OS_Key_F19,
|
||||
OS_Key_F20,
|
||||
OS_Key_F21,
|
||||
OS_Key_F22,
|
||||
OS_Key_F23,
|
||||
OS_Key_F24,
|
||||
OS_Key_Tick,
|
||||
OS_Key_0,
|
||||
OS_Key_1,
|
||||
OS_Key_2,
|
||||
OS_Key_3,
|
||||
OS_Key_4,
|
||||
OS_Key_5,
|
||||
OS_Key_6,
|
||||
OS_Key_7,
|
||||
OS_Key_8,
|
||||
OS_Key_9,
|
||||
OS_Key_Minus,
|
||||
OS_Key_Equal,
|
||||
OS_Key_Backspace,
|
||||
OS_Key_Tab,
|
||||
OS_Key_Q,
|
||||
OS_Key_W,
|
||||
OS_Key_E,
|
||||
OS_Key_R,
|
||||
OS_Key_T,
|
||||
OS_Key_Y,
|
||||
OS_Key_U,
|
||||
OS_Key_I,
|
||||
OS_Key_O,
|
||||
OS_Key_P,
|
||||
OS_Key_LeftBracket,
|
||||
OS_Key_RightBracket,
|
||||
OS_Key_BackSlash,
|
||||
OS_Key_CapsLock,
|
||||
OS_Key_A,
|
||||
OS_Key_S,
|
||||
OS_Key_D,
|
||||
OS_Key_F,
|
||||
OS_Key_G,
|
||||
OS_Key_H,
|
||||
OS_Key_J,
|
||||
OS_Key_K,
|
||||
OS_Key_L,
|
||||
OS_Key_Semicolon,
|
||||
OS_Key_Quote,
|
||||
OS_Key_Return,
|
||||
OS_Key_Shift,
|
||||
OS_Key_Z,
|
||||
OS_Key_X,
|
||||
OS_Key_C,
|
||||
OS_Key_V,
|
||||
OS_Key_B,
|
||||
OS_Key_N,
|
||||
OS_Key_M,
|
||||
OS_Key_Comma,
|
||||
OS_Key_Period,
|
||||
OS_Key_Slash,
|
||||
OS_Key_Ctrl,
|
||||
OS_Key_Alt,
|
||||
OS_Key_Space,
|
||||
OS_Key_Menu,
|
||||
OS_Key_ScrollLock,
|
||||
OS_Key_Pause,
|
||||
OS_Key_Insert,
|
||||
OS_Key_Home,
|
||||
OS_Key_PageUp,
|
||||
OS_Key_Delete,
|
||||
OS_Key_End,
|
||||
OS_Key_PageDown,
|
||||
OS_Key_Up,
|
||||
OS_Key_Left,
|
||||
OS_Key_Down,
|
||||
OS_Key_Right,
|
||||
OS_Key_NumLock,
|
||||
OS_Key_NumSlash,
|
||||
OS_Key_NumStar,
|
||||
OS_Key_NumMinus,
|
||||
OS_Key_NumPlus,
|
||||
OS_Key_NumPeriod,
|
||||
OS_Key_Num0,
|
||||
OS_Key_Num1,
|
||||
OS_Key_Num2,
|
||||
OS_Key_Num3,
|
||||
OS_Key_Num4,
|
||||
OS_Key_Num5,
|
||||
OS_Key_Num6,
|
||||
OS_Key_Num7,
|
||||
OS_Key_Num8,
|
||||
OS_Key_Num9,
|
||||
OS_Key_LeftMouseButton,
|
||||
OS_Key_MiddleMouseButton,
|
||||
OS_Key_RightMouseButton,
|
||||
OS_Key_OS_Key_COUNT,
|
||||
} OS_Key;
|
||||
|
||||
#endif // OS_META_H
|
||||
@ -1,121 +0,0 @@
|
||||
typedef enum OS_Key
|
||||
{
|
||||
OS_Key_Null,
|
||||
OS_Key_Esc,
|
||||
OS_Key_F1,
|
||||
OS_Key_F2,
|
||||
OS_Key_F3,
|
||||
OS_Key_F4,
|
||||
OS_Key_F5,
|
||||
OS_Key_F6,
|
||||
OS_Key_F7,
|
||||
OS_Key_F8,
|
||||
OS_Key_F9,
|
||||
OS_Key_F10,
|
||||
OS_Key_F11,
|
||||
OS_Key_F12,
|
||||
OS_Key_F13,
|
||||
OS_Key_F14,
|
||||
OS_Key_F15,
|
||||
OS_Key_F16,
|
||||
OS_Key_F17,
|
||||
OS_Key_F18,
|
||||
OS_Key_F19,
|
||||
OS_Key_F20,
|
||||
OS_Key_F21,
|
||||
OS_Key_F22,
|
||||
OS_Key_F23,
|
||||
OS_Key_F24,
|
||||
OS_Key_Tick,
|
||||
OS_Key_0,
|
||||
OS_Key_1,
|
||||
OS_Key_2,
|
||||
OS_Key_3,
|
||||
OS_Key_4,
|
||||
OS_Key_5,
|
||||
OS_Key_6,
|
||||
OS_Key_7,
|
||||
OS_Key_8,
|
||||
OS_Key_9,
|
||||
OS_Key_Minus,
|
||||
OS_Key_Equal,
|
||||
OS_Key_Backspace,
|
||||
OS_Key_Tab,
|
||||
OS_Key_Q,
|
||||
OS_Key_W,
|
||||
OS_Key_E,
|
||||
OS_Key_R,
|
||||
OS_Key_T,
|
||||
OS_Key_Y,
|
||||
OS_Key_U,
|
||||
OS_Key_I,
|
||||
OS_Key_O,
|
||||
OS_Key_P,
|
||||
OS_Key_LeftBracket,
|
||||
OS_Key_RightBracket,
|
||||
OS_Key_BackSlash,
|
||||
OS_Key_CapsLock,
|
||||
OS_Key_A,
|
||||
OS_Key_S,
|
||||
OS_Key_D,
|
||||
OS_Key_F,
|
||||
OS_Key_G,
|
||||
OS_Key_H,
|
||||
OS_Key_J,
|
||||
OS_Key_K,
|
||||
OS_Key_L,
|
||||
OS_Key_Semicolon,
|
||||
OS_Key_Quote,
|
||||
OS_Key_Return,
|
||||
OS_Key_Shift,
|
||||
OS_Key_Z,
|
||||
OS_Key_X,
|
||||
OS_Key_C,
|
||||
OS_Key_V,
|
||||
OS_Key_B,
|
||||
OS_Key_N,
|
||||
OS_Key_M,
|
||||
OS_Key_Comma,
|
||||
OS_Key_Period,
|
||||
OS_Key_Slash,
|
||||
OS_Key_Ctrl,
|
||||
OS_Key_Alt,
|
||||
OS_Key_Space,
|
||||
OS_Key_Menu,
|
||||
OS_Key_ScrollLock,
|
||||
OS_Key_Pause,
|
||||
OS_Key_Insert,
|
||||
OS_Key_Home,
|
||||
OS_Key_PageUp,
|
||||
OS_Key_Delete,
|
||||
OS_Key_End,
|
||||
OS_Key_PageDown,
|
||||
OS_Key_Up,
|
||||
OS_Key_Left,
|
||||
OS_Key_Down,
|
||||
OS_Key_Right,
|
||||
OS_Key_NumLock,
|
||||
OS_Key_NumSlash,
|
||||
OS_Key_NumStar,
|
||||
OS_Key_NumMinus,
|
||||
OS_Key_NumPlus,
|
||||
OS_Key_NumPeriod,
|
||||
OS_Key_Num0,
|
||||
OS_Key_Num1,
|
||||
OS_Key_Num2,
|
||||
OS_Key_Num3,
|
||||
OS_Key_Num4,
|
||||
OS_Key_Num5,
|
||||
OS_Key_Num6,
|
||||
OS_Key_Num7,
|
||||
OS_Key_Num8,
|
||||
OS_Key_Num9,
|
||||
OS_Key_LeftMouseButton,
|
||||
OS_Key_MiddleMouseButton,
|
||||
OS_Key_RightMouseButton,
|
||||
OS_Key_COUNT
|
||||
}
|
||||
OS_Key;
|
||||
|
||||
extern char * os_key_display_string[113];
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
#include "os/generated/os_core.meta.c"
|
||||
#include "os/generated/os.meta.c"
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
#define OS_MAX_EVENTS 2048
|
||||
|
||||
#include "os/generated/os_core.meta.h"
|
||||
#include "os/generated/os.meta.h"
|
||||
|
||||
typedef struct OS_Handle OS_Handle;
|
||||
struct OS_Handle
|
||||
|
||||
@ -125,15 +125,14 @@ OS_KeyTable:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~ Generators
|
||||
|
||||
@table_gen_enum OS_Key:
|
||||
@enum OS_Key:
|
||||
{
|
||||
@expand(OS_KeyTable a)
|
||||
` OS_Key_$(a.name),`;
|
||||
` OS_Key_COUNT`
|
||||
@expand(OS_KeyTable a) `$(a.name)`
|
||||
OS_Key_COUNT,
|
||||
}
|
||||
|
||||
@table_gen_data(`char *`) os_key_display_string:
|
||||
@c_file @data(`char *`)
|
||||
os_key_display_string:
|
||||
{
|
||||
@expand(OS_KeyTable a)
|
||||
`"$(a.display_string)",`;
|
||||
@expand(OS_KeyTable a) `"$(a.display_string)"`;
|
||||
}
|
||||
16
src/render/d3d12/generated/render_d3d12.meta.c
Normal file
16
src/render/d3d12/generated/render_d3d12.meta.c
Normal file
@ -0,0 +1,16 @@
|
||||
//- GENERATED CODE
|
||||
|
||||
const char *r_d3d12_g_vs_kind_source_table[R_D3D12_VS_Kind_COUNT];
|
||||
internal void r_d3d12_init_vs_sources()
|
||||
{
|
||||
r_d3d12_g_vs_kind_source_table[R_D3D12_VS_Kind_Triangle] = r_d3d12_g_triangle_shader_src;
|
||||
r_d3d12_g_vs_kind_source_table[R_D3D12_VS_Kind_Test] = r_d3d12_g_test_shader_src;
|
||||
}
|
||||
|
||||
const char *r_d3d12_g_ps_kind_source_table[R_D3D12_PS_Kind_COUNT];
|
||||
internal void r_d3d12_init_ps_sources()
|
||||
{
|
||||
r_d3d12_g_ps_kind_source_table[R_D3D12_PS_Kind_Triangle] = r_d3d12_g_triangle_shader_src;
|
||||
r_d3d12_g_ps_kind_source_table[R_D3D12_PS_Kind_Test] = r_d3d12_g_test_shader_src;
|
||||
}
|
||||
|
||||
71
src/render/d3d12/generated/render_d3d12.meta.h
Normal file
71
src/render/d3d12/generated/render_d3d12.meta.h
Normal file
@ -0,0 +1,71 @@
|
||||
//- GENERATED CODE
|
||||
|
||||
#ifndef RENDER_D3D12_META_H
|
||||
#define RENDER_D3D12_META_H
|
||||
|
||||
typedef enum R_D3D12_VS_Kind
|
||||
{
|
||||
R_D3D12_VS_Kind_Triangle,
|
||||
R_D3D12_VS_Kind_Test,
|
||||
R_D3D12_VS_Kind_COUNT,
|
||||
} R_D3D12_VS_Kind;
|
||||
|
||||
typedef enum R_D3D12_PS_Kind
|
||||
{
|
||||
R_D3D12_PS_Kind_Triangle,
|
||||
R_D3D12_PS_Kind_Test,
|
||||
R_D3D12_PS_Kind_COUNT,
|
||||
} R_D3D12_PS_Kind;
|
||||
|
||||
read_only global const char* r_d3d12_g_triangle_shader_src =
|
||||
""
|
||||
"\n"
|
||||
"struct PSInput\n"
|
||||
"{\n"
|
||||
" float4 position : SV_POSITION;\n"
|
||||
" float4 color : COLOR;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"PSInput vs_main(float4 position : POSITION, float4 color : COLOR)\n"
|
||||
"{\n"
|
||||
" PSInput result;\n"
|
||||
"\n"
|
||||
" result.position = position;\n"
|
||||
" result.color = color;\n"
|
||||
"\n"
|
||||
" return result;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"float4 ps_main(PSInput input) : SV_TARGET\n"
|
||||
"{\n"
|
||||
" return input.color;\n"
|
||||
"}\n"
|
||||
""
|
||||
;
|
||||
read_only global const char* r_d3d12_g_test_shader_src =
|
||||
""
|
||||
"\n"
|
||||
"struct PSInput\n"
|
||||
"{\n"
|
||||
" float4 position : SV_POSITION;\n"
|
||||
" float4 color : COLOR;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"PSInput vs_main(float4 position : POSITION, float4 color : COLOR)\n"
|
||||
"{\n"
|
||||
" PSInput result;\n"
|
||||
"\n"
|
||||
" result.position = position;\n"
|
||||
" result.color = color;\n"
|
||||
"\n"
|
||||
" return result;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"float4 ps_main(PSInput input) : SV_TARGET\n"
|
||||
"{\n"
|
||||
" return input.color;\n"
|
||||
"}\n"
|
||||
""
|
||||
;
|
||||
|
||||
#endif // RENDER_D3D12_META_H
|
||||
@ -1,17 +1,34 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
#include <d3dcompiler.h>
|
||||
#include "generated/render_d3d12.meta.c"
|
||||
|
||||
#pragma comment(lib, "d3d12.lib")
|
||||
#pragma comment(lib, "dxgi.lib")
|
||||
#pragma comment(lib, "dxguid.lib")
|
||||
#pragma comment(lib, "d3dcompiler.lib")
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
|
||||
#define D3D12_ERROR(msg, ...) LOG("D3D12 ERROR (anton): "); LOG(msg, __VA_ARGS__); Trap();
|
||||
#define D3D12_CHECK(hr, msg) if(FAILED((hr))) { D3D12_ERROR(msg, __VA_ARGS__) }
|
||||
#define D3D12_ERROR(msg, ...) \
|
||||
LOG("D3D12 ERROR (anton): "); \
|
||||
LOG(msg, __VA_ARGS__); \
|
||||
Trap();
|
||||
#define D3D12_CHECK(hr, msg) \
|
||||
if(FAILED((hr))) \
|
||||
{ \
|
||||
D3D12_ERROR(msg, __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define D3D12_RELEASE(res) if( (res) && (res)->lpVtbl) { (res)->lpVtbl->Release((res)); (res) = 0; }
|
||||
#define D3D12_RELEASE(res) \
|
||||
if((res) && (res)->lpVtbl) \
|
||||
{ \
|
||||
(res)->lpVtbl->Release((res)); \
|
||||
(res) = 0; \
|
||||
}
|
||||
|
||||
#define D3D12_SHADER_CHECK(hr, err_blob) r_d3d12_shader_check((hr), (err_blob))
|
||||
|
||||
global R_D3D12_State *r_d3d12_state = 0;
|
||||
global R_D3D12_Command *r_d3d12_cmd = 0;
|
||||
@ -20,23 +37,77 @@ global R_D3D12_RenderTarget *r_d3d12_rt = 0;
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
|
||||
internal U32 c_strlen(const char * str)
|
||||
{
|
||||
U32 out = 0;
|
||||
char c = str[0];
|
||||
while(c != '\0')
|
||||
{
|
||||
//LOG("c: %c ", c);
|
||||
out += 1;
|
||||
if(out > 1000000)
|
||||
{
|
||||
break;
|
||||
}
|
||||
c = *(&str[0] + out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
internal void
|
||||
r_init()
|
||||
r_d3d12_shader_check(HRESULT hr, ID3D10Blob *err_blob)
|
||||
{
|
||||
if(FAILED(hr))
|
||||
{
|
||||
LOG("Shader compilation failed: %.*s\n",
|
||||
(int)ID3D10Blob_GetBufferSize(err_blob),
|
||||
(char*)ID3D10Blob_GetBufferPointer(err_blob));
|
||||
ID3D10Blob_Release(err_blob);
|
||||
}
|
||||
}
|
||||
|
||||
internal D3D12_SHADER_BYTECODE
|
||||
r_d3d12_get_shader_bytecode(ID3DBlob *shader_blob)
|
||||
{
|
||||
D3D12_SHADER_BYTECODE out = {0};
|
||||
out.pShaderBytecode = ID3D10Blob_GetBufferPointer(shader_blob);
|
||||
out.BytecodeLength = ID3D10Blob_GetBufferSize(shader_blob);
|
||||
return out;
|
||||
}
|
||||
|
||||
internal const char *
|
||||
r_d3d12_get_vs_shader_source(R_D3D12_VS_Kind kind)
|
||||
{
|
||||
return r_d3d12_g_vs_kind_source_table[kind];
|
||||
}
|
||||
|
||||
internal const char *
|
||||
r_d3d12_get_ps_shader_source(R_D3D12_PS_Kind kind)
|
||||
{
|
||||
return r_d3d12_g_ps_kind_source_table[kind];
|
||||
}
|
||||
|
||||
|
||||
internal void r_init()
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
r_d3d12_state = push_array(arena, R_D3D12_State, 1);
|
||||
r_d3d12_state->arena = arena;
|
||||
r_d3d12_state->window_handle = g_win32_window_handle;
|
||||
|
||||
r_d3d12_cmd = push_array(arena, R_D3D12_Command, 1);
|
||||
|
||||
r_d3d12_cmd = push_array(arena,
|
||||
R_D3D12_Command,
|
||||
1);
|
||||
|
||||
r_d3d12_cmd->arena = arena;
|
||||
|
||||
r_d3d12_rt = push_array(arena, R_D3D12_RenderTarget, 1);
|
||||
r_d3d12_rt = push_array(arena,
|
||||
R_D3D12_RenderTarget, 1);
|
||||
r_d3d12_rt->arena = arena;
|
||||
|
||||
HRESULT hr;
|
||||
hr = D3D12GetDebugInterface(&IID_ID3D12Debug, (void**)&r_d3d12_state->debug);
|
||||
if(SUCCEEDED(hr) && r_d3d12_state->debug )
|
||||
hr = D3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&r_d3d12_state->debug);
|
||||
if(SUCCEEDED(hr) && r_d3d12_state->debug)
|
||||
{
|
||||
r_d3d12_state->debug->lpVtbl->EnableDebugLayer(r_d3d12_state->debug);
|
||||
}
|
||||
@ -44,112 +115,105 @@ r_init()
|
||||
{
|
||||
D3D12_ERROR("Failed to create D3D12 Debug interface \n");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Create device
|
||||
hr = D3D12CreateDevice(0,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
&IID_ID3D12Device,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
&IID_ID3D12Device,
|
||||
(void **)&r_d3d12_state->device);
|
||||
D3D12_CHECK(hr, "Failed to create device\n");
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Create command queue
|
||||
D3D12_COMMAND_QUEUE_DESC queue_desc = {
|
||||
.Type = D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||
.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
|
||||
.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
|
||||
.NodeMask = 0
|
||||
};
|
||||
.Type = D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||
.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
|
||||
.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
|
||||
.NodeMask = 0
|
||||
};
|
||||
|
||||
hr = ID3D12Device_CreateCommandQueue(r_d3d12_state->device,
|
||||
&queue_desc,
|
||||
&IID_ID3D12CommandQueue,
|
||||
(void**)&r_d3d12_cmd->queue);
|
||||
|
||||
&queue_desc,
|
||||
&IID_ID3D12CommandQueue,
|
||||
(void **)&r_d3d12_cmd->queue);
|
||||
|
||||
D3D12_CHECK(hr, "Failed to create command queue\n");
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Create DXGI factory
|
||||
IDXGIFactory4 *factory;
|
||||
hr = CreateDXGIFactory1(&IID_IDXGIFactory4, (void**)&factory);
|
||||
hr = CreateDXGIFactory1(&IID_IDXGIFactory4, (void **)&factory);
|
||||
D3D12_CHECK(hr, "Failed to create factory\n");
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Create Swapchain
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {
|
||||
.Width = WINDOW_WIDTH_PX,
|
||||
.Height = WINDOW_HEIGHT_PX,
|
||||
.Format = DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
.Stereo = FALSE,
|
||||
.SampleDesc = {1, 0},
|
||||
.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||
.BufferCount = R_NUM_FRAMES_IN_FLIGHT,
|
||||
.Scaling = DXGI_SCALING_STRETCH,
|
||||
.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD,
|
||||
.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED,
|
||||
.Flags = 0
|
||||
};
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {.Width = WINDOW_WIDTH_PX,
|
||||
.Height = WINDOW_HEIGHT_PX,
|
||||
.Format = DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
.Stereo = FALSE,
|
||||
.SampleDesc = {1, 0},
|
||||
.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||
.BufferCount = R_NUM_FRAMES_IN_FLIGHT,
|
||||
.Scaling = DXGI_SCALING_STRETCH,
|
||||
.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD,
|
||||
.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED,
|
||||
.Flags = 0};
|
||||
|
||||
// We create a temporary SwapChain1 that is then upgraded to a SwapChain3.
|
||||
IDXGISwapChain1* temp_swap_chain;
|
||||
hr = IDXGIFactory4_CreateSwapChainForHwnd(factory,
|
||||
(IUnknown*)r_d3d12_cmd->queue,
|
||||
r_d3d12_state->window_handle,
|
||||
&swap_chain_desc,
|
||||
0,
|
||||
0,
|
||||
&temp_swap_chain);
|
||||
IDXGISwapChain1 *temp_swap_chain;
|
||||
hr = IDXGIFactory4_CreateSwapChainForHwnd(factory,
|
||||
(IUnknown *)r_d3d12_cmd->queue,
|
||||
r_d3d12_state->window_handle,
|
||||
&swap_chain_desc,
|
||||
0,
|
||||
0,
|
||||
&temp_swap_chain);
|
||||
|
||||
D3D12_CHECK(hr, "Failed to create temp swap chain \n");
|
||||
|
||||
hr = temp_swap_chain->lpVtbl->QueryInterface(temp_swap_chain,
|
||||
&IID_IDXGISwapChain3,
|
||||
(void**)&r_d3d12_state->swapchain);
|
||||
&IID_IDXGISwapChain3,
|
||||
(void **)&r_d3d12_state->swapchain);
|
||||
D3D12_CHECK(hr, "Failed to upgrade to swapchain3\n");
|
||||
temp_swap_chain->lpVtbl->Release(temp_swap_chain);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Create Render target view (RTV) descriptor heap
|
||||
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc = {
|
||||
.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
|
||||
.NumDescriptors = R_NUM_FRAMES_IN_FLIGHT,
|
||||
.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
|
||||
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc =
|
||||
{
|
||||
.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
|
||||
.NumDescriptors = R_NUM_FRAMES_IN_FLIGHT,
|
||||
.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
|
||||
.NodeMask = 0
|
||||
};
|
||||
|
||||
|
||||
hr = ID3D12Device_CreateDescriptorHeap(r_d3d12_state->device,
|
||||
&rtv_heap_desc,
|
||||
&IID_ID3D12DescriptorHeap,
|
||||
(void**)&r_d3d12_rt->heap);
|
||||
hr = ID3D12Device_CreateDescriptorHeap(r_d3d12_state->device,
|
||||
&rtv_heap_desc,
|
||||
&IID_ID3D12DescriptorHeap,
|
||||
(void **)&r_d3d12_rt->heap);
|
||||
D3D12_CHECK(hr, "Failed to create descriptor heap\n");
|
||||
|
||||
r_d3d12_rt->descriptor_size = r_d3d12_state->device->lpVtbl->
|
||||
GetDescriptorHandleIncrementSize(r_d3d12_state->device,
|
||||
GetDescriptorHandleIncrementSize(r_d3d12_state->device,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Create render target views
|
||||
// Create render target views
|
||||
// TODO(anton): This is probably not correct D3D12 API, but I might have an old SDK.
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle;
|
||||
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(r_d3d12_rt->heap, &handle);
|
||||
|
||||
for (U32 i = 0; i < R_NUM_FRAMES_IN_FLIGHT; i += 1)
|
||||
for(U32 i = 0; i < R_NUM_FRAMES_IN_FLIGHT; i += 1)
|
||||
{
|
||||
|
||||
IDXGISwapChain3_GetBuffer(r_d3d12_state->swapchain,
|
||||
i,
|
||||
&IID_ID3D12Resource,
|
||||
(void**)&r_d3d12_rt->targets[i]);
|
||||
|
||||
ID3D12Device_CreateRenderTargetView(r_d3d12_state->device,
|
||||
r_d3d12_rt->targets[i],
|
||||
0,
|
||||
handle);
|
||||
IDXGISwapChain3_GetBuffer(r_d3d12_state->swapchain,
|
||||
i,
|
||||
&IID_ID3D12Resource,
|
||||
(void **)&r_d3d12_rt->targets[i]);
|
||||
|
||||
ID3D12Device_CreateRenderTargetView(r_d3d12_state->device, r_d3d12_rt->targets[i], 0, handle);
|
||||
|
||||
handle.ptr += r_d3d12_rt->descriptor_size;
|
||||
}
|
||||
@ -157,126 +221,279 @@ r_init()
|
||||
// ---------------------------------------------------------------------------
|
||||
// Command allocator and command list
|
||||
hr = ID3D12Device_CreateCommandAllocator(r_d3d12_state->device,
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||
&IID_ID3D12CommandAllocator,
|
||||
(void**)&r_d3d12_cmd->allocator);
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||
&IID_ID3D12CommandAllocator,
|
||||
(void **)&r_d3d12_cmd->allocator);
|
||||
D3D12_CHECK(hr, "Failed to create command allocator\n");
|
||||
|
||||
hr = ID3D12Device_CreateCommandList(r_d3d12_state->device,
|
||||
0,
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||
r_d3d12_cmd->allocator,
|
||||
0,
|
||||
&IID_ID3D12GraphicsCommandList,
|
||||
(void**)&r_d3d12_cmd->list1);
|
||||
hr = ID3D12Device_CreateCommandList(r_d3d12_state->device,
|
||||
0,
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||
r_d3d12_cmd->allocator,
|
||||
0,
|
||||
&IID_ID3D12GraphicsCommandList,
|
||||
(void **)&r_d3d12_cmd->list1);
|
||||
D3D12_CHECK(hr, "Failed to create command list\n");
|
||||
// Put it in a closed state during initialisation. It will be opened at the start of the render function.
|
||||
ID3D12GraphicsCommandList_Close(r_d3d12_cmd->list1);
|
||||
|
||||
|
||||
// Create the vertex buffer.
|
||||
{
|
||||
// Define the geometry for a triangle.
|
||||
R_D3D12_Vertex triangle_vertices[3];
|
||||
F32 r_aspect_ratio = (F32)WINDOW_WIDTH_PX / (F32)WINDOW_HEIGHT_PX;
|
||||
triangle_vertices[0].pos = (Vec3F32){0.0f, 0.25f * r_aspect_ratio, 0.0f};
|
||||
triangle_vertices[1].pos = (Vec3F32){0.25f, -0.25f * r_aspect_ratio, 0.0f};
|
||||
triangle_vertices[2].pos = (Vec3F32){-0.25f, -0.25f * r_aspect_ratio, 0.0f};
|
||||
triangle_vertices[0].color = (Vec4F32){1.0f, 0.0f, 0.0f, 1.0f};
|
||||
triangle_vertices[1].color = (Vec4F32){0.0f, 1.0f, 0.0f, 1.0f};
|
||||
triangle_vertices[2].color = (Vec4F32){0.0f, 0.0f, 1.0f, 1.0f};
|
||||
|
||||
U32 vertex_buffer_size = 3 * sizeof(R_D3D12_Vertex);
|
||||
|
||||
D3D12_RESOURCE_DESC buffer_desc = {
|
||||
.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
|
||||
.Alignment = 0,
|
||||
.Width = vertex_buffer_size,
|
||||
.Height = 1,
|
||||
.DepthOrArraySize = 1,
|
||||
.MipLevels = 1,
|
||||
.Format = DXGI_FORMAT_UNKNOWN,
|
||||
.SampleDesc = {.Count = 1, .Quality = 0},
|
||||
.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
||||
.Flags = D3D12_RESOURCE_FLAG_NONE
|
||||
};
|
||||
|
||||
// Note: using upload heaps to transfer static data like vert buffers is not
|
||||
// recommended. Every time the GPU needs it, the upload heap will be marshalled
|
||||
// over. Please read up on Default Heap usage. An upload heap is used here for
|
||||
// code simplicity and because there are very few verts to actually transfer.
|
||||
D3D12_HEAP_PROPERTIES heap_props = {
|
||||
.Type = D3D12_HEAP_TYPE_UPLOAD,
|
||||
.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
||||
.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN,
|
||||
.CreationNodeMask = 1,
|
||||
.VisibleNodeMask = 1
|
||||
};
|
||||
|
||||
ID3D12Device_CreateCommittedResource(r_d3d12_state->device,
|
||||
&heap_props,
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&buffer_desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
0,
|
||||
&IID_ID3D12Resource,
|
||||
(void **)&r_d3d12_state->vertex_buffer);
|
||||
|
||||
|
||||
// Copy the triangle data to the vertex buffer.
|
||||
U8 *vtx_data_begin;
|
||||
D3D12_RANGE read_range = {0, 0}; // We don't intend to read from this resource on the CPU
|
||||
|
||||
hr = ID3D12Resource_Map(r_d3d12_state->vertex_buffer,
|
||||
0, // Subresource index (0 for buffers)
|
||||
&read_range, // Read range (NULL or {0,0} if not reading)
|
||||
&vtx_data_begin);
|
||||
D3D12_CHECK(hr, "Failed to map vertex buffer\n");
|
||||
memcpy(vtx_data_begin, &triangle_vertices[0], vertex_buffer_size);
|
||||
ID3D12Resource_Unmap(r_d3d12_state->vertex_buffer, 0, 0);
|
||||
|
||||
// Initialize the vertex buffer view.
|
||||
r_d3d12_state->vtx_buf_view.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(r_d3d12_state->vertex_buffer);
|
||||
r_d3d12_state->vtx_buf_view.StrideInBytes = sizeof(R_D3D12_Vertex);
|
||||
r_d3d12_state->vtx_buf_view.SizeInBytes = vertex_buffer_size;
|
||||
}
|
||||
|
||||
// Create shader pipeline
|
||||
{
|
||||
r_d3d12_init_vs_sources();
|
||||
r_d3d12_init_ps_sources();
|
||||
|
||||
D3D12_ROOT_SIGNATURE_DESC root_sig_desc = {0};
|
||||
root_sig_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
||||
|
||||
ID3DBlob *signature = 0;
|
||||
ID3DBlob *err_blob = 0;
|
||||
|
||||
hr = D3D12SerializeRootSignature(&root_sig_desc,
|
||||
D3D_ROOT_SIGNATURE_VERSION_1,
|
||||
&signature,
|
||||
&err_blob);
|
||||
D3D12_CHECK(hr, "Failed to serialize root signature \n");
|
||||
hr = ID3D12Device_CreateRootSignature(r_d3d12_state->device,
|
||||
0,
|
||||
ID3D10Blob_GetBufferPointer(signature),
|
||||
ID3D10Blob_GetBufferSize(signature),
|
||||
&IID_ID3D12RootSignature,
|
||||
(void **)&r_d3d12_state->root_signature);
|
||||
D3D12_CHECK(hr, "Failed to create root signature \n");
|
||||
|
||||
ID3DBlob *vtx_shader = 0;
|
||||
ID3DBlob *pxl_shader = 0;
|
||||
|
||||
|
||||
U32 compile_flags = 0; // Can be debug flags D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
|
||||
const char *vs_source = r_d3d12_get_vs_shader_source(R_D3D12_VS_Kind_Triangle);
|
||||
hr = D3DCompile(vs_source,
|
||||
c_strlen(vs_source),
|
||||
0, // Source name (0 since in memory)
|
||||
0, // shader macros, not used if 0
|
||||
0, // include handler, not used if 0
|
||||
"vs_main", // entry point
|
||||
"vs_5_0",
|
||||
compile_flags,
|
||||
0, // effect falgs
|
||||
&vtx_shader, // outputblob
|
||||
&err_blob);
|
||||
D3D12_SHADER_CHECK(hr, err_blob);
|
||||
|
||||
const char *ps_source = r_d3d12_get_ps_shader_source(R_D3D12_PS_Kind_Triangle);
|
||||
hr = D3DCompile(ps_source,
|
||||
c_strlen(ps_source),
|
||||
0, // Source name (0 since in memory)
|
||||
0, // shader macros, not used if 0
|
||||
0, // include handler, not used if 0
|
||||
"ps_main", // entry point
|
||||
"ps_5_0",
|
||||
compile_flags,
|
||||
0, // effect flags
|
||||
&pxl_shader, // outputblob
|
||||
&err_blob);
|
||||
D3D12_SHADER_CHECK(hr, err_blob);
|
||||
|
||||
|
||||
|
||||
|
||||
if(pxl_shader)
|
||||
{
|
||||
ID3D10Blob_Release(pxl_shader);
|
||||
}
|
||||
if(vtx_shader)
|
||||
{
|
||||
ID3D10Blob_Release(vtx_shader);
|
||||
}
|
||||
if(err_blob)
|
||||
{
|
||||
ID3D10Blob_Release(err_blob);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Fence
|
||||
hr = ID3D12Device_CreateFence(r_d3d12_state->device,
|
||||
0,
|
||||
D3D12_FENCE_FLAG_NONE,
|
||||
&IID_ID3D12Fence,
|
||||
(void**)&r_d3d12_state->fence);
|
||||
hr = ID3D12Device_CreateFence(r_d3d12_state->device,
|
||||
0,
|
||||
D3D12_FENCE_FLAG_NONE,
|
||||
&IID_ID3D12Fence,
|
||||
(void **)&r_d3d12_state->fence);
|
||||
D3D12_CHECK(hr, "Failed to create fence\n");
|
||||
r_d3d12_state->fence_value = 1;
|
||||
|
||||
|
||||
r_d3d12_state->fence_event = CreateEvent(0, FALSE, FALSE, 0);
|
||||
if(!r_d3d12_state->fence_event)
|
||||
if(!r_d3d12_state->fence_event)
|
||||
{
|
||||
HRESULT fence_hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
D3D12_CHECK(fence_hr, "Failed to create fence event\n");
|
||||
}
|
||||
|
||||
r_d3d12_wait_for_previous_frame();
|
||||
|
||||
r_d3d12_wait_for_previous_frame();
|
||||
}
|
||||
|
||||
internal void
|
||||
r_d3d12_wait_for_previous_frame()
|
||||
internal void r_d3d12_wait_for_previous_frame()
|
||||
{
|
||||
U64 fence_value = r_d3d12_state->fence_value;
|
||||
ID3D12CommandQueue_Signal(r_d3d12_cmd->queue, r_d3d12_state->fence, fence_value);
|
||||
r_d3d12_state->fence_value += 1;
|
||||
if(ID3D12Fence_GetCompletedValue(r_d3d12_state->fence) < fence_value)
|
||||
{
|
||||
HRESULT hr = ID3D12Fence_SetEventOnCompletion(r_d3d12_state->fence, fence_value, r_d3d12_state->fence_event);
|
||||
{
|
||||
HRESULT hr = ID3D12Fence_SetEventOnCompletion(r_d3d12_state->fence,
|
||||
fence_value,
|
||||
r_d3d12_state->fence_event);
|
||||
D3D12_CHECK(hr, "Failed to set fence event on completion\n");
|
||||
WaitForSingleObject(r_d3d12_state->fence_event, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
r_render()
|
||||
internal void r_render()
|
||||
{
|
||||
|
||||
|
||||
HRESULT hr = ID3D12CommandAllocator_Reset(r_d3d12_cmd->allocator);
|
||||
D3D12_CHECK(hr, "Failed to reset command allocator\n");
|
||||
hr = ID3D12GraphicsCommandList_Reset(r_d3d12_cmd->list1, r_d3d12_cmd->allocator, 0);
|
||||
D3D12_CHECK(hr, "Failed to reset command list\n");
|
||||
|
||||
|
||||
U32 frame_index = IDXGISwapChain3_GetCurrentBackBufferIndex(r_d3d12_state->swapchain);
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrier = {
|
||||
.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
|
||||
.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
D3D12_RESOURCE_BARRIER barrier =
|
||||
{
|
||||
.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
|
||||
.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
.Transition = {
|
||||
.pResource = r_d3d12_rt->targets[frame_index],
|
||||
.StateBefore = D3D12_RESOURCE_STATE_PRESENT,
|
||||
.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
.pResource = r_d3d12_rt->targets[frame_index],
|
||||
.StateBefore = D3D12_RESOURCE_STATE_PRESENT,
|
||||
.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES
|
||||
}
|
||||
};
|
||||
|
||||
// Transition from present to render target
|
||||
ID3D12GraphicsCommandList_ResourceBarrier(r_d3d12_cmd->list1, 1, &barrier);
|
||||
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle;
|
||||
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(r_d3d12_rt->heap, &rtv_handle);
|
||||
rtv_handle.ptr += frame_index * r_d3d12_rt->descriptor_size;
|
||||
|
||||
// Clear render target
|
||||
F32 clearColor[4] = {0.1f, 0.2f, 0.3f, 1.0f};
|
||||
ID3D12GraphicsCommandList_ClearRenderTargetView(r_d3d12_cmd->list1, rtv_handle, clearColor, 0, NULL);
|
||||
ID3D12GraphicsCommandList_ClearRenderTargetView(r_d3d12_cmd->list1,
|
||||
rtv_handle,
|
||||
clearColor,
|
||||
0,
|
||||
0);
|
||||
|
||||
// Transition render target back to present state
|
||||
|
||||
|
||||
// Transition render target back to present state
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
ID3D12GraphicsCommandList_ResourceBarrier(r_d3d12_cmd->list1, 1, &barrier);
|
||||
|
||||
// Close command list
|
||||
// Close command list
|
||||
hr = ID3D12GraphicsCommandList_Close(r_d3d12_cmd->list1);
|
||||
if (FAILED(hr)) return;
|
||||
if(FAILED(hr))
|
||||
return;
|
||||
|
||||
// Execute command list
|
||||
ID3D12CommandList* commandLists[] = { (ID3D12CommandList*)r_d3d12_cmd->list1 };
|
||||
ID3D12CommandQueue_ExecuteCommandLists(r_d3d12_cmd->queue, 1, commandLists);
|
||||
// Execute command list
|
||||
ID3D12CommandList *commandLists[] = { (ID3D12CommandList *)r_d3d12_cmd->list1 };
|
||||
|
||||
// Present frame
|
||||
ID3D12CommandQueue_ExecuteCommandLists(r_d3d12_cmd->queue,
|
||||
1,
|
||||
commandLists);
|
||||
|
||||
// Present frame
|
||||
IDXGISwapChain3_Present(r_d3d12_state->swapchain, 1, 0);
|
||||
|
||||
r_d3d12_wait_for_previous_frame();
|
||||
|
||||
}
|
||||
|
||||
internal void
|
||||
r_cleanup()
|
||||
internal void r_cleanup()
|
||||
{
|
||||
r_d3d12_wait_for_previous_frame();
|
||||
|
||||
U32 do_report_live_objects = 2; // 1 for all, 2 for only after release to check any dangling.
|
||||
// Report live objects
|
||||
if(do_report_live_objects == 1)
|
||||
{
|
||||
{
|
||||
LOG("D3D12 Reporting live objects before cleanup:\n");
|
||||
if(r_d3d12_state->device)
|
||||
{
|
||||
ID3D12DebugDevice *debug_device = 0;
|
||||
HRESULT hr = r_d3d12_state->device->lpVtbl->QueryInterface(r_d3d12_state->device,
|
||||
&IID_ID3D12DebugDevice,
|
||||
(void **)&debug_device);
|
||||
HRESULT hr = r_d3d12_state->device->lpVtbl->QueryInterface(r_d3d12_state->device, &IID_ID3D12DebugDevice, (void **)&debug_device);
|
||||
if(SUCCEEDED(hr) && debug_device)
|
||||
{
|
||||
debug_device->lpVtbl->ReportLiveDeviceObjects(debug_device,
|
||||
@ -285,18 +502,20 @@ r_cleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// State
|
||||
|
||||
D3D12_RELEASE(r_d3d12_state->debug);
|
||||
D3D12_RELEASE(r_d3d12_state->swapchain);
|
||||
D3D12_RELEASE(r_d3d12_state->fence);
|
||||
D3D12_RELEASE(r_d3d12_state->vertex_buffer);
|
||||
|
||||
// RT
|
||||
D3D12_RELEASE(r_d3d12_rt->heap);
|
||||
for(U32 i = 0; i < R_NUM_FRAMES_IN_FLIGHT; i+=1)
|
||||
for(U32 i = 0; i < R_NUM_FRAMES_IN_FLIGHT; i += 1)
|
||||
{
|
||||
D3D12_RELEASE(r_d3d12_rt->targets[i]);
|
||||
}
|
||||
|
||||
// Cmd
|
||||
D3D12_RELEASE(r_d3d12_cmd->queue);
|
||||
D3D12_RELEASE(r_d3d12_cmd->allocator);
|
||||
@ -304,13 +523,13 @@ r_cleanup()
|
||||
|
||||
// Report live objects
|
||||
if(do_report_live_objects >= 1)
|
||||
{
|
||||
{
|
||||
LOG("D3D12 Reporting live objects after cleanup (should only be device):\n");
|
||||
if(r_d3d12_state->device)
|
||||
{
|
||||
ID3D12DebugDevice *debug_device = 0;
|
||||
HRESULT hr = r_d3d12_state->device->lpVtbl->QueryInterface(r_d3d12_state->device,
|
||||
&IID_ID3D12DebugDevice,
|
||||
HRESULT hr = r_d3d12_state->device->lpVtbl->QueryInterface(r_d3d12_state->device,
|
||||
&IID_ID3D12DebugDevice,
|
||||
(void **)&debug_device);
|
||||
if(SUCCEEDED(hr) && debug_device)
|
||||
{
|
||||
@ -323,5 +542,4 @@ r_cleanup()
|
||||
D3D12_RELEASE(r_d3d12_state->device);
|
||||
|
||||
arena_release(r_d3d12_state->arena);
|
||||
|
||||
}
|
||||
@ -5,6 +5,7 @@
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_4.h>
|
||||
|
||||
#include "generated/render_d3d12.meta.h"
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
|
||||
@ -15,6 +16,13 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
|
||||
typedef struct R_D3D12_Vertex R_D3D12_Vertex;
|
||||
struct R_D3D12_Vertex
|
||||
{
|
||||
Vec3F32 pos;
|
||||
Vec4F32 color;
|
||||
};
|
||||
|
||||
|
||||
typedef struct R_D3D12_Command R_D3D12_Command;
|
||||
struct R_D3D12_Command
|
||||
@ -47,6 +55,10 @@ struct R_D3D12_State
|
||||
U64 fence_value;
|
||||
U64 frame_fence_values[R_NUM_FRAMES_IN_FLIGHT];
|
||||
HANDLE fence_event;
|
||||
ID3D12Resource *vertex_buffer;
|
||||
D3D12_VERTEX_BUFFER_VIEW vtx_buf_view;
|
||||
ID3D12PipelineState *pipeline;
|
||||
ID3D12RootSignature *root_signature;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
108
src/render/d3d12/render_shaders_d3d12.mdesk
Normal file
108
src/render/d3d12/render_shaders_d3d12.mdesk
Normal file
@ -0,0 +1,108 @@
|
||||
////////////////////////////////
|
||||
// Pipeline Tables
|
||||
|
||||
@table(name, source)
|
||||
R_D3D12_VSTable:
|
||||
{
|
||||
{Triangle r_d3d12_g_triangle_shader_src}
|
||||
{Test r_d3d12_g_test_shader_src}
|
||||
}
|
||||
|
||||
@table(name, source)
|
||||
R_D3D12_PSTable:
|
||||
{
|
||||
{Triangle r_d3d12_g_triangle_shader_src}
|
||||
{Test r_d3d12_g_test_shader_src}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Triangle shader
|
||||
|
||||
@embed_string r_d3d12_g_triangle_shader_src:
|
||||
"""
|
||||
struct PSInput
|
||||
{
|
||||
float4 position : SV_POSITION;
|
||||
float4 color : COLOR;
|
||||
};
|
||||
|
||||
PSInput vs_main(float4 position : POSITION, float4 color : COLOR)
|
||||
{
|
||||
PSInput result;
|
||||
|
||||
result.position = position;
|
||||
result.color = color;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 ps_main(PSInput input) : SV_TARGET
|
||||
{
|
||||
return input.color;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
//~ Test shader
|
||||
|
||||
@embed_string r_d3d12_g_test_shader_src:
|
||||
"""
|
||||
struct PSInput
|
||||
{
|
||||
float4 position : SV_POSITION;
|
||||
float4 color : COLOR;
|
||||
};
|
||||
|
||||
PSInput vs_main(float4 position : POSITION, float4 color : COLOR)
|
||||
{
|
||||
PSInput result;
|
||||
|
||||
result.position = position;
|
||||
result.color = color;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 ps_main(PSInput input) : SV_TARGET
|
||||
{
|
||||
return input.color;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~ Generators
|
||||
|
||||
@enum R_D3D12_VS_Kind:
|
||||
{
|
||||
@expand(R_D3D12_VSTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@enum R_D3D12_PS_Kind:
|
||||
{
|
||||
@expand(R_D3D12_PSTable a) `$(a.name)`,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
@gen @c_file
|
||||
{
|
||||
`const char *r_d3d12_g_vs_kind_source_table[R_D3D12_VS_Kind_COUNT];`;
|
||||
`internal void r_d3d12_init_vs_sources()`;
|
||||
`{`;
|
||||
@expand(R_D3D12_VSTable a) `r_d3d12_g_vs_kind_source_table[R_D3D12_VS_Kind_$(a.name)] = $(a.source);`
|
||||
`}`;
|
||||
``;
|
||||
}
|
||||
|
||||
@gen @c_file
|
||||
{
|
||||
`const char *r_d3d12_g_ps_kind_source_table[R_D3D12_PS_Kind_COUNT];`;
|
||||
`internal void r_d3d12_init_ps_sources()`;
|
||||
`{`;
|
||||
@expand(R_D3D12_PSTable a) `r_d3d12_g_ps_kind_source_table[R_D3D12_PS_Kind_$(a.name)] = $(a.source);`
|
||||
`}`;
|
||||
``;
|
||||
}
|
||||
|
||||
@ -1,6 +1,29 @@
|
||||
#ifndef RENDER_CORE_H
|
||||
#define RENDER_CORE_H
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
|
||||
#define BATCH_LIST_SIZE 256
|
||||
|
||||
typedef struct R_Batch R_Batch;
|
||||
struct R_Batch
|
||||
{
|
||||
U8 *v; // Pointer to batch data
|
||||
U64 byte_count;
|
||||
};
|
||||
|
||||
typedef struct R_BatchList R_BatchList;
|
||||
struct R_BatchList
|
||||
{
|
||||
R_Batch batch[BATCH_LIST_SIZE];
|
||||
U64 batch_count;
|
||||
U64 byte_count;
|
||||
U64 byte_per_instance;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
|
||||
|
||||
2055
src/third_party/stb/stb_sprintf.h
vendored
Normal file
2055
src/third_party/stb/stb_sprintf.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user