Compare commits

...
Author SHA1 Message Date
Patedam 5fa75c116e blue window 2026-10-27 23:06:45 -04:00
Patedam 2881b2c9d5 started d3d12 renderer. device + swap chain + associate to window 2026-10-26 22:52:08 -04:00
Patedam d79cf42a3d starting render/d3d12 layer 2026-10-25 23:37:14 -04:00
Patedam 17af5348e9 more keyboard function (is down) 2026-10-25 20:49:27 -04:00
Patedam dec8cbd059 keyboard support improved. F1 open a new window. 2026-10-25 18:12:51 -04:00
Patedam f580776964 can close windows independently 2026-10-25 15:57:52 -04:00
Patedam d2d9981efe two windows open + can close the app by pressing X 2026-10-25 15:23:07 -04:00
Patedam f6b48a1c11 window management. still missing first paint but progressing 2026-10-24 22:52:26 -04:00
Patedam bf13f269fe almost there (open window) 2026-10-24 18:17:43 -04:00
Patedam cf86dd10a7 lock submodules to version + move from stb to stb_sprintf 2026-10-24 17:36:47 -04:00
Patedam 5995dd9a47 Replace stb with standalone stb_sprintf and pin submodule versions 2026-10-24 17:31:55 -04:00
Patedam d5c6c79a76 adding xxhash 2026-10-24 17:16:41 -04:00
Patedam 7e8e626e24 adding hash library + multi windows support being started 2026-10-24 17:05:55 -04:00
Patedam f96b2e99cf windows open now 2026-10-23 23:35:45 -04:00
Patedam 4ec42f4bee open window code still not opening :) 2026-10-22 22:58:32 -04:00
Patedam 886e722c71 started window management 2026-10-20 23:15:56 -04:00
Patedam 575379e264 added thread naming 2026-10-18 23:41:43 -04:00
Patedam 17e26fdd00 fix build error 2026-10-18 23:07:59 -04:00
Patedam 5d6ca639fd Adding more core layer stuff. Can now boot. 2026-10-18 23:06:41 -04:00
Patedam 16664c68b5 wok on arena 2026-10-18 00:25:02 -04:00
Patedam ee1878cce7 core layer 2026-10-17 23:21:16 -04:00
68 changed files with 10168 additions and 10 deletions

No files matched your search

+8
View File
@@ -22,3 +22,11 @@ Struct members: lower_snake_case. Exemple: data, node, next.
global/static variables: lower_snake_case prefixed. Exemple: g_my_global.
const variables: lower_snake_case prefixed. Exemple: k_my_const_var.
Defines and Macros: ALL_CAPS_SNAKE. Exemple: MY_MACRO
Modular Architecture & Include Rules:
- Juliet uses a single-pass unity build pattern.
- Layer aggregators `<layer>_inc.h` and `<layer>_inc.c` dictate header and source inclusion order.
- Top-level translation units (e.g. `appbin_main.c`) include the layer `_inc` files in dependency order (`core` -> `render` -> `ui`...).
- Sub-files within a module (e.g. `core.h`, `core_arena.c`, `render.c`) must NEVER directly `#include` other module headers, sibling headers, or configuration defines (`core_defines.h`).
- Never add `#include` directives to sub-files to satisfy standalone LSP/compiler diagnostics. Tooling (`new_project_gen.c` / `compile_commands.json`) must supply preceding includes dynamically based on the base file include order.
- Always explain root causes and confirm with the user before editing project architecture or files.
+5 -6
View File
@@ -44,10 +44,14 @@ IncludeCategories:
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentAccessModifiers: false
IndentCaseBlocks: true
IndentPPDirectives: AfterHash
IndentWidth: 4
InsertNewlineAtEOF: true
MacroBlockBegin: ''
MacroBlockEnd: ''
Macros:
- 'EachIndex(it, count)=(uint64 it = 0; it < (count); ++it)'
- 'EachNode(it, Type, first)=(Type* it = first; it != 0; it = it->next)'
NamespaceIndentation: All
ObjCSpaceAfterProperty: true
PenaltyBreakBeforeFirstCallParameter: 100
@@ -57,15 +61,10 @@ PenaltyBreakString: 100
PenaltyExcessCharacter: 1
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left
PPIndentWidth: 1
SortIncludes: CaseInsensitive
SpacesInAngles: Never
SpacesInContainerLiterals: false
Standard: Cpp11
StatementMacros:
- UPROPERTY
- UCLASS
- USTRUCT
- GENERATED_BODY
- UENUM
TabWidth: 4
...
+14 -3
View File
@@ -3,6 +3,10 @@ CompileFlags:
- --driver-mode=cl
- -Wno-unknown-pragmas
- -Wno-unused-command-line-argument
- -Wno-unused-function
- -Wno-undefined-internal
- -Wno-initializer-overrides
- /IJuliet
Remove:
- /Yu*
- /Yc*
@@ -16,8 +20,15 @@ CompileFlags:
Diagnostics:
UnusedIncludes: None
Suppress:
- unused-function
- undefined-internal
- initializer-overrides
InlayHints:
Enabled: Yes
ParameterNames: Yes
DeducedTypes: Yes
Enabled: true
ParameterNames: true
DeducedTypes: true
Designators: true
BlockEnd: false
TypeNameLimit: 24
+1
View File
@@ -9,6 +9,7 @@
# Binaries
[Bb]in/
[Bb]uild/
[Ll]ib/
.idea/
.vs/
+11
View File
@@ -1,3 +1,14 @@
[submodule "External/Imgui"]
path = External/Imgui
url = https://github.com/ocornut/imgui.git
# Pinned to v1.93.0 (c1aaac65e)
[submodule "Juliet/external/xxHash"]
path = Juliet/external/xxHash
url = https://github.com/Cyan4973/xxHash.git
# Pinned to v0.8.4 (c87183a77)
[submodule "Juliet/external/stb_sprintf"]
path = Juliet/external/stb_sprintf
url = https://github.com/nothings/stb_sprintf.git
# Pinned to v1.10 / commit 2ffb3379e
+1 -1
+30
View File
@@ -0,0 +1,30 @@
// =============================================================================
// Safe Casts
internal uint16 safe_cast_uint16(uint32 val)
{
AssertAlways(val <= max_uint16);
uint16 result = (uint16)val;
return result;
}
internal uint32 safe_cast_uint32(uint64 val)
{
AssertAlways(val <= max_uint32);
uint32 result = (uint32)val;
return result;
}
internal int32 safe_cast_int32(int64 val)
{
AssertAlways(val <= max_int32);
int32 result = (int32)val;
return result;
}
// =============================================================================
// Third party includes
#define STB_SPRINTF_IMPLEMENTATION
#define STB_SPRINTF_STATIC
#include "external/stb_sprintf/stb_sprintf.h"
+299
View File
@@ -0,0 +1,299 @@
#pragma once
#include <stdint.h>
// =============================================================================
// Third party includes
#define STB_SPRINTF_DECORATE(name) juliet_##name
#define STB_SPRINTF_STATIC
#include "external/stb_sprintf/stb_sprintf.h"
#define internal static
#define global static
#define local_persist static
#if (COMPILER_CLANG && OS_WINDOWS) || COMPILER_MSVC
# pragma section(".rdata$", read)
# define read_only __declspec(allocate(".rdata$"))
#elif (COMPILER_CLANG && OS_LINUX)
# define read_only __attribute__((section(".rodata")))
#else
// Note: not possible with GCC
# define read_only
#endif
#if COMPILER_CLANG || COMPILER_GCC
# define thread_static __thread
#elif COMPILER_MSVC
# define thread_static __declspec(thread)
#else
# error thread_static not defined for this compiler
#endif
// =============================================================================
// Units
#define KB(d) ((uint64)(d) << 10)
#define MB(d) ((uint64)(d) << 20)
#define GB(d) ((uint64)(d) << 30)
#define Million(n) ((n) * 1000000)
// =============================================================================
// 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)
// =============================================================================
// Min Max Clamp
#define Min(A, B) (((A) < (B) ? (A) : (B)))
#define Max(A, B) (((A) > (B) ? (A) : (B)))
#define ClampTop(A, X) Min(A, X)
#define ClampBottom(X, B) Max(X, B)
#define Clamp(A, X, B) (((X) < (A)) ? (A) : ((X) > (B)) ? (B) : (X))
// =============================================================================
// Alignment
#if COMPILER_CLANG || COMPILER_GCC
# define AlignOf(Type) __alignof(Type)
#elif COMPILER_MSVC
# define AlignOf(Type) __alignof(Type)
#else
# error AlignOf not defined for this compiler
#endif
// =============================================================================
// For loop helpers
#define DeferLoop(begin, end) for (int _i_ = ((begin), 0); !_i_; ++_i_, (end))
#define EachIndex(it, count) (uint64 it = 0; it < (count); ++it)
#define EachNode(it, Type, first) (Type* it = first; it != 0; it = it->next)
// =============================================================================
// Memory Helpers
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
#define MemorySet(dst, src, size) memset((dst), (src), (size))
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
#define MemoryZero(ptr, size) memset((ptr), 0, (size))
#define MemoryZeroStruct(s) MemoryZero((s), sizeof(*(s)))
#define MemoryZeroArray(arr) MemoryZero((arr), sizeof(arr))
#define MemoryMatch(a, b, size) (MemoryCompare((a), (b), (size)) == 0)
#define MemoryMatchStruct(a, b) MemoryMatch((a), (b), sizeof(*(a)))
#define MemoryMatchArray(a, b) MemoryMatch((a), (b), sizeof(a))
// =============================================================================
// Asserts
#if COMPILER_CLANG || COMPILER_GCC
# define Trap() __builtin_trap()
#elif COMPILER_MSVC
# define Trap() __debugbreak()
#else
# error Unknown trap intrinsic for this compiler
#endif
#define AssertAlways(cond) \
do \
{ \
if (!(cond)) \
{ \
Trap(); \
} \
} \
while (0)
#if BUILD_DEBUG
# define Assert(cond) AssertAlways(cond)
#else
# define Assert(cond) (void)(cond)
#endif
#define StaticAssert(cond, ID) global uint8 GLUE(ID, __LINE__)[(cond) ? 1 : -1]
// =============================================================================
// Linked List macro
// Linked list macro helpers
#define CheckNil(nil, ptr) ((ptr) == 0 || (ptr) == nil)
#define SetNil(nil, ptr) ((ptr) = nil)
// Doubly-linked-lists
// clang-format off
#define DLL_insert_next_prev_zero(nil, first, last, ptr, node, next, previous) \
(CheckNil(nil, first) ? ((first) = (last) = (node), SetNil(nil, (node)->next), SetNil(nil, (node)->previous)) \
: CheckNil(nil, ptr) ? ((node)->next = (first), (first)->previous = (node), (first) = (node), SetNil(nil, (node)->previous)) \
: ((ptr) == (last)) ? ((last)->next = (node), (node )->previous = (last), (last ) = (node), SetNil(nil, (node)->next)) \
: (((CheckNil(nil, ptr) && CheckNil(nil, (ptr)->next)) ? (0) : ((ptr)->next->previous = (node))), \
((node)->next = (ptr)->next), ((ptr)->next = (node)), ((node)->previous = (ptr))))
#define DLL_push_back_next_prev_zero(nil, first, last, node, next, previous) \
DLL_insert_next_prev_zero(nil, first, last, last, node, next, previous)
#define DLL_remove_next_prev_zero(nil, first, last, node, next, previous) \
(((node) == (first) ? (first) = (node)->next : (0)), ((node) == (last) ? (last) = (last)->previous : (0)), \
(CheckNil(nil, (node)->previous) ? (0) : ((node)->previous->next = (node)->next)), \
(CheckNil(nil, (node)->next) ? (0) : ((node)->next->previous = (node)->previous)))
// clang-format on
// Single link double head lists (= queues)
#define SLL_queue_push_next_zero(nil, first, last, node, next) \
(CheckNil(nil, first) ? ((first) = (last) = (node), SetNil(nil, (node)->next)) \
: ((last)->next = (node), (last) = (node), SetNil(nil, (node)->next)))
// Single (link & head) lists (= stacks)
#define SLL_stack_push_next(first, node, next) ((node)->next = (first), (first) = (node))
#define SLL_stack_pop_next(first, next) ((first) = (first)->next);
// Double linked list helpers
#define DLL_push_back_next_prev(first, last, node, next, previous) \
DLL_push_back_next_prev_zero(0, first, last, node, next, previous)
#define DLL_remove_next_prev(first, last, node, next, prev) DLL_remove_next_prev_zero(0, first, last, node, next, prev)
#define DLL_push_back(first, last, node) DLL_push_back_next_prev_zero(0, first, last, node, next, previous)
#define DLL_remove(first, last, node) DLL_remove_next_prev_zero(0, first, last, node, next, previous)
// Queue helpers
#define SLL_queue_push(first, last, node) SLL_queue_push_next_zero(0, first, last, node, next)
// Stack helpers
#define SLL_stack_push(first, node) SLL_stack_push_next(first, node, next)
#define SLL_stack_pop(first) SLL_stack_pop_next(first, next)
// =============================================================================
// Helpers
#define AlignPow2(x, align) (((x) + (align) - 1) & (~((align) - 1)))
#define Stringify_(S) #S
#define Stringify(S) Stringify_(S)
#define GLUE_(A, B) A##B
#define GLUE(A, B) GLUE_(A, B)
#define ArrayCount(arr) (sizeof(arr) / sizeof((arr)[0]))
#if ARCH_64BIT
# define IntFromPtr(ptr) ((uint64)(ptr))
#else
# error Missing pointer to integer cast for this architecture
#endif
#define PtrFromInt(i) (void*)(i)
// =============================================================================
// Core Types
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef float float32;
typedef double float64;
typedef int8 bool8;
typedef int16 bool16;
typedef int32 bool32;
typedef int64 bool64;
// =============================================================================
// Core Constants
global uint8 max_uint8 = 0xFF;
global uint16 max_uint16 = 0xFFFF;
global uint32 max_uint32 = 0xFFFFFFFF;
global uint64 max_uint64 = 0xFFFFFFFFFFFFFFFFll;
global int8 max_int8 = (int8)0x7F;
global int16 max_int16 = (int16)0x7FFF;
global int32 max_int32 = (int32)0x7FFFFFFF;
global int64 max_int64 = (int64)0x7FFFFFFFFFFFFFFFll;
global const uint32 bitmask1 = 0x00000001;
global const uint32 bitmask2 = 0x00000003;
global const uint32 bitmask3 = 0x00000007;
global const uint32 bitmask4 = 0x0000000f;
global const uint32 bitmask5 = 0x0000001f;
global const uint32 bitmask6 = 0x0000003f;
global const uint32 bitmask7 = 0x0000007f;
global const uint32 bitmask8 = 0x000000ff;
global const uint32 bitmask9 = 0x000001ff;
global const uint32 bitmask10 = 0x000003ff;
global const uint32 bitmask11 = 0x000007ff;
global const uint32 bitmask12 = 0x00000fff;
global const uint32 bitmask13 = 0x00001fff;
global const uint32 bitmask14 = 0x00003fff;
global const uint32 bitmask15 = 0x00007fff;
global const uint32 bitmask16 = 0x0000ffff;
global const uint32 bitmask17 = 0x0001ffff;
global const uint32 bitmask18 = 0x0003ffff;
global const uint32 bitmask19 = 0x0007ffff;
global const uint32 bitmask20 = 0x000fffff;
global const uint32 bitmask21 = 0x001fffff;
global const uint32 bitmask22 = 0x003fffff;
global const uint32 bitmask23 = 0x007fffff;
global const uint32 bitmask24 = 0x00ffffff;
global const uint32 bitmask25 = 0x01ffffff;
global const uint32 bitmask26 = 0x03ffffff;
global const uint32 bitmask27 = 0x07ffffff;
global const uint32 bitmask28 = 0x0fffffff;
global const uint32 bitmask29 = 0x1fffffff;
global const uint32 bitmask30 = 0x3fffffff;
global const uint32 bitmask31 = 0x7fffffff;
global const uint32 bitmask32 = 0xffffffff;
global const uint32 bit1 = (1 << 0);
global const uint32 bit2 = (1 << 1);
global const uint32 bit3 = (1 << 2);
global const uint32 bit4 = (1 << 3);
global const uint32 bit5 = (1 << 4);
global const uint32 bit6 = (1 << 5);
global const uint32 bit7 = (1 << 6);
global const uint32 bit8 = (1 << 7);
global const uint32 bit9 = (1 << 8);
global const uint32 bit10 = (1 << 9);
global const uint32 bit11 = (1 << 10);
global const uint32 bit12 = (1 << 11);
global const uint32 bit13 = (1 << 12);
global const uint32 bit14 = (1 << 13);
global const uint32 bit15 = (1 << 14);
global const uint32 bit16 = (1 << 15);
global const uint32 bit17 = (1 << 16);
global const uint32 bit18 = (1 << 17);
global const uint32 bit19 = (1 << 18);
global const uint32 bit20 = (1 << 19);
global const uint32 bit21 = (1 << 20);
global const uint32 bit22 = (1 << 21);
global const uint32 bit23 = (1 << 22);
global const uint32 bit24 = (1 << 23);
global const uint32 bit25 = (1 << 24);
global const uint32 bit26 = (1 << 25);
global const uint32 bit27 = (1 << 26);
global const uint32 bit28 = (1 << 27);
global const uint32 bit29 = (1 << 28);
global const uint32 bit30 = (1 << 29);
global const uint32 bit31 = (1 << 30);
global const uint32 bit32 = (1 << 31);
// =============================================================================
// Safe Casts
internal uint16 safe_cast_uint16(uint32 val);
internal uint32 safe_cast_uint32(uint64 val);
internal int32 safe_cast_int32(int64 val);
// =============================================================================
// Time functions
internal uint64 now_time_us();
internal void sleep_ms(uint32 ms);
+193
View File
@@ -0,0 +1,193 @@
// =============================================================================
// Arena Functions
#include "core/core.h"
internal Arena* arena_alloc_internal(ArenaParams* params)
{
uint64 committed = params->commit_size;
uint64 reserved = params->reserve_size;
// Initial block
void* base = NULL;
if (params->flags & ArenaFlag_LargePages)
{
uint64 page_size = get_system_info()->large_page_size;
reserved = AlignPow2(reserved, page_size);
committed = AlignPow2(committed, page_size);
base = reserve_memory_large(reserved);
commit_memory_large(base, committed);
}
else
{
uint64 page_size = get_system_info()->page_size;
reserved = AlignPow2(reserved, page_size);
committed = AlignPow2(committed, page_size);
base = reserve_memory(reserved);
commit_memory(base, committed);
}
if (Unlikely(base == 0))
{
abort_self(1);
}
Arena* arena = base;
arena->current = arena;
arena->commit_size = params->commit_size;
arena->reserve_size = params->reserve_size;
arena->base_position = 0;
arena->position = ARENA_HEADER_SIZE;
arena->committed = committed;
arena->reserved = reserved;
#if BUILD_DEBUG
arena->alloc_file = params->alloc_file;
arena->alloc_line = params->alloc_line;
arena->name = params->name;
#endif
return arena;
}
internal void arena_release(Arena* arena)
{
for (Arena *p = arena->current, *prev = 0; p != 0; p = prev)
{
prev = p->previous;
release_memory(p, p->reserved);
}
}
// =============================================================================
// Arena Push/Pop core Functions
internal void* arena_push(Arena* arena, uint64 size, uint64 align, bool32 zero)
{
Arena* current = arena->current;
uint64 pos_pre = AlignPow2(current->position, align);
uint64 pos_post = pos_pre + size;
uint64 size_to_zero = 0;
if (zero)
{
size_to_zero = Min(current->committed, pos_post) - pos_pre;
}
if (current->reserved < pos_post && !(arena->flags & ArenaFlag_NoChain))
{
Arena* new_block = 0;
if (new_block == 0)
{
uint64 reserved_size = arena->reserve_size;
uint64 committed_size = arena->commit_size;
if (size + ARENA_HEADER_SIZE > reserved_size)
{
reserved_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
committed_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
}
new_block = arena_alloc(.reserve_size = reserved_size, .commit_size = committed_size, .flags = arena->flags,
#if BUILD_DEBUG
.alloc_file = arena->alloc_file, .alloc_line = arena->alloc_line
#endif
);
size_to_zero = 0;
}
else
{
size_to_zero = size;
}
new_block->base_position = current->base_position + current->reserved;
SLL_stack_push_next(arena->current, new_block, previous);
current = new_block;
pos_pre = AlignPow2(current->position, align);
pos_post = pos_pre + size;
}
// commit new pages if needed
if (current->committed < pos_post)
{
uint64 committed_past_aligned = pos_post + current->commit_size - 1;
committed_past_aligned -= committed_past_aligned % current->commit_size;
uint64 committed_past_clamped = ClampTop(committed_past_aligned, current->reserved);
uint64 committed_size = committed_past_clamped - current->committed;
uint8* committed_ptr = (uint8*)current + current->committed;
if (current->flags & ArenaFlag_LargePages)
{
commit_memory_large(committed_ptr, committed_size);
}
else
{
commit_memory(committed_ptr, committed_size);
}
current->committed = committed_past_clamped;
}
void* result = 0;
if (current->committed >= pos_post)
{
result = (uint8*)current + pos_pre;
current->position = pos_post;
MemoryZero(result, size_to_zero);
}
if (Unlikely(result == 0))
{
abort_self(1);
}
return result;
}
internal uint64 arena_pos(Arena* arena)
{
Arena* current = arena->current;
uint64 position = current->base_position + current->position;
return position;
}
internal void arena_pop_to(Arena* arena, uint64 position)
{
uint64 clamped_pos = ClampBottom(ARENA_HEADER_SIZE, position);
Arena* current = arena->current;
for (Arena* previous = 0; current->base_position >= clamped_pos; current = previous)
{
previous = current->previous;
release_memory(current, current->reserved);
}
arena->current = current;
uint64 new_position = clamped_pos - current->base_position;
AssertAlways(new_position <= current->position);
current->position = new_position;
}
internal void arena_clear(Arena* arena)
{
arena_pop_to(arena, 0);
}
internal void arena_pop(Arena* arena, uint64 amount)
{
uint64 pos_old = arena_pos(arena);
Assert(pos_old > amount);
uint64 pos_new = pos_old - amount;
arena_pop_to(arena, pos_new);
}
// Temp arena
internal TempArena temp_begin(Arena* arena)
{
uint64 position = arena_pos(arena);
TempArena temp = { arena, position };
return temp;
}
internal void temp_end(TempArena temp)
{
arena_pop_to(temp.arena, temp.position);
}
+88
View File
@@ -0,0 +1,88 @@
#pragma once
#define ARENA_HEADER_SIZE 128
// =============================================================================
// Arena Types
typedef uint64 ArenaFlags;
enum
{
ArenaFlag_NoChain = (1 << 0),
ArenaFlag_LargePages = (1 << 1),
};
typedef struct ArenaParams ArenaParams;
struct ArenaParams
{
ArenaFlags flags;
uint64 commit_size;
uint64 reserve_size;
char* alloc_file;
int alloc_line;
char* name;
};
typedef struct Arena Arena;
struct Arena
{
Arena* previous;
Arena* current;
ArenaFlags flags;
uint64 base_position;
uint64 position;
uint64 commit_size;
uint64 committed;
uint64 reserve_size;
uint64 reserved;
#if BUILD_DEBUG
char* alloc_file;
int alloc_line;
char* name;
#endif
};
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
typedef struct TempArena TempArena;
struct TempArena
{
Arena* arena;
uint64 position;
};
// =============================================================================
// Arena Functions
global uint64 arena_default_reserve_size = MB(64);
global uint64 arena_default_commit_size = KB(64);
internal Arena* arena_alloc_internal(ArenaParams* params);
#define arena_alloc(...) \
arena_alloc_internal(&(ArenaParams){ .commit_size = arena_default_commit_size, \
.reserve_size = arena_default_reserve_size, \
.alloc_file = __FILE__, \
.alloc_line = __LINE__, \
__VA_ARGS__ })
internal void arena_release(Arena* arena);
// Arena Push/Pop core Functions
internal void* arena_push(Arena* arena, uint64 size, uint64 align, bool32 zero);
internal uint64 arena_pos(Arena* arena);
internal void arena_pop_to(Arena* arena, uint64 position);
internal void arena_clear(Arena* arena);
internal void arena_pop(Arena* arena, uint64 amount);
// Temp arena
internal TempArena temp_begin(Arena* arena);
internal void temp_end(TempArena temp);
// =============================================================================
// Push Helper Macros
#define push_array_no_zero_aligned(arr, Type, count, align) \
(Type*)arena_push((arr), sizeof(Type) * (count), (align), (0))
#define push_array_aligned(arr, Type, count, align) (Type*)arena_push((arr), sizeof(Type) * (count), (align), (1))
#define push_array_no_zero(arr, Type, count) push_array_no_zero_aligned(arr, Type, count, Max(8, AlignOf(Type)))
#define push_array(arr, Type, count) push_array_aligned(arr, Type, count, Max(8, AlignOf(Type)))
+98
View File
@@ -0,0 +1,98 @@
#pragma once
// ========================================================================== //
// Compiler defines | Clang
#if defined(__clang__)
# define COMPILER_CLANG 1
# if defined(_WIN32)
# define OS_WINDOWS 1
# else
# error Compiler / OS combo is not supported
# endif
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
# define ARCH_X64 1
# else
# error Architecture not supported
# endif
#elif defined(_MSC_VER)
# define COMPILER_MSVC 1
# if defined(_WIN32)
# define OS_WINDOWS 1
# else
# error Compiler / OS combo is not supported
# endif
# if defined(_M_AMD64)
# define ARCH_X64 1
# else
# error Architecture not supported
# endif
#else
# error Compiler not supported.
#endif
// ========================================================================== //
// Architecture
#if defined(ARCH_X64)
# define ARCH_64BIT 1
#endif
// ========================================================================== //
// Language
#if defined(__cplusplus)
# define LANG_CPP 1
#else
# define LANG_C 1
#endif
// ========================================================================== //
// Build Options
#if !defined(BUILD_DEBUG)
# define BUILD_DEBUG 1
#endif
// ========================================================================== //
// Zeroing unused Options
#if !defined(ARCH_X64)
# define ARCH_X64 0
#endif
#if !defined(ARCH_X86)
# define ARCH_X86 0
#endif
#if !defined(COMPILER_CLANG)
# define COMPILER_CLANG 0
#endif
#if !defined(COMPILER_MSVC)
# define COMPILER_MSVC 0
#endif
#if !defined(OS_WINDOWS)
# define OS_WINDOWS 0
#endif
#if !defined(LANG_CPP)
# define LANG_CPP 0
#endif
#if !defined(LANG_C)
# define LANG_C 0
#endif
#if !ARCH_X64
# error Trying to build unsupported architecture. Only x64 is supported.
#endif
+13
View File
@@ -0,0 +1,13 @@
internal void entry_point();
internal void main_thread_core_entry_point(int argc, char** argv)
{
ThreadNameF("main_thread");
entry_point();
}
internal bool32 update()
{
bool32 result = frame();
return result;
}
+4
View File
@@ -0,0 +1,4 @@
#pragma once
internal void main_thread_core_entry_point(int argc, char** argv);
internal bool32 update();
+26
View File
@@ -0,0 +1,26 @@
// =============================================================================
// Hash Functions
#pragma push_macro("__cpuid")
#undef __cpuid
#if !defined(XXH_IMPLEMENTATION)
# define XXH_INLINE_ALL
# define XXH_IMPLEMENTATION
# define XXH_STATIC_LINKING_ONLY
# include "external/xxHash/xxhash.h"
#endif
#pragma pop_macro("__cpuid")
#define HASH_SEED 4259
internal uint64 uint64_hash_from_string(String8 string)
{
uint64 result = uint64_hash_from_seed_string(HASH_SEED, string);
return result;
}
internal uint64 uint64_hash_from_seed_string(uint64 seed, String8 string)
{
uint64 result = XXH3_64bits_withSeed(string.str, string.size, seed);
return result;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
// =============================================================================
// Hash Functions
internal uint64 uint64_hash_from_string(String8 string);
internal uint64 uint64_hash_from_seed_string(uint64 seed, String8 string);
+20
View File
@@ -0,0 +1,20 @@
// clang-format off
#include "core.c"
#include "core_memory.c"
#include "core_arena.c"
#include "core_math.c"
#include "core_string.c"
#include "core_hash.c"
#include "core_system.c"
#include "core_threads.c"
#include "core_thread_context.c"
#include "core_processes.c"
#include "core_markup.c"
#include "core_entry_point.c"
// clang-format on
#if OS_WINDOWS
# include "win32/core/win32_core.c"
#elif
# error Unsupported OS
#endif
+24
View File
@@ -0,0 +1,24 @@
#pragma once
// clang-format off
#include "core_defines.h"
#include "core.h"
#include "core_memory.h"
#include "core_processes.h"
#include "core_arena.h"
#include "core_math.h"
#include "core_string.h"
#include "core_hash.h"
#include "core_system.h"
#include "core_threads.h"
#include "core_thread_context.h"
#include "core_markup.h"
#include "core_entry_point.h"
// clang-format on
#if OS_WINDOWS
# include "win32/core/win32_core.h"
#elif
# error Unsupported OS
#endif
View File
Whitespace-only changes.
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__))
+33
View File
@@ -0,0 +1,33 @@
// =============================================================================
// Functions
// =============================================================================
// Vectors
internal Vector2f vector_2f(float32 x, float32 y)
{
Vector2f v = { x, y };
return v;
}
// =============================================================================
// Rectangles
internal Rect2f rect_2f(Vector2f min, Vector2f max)
{
Rect2f rect = { min, max };
return rect;
}
internal bool32 contains_2f(Rect2f rect, Vector2f x)
{
bool32 cond = (rect.min.x <= x.x && x.x < rect.max.x && rect.min.y <= x.y && x.y < rect.max.y);
return cond;
}
internal Vector2f dimension_2f(Rect2f rect)
{
Vector2f dim = { ((rect.max.x > rect.min.x) ? (rect.max.x - rect.min.x) : 0),
((rect.max.y > rect.min.y) ? (rect.max.y - rect.min.y) : 0) };
return dim;
}
+70
View File
@@ -0,0 +1,70 @@
#pragma once
// =============================================================================
// Vector Types
typedef union Vector2f Vector2f;
union Vector2f
{
struct
{
float32 x;
float32 y;
};
float32 v[2];
};
typedef union Vector2i Vector2i;
union Vector2i
{
struct
{
int32 x;
int32 y;
};
int32 v[2];
};
// =============================================================================
// Rect Types
typedef union Rect2f Rect2f;
union Rect2f
{
struct
{
Vector2f min;
Vector2f max;
};
struct
{
Vector2f p0;
Vector2f p1;
};
struct
{
float32 x0;
float32 y0;
float32 x1;
float32 y1;
};
Vector2f v[2];
};
// =============================================================================
// Functions
// =============================================================================
// Vectors
#define vector2f(x, y) vector_2f((x), (y))
internal Vector2f vector_2f(float32 x, float32 y);
// =============================================================================
// Rectangles
#define rect2f(min, max) rect_2f((min), (max))
#define rect2fp(x, y, z, w) rect2f(vector2f((x), (y)), vector2f((z), (w)))
internal Rect2f rect_2f(Vector2f min, Vector2f max);
internal bool32 contains_2f(Rect2f rect, Vector2f x);
internal Vector2f dimension_2f(Rect2f rect);
+1
View File
@@ -0,0 +1 @@
// OS DEPEND see os/core/os_core.c
+8
View File
@@ -0,0 +1,8 @@
#pragma once
internal void* reserve_memory(uint64 size);
internal bool32 commit_memory(void* ptr, uint64 size);
internal void* reserve_memory_large(uint64 size);
internal bool32 commit_memory_large(void* ptr, uint64 size);
internal void decommit_memory(void* ptr, uint64 size);
internal void release_memory(void* ptr, uint64 size);
View File
Whitespace-only changes.
+6
View File
@@ -0,0 +1,6 @@
#pragma once
// =============================================================================
// Aborting (os dependent see os/core/os_core.c)
internal void abort_self(uint64 exit_code);
+395
View File
@@ -0,0 +1,395 @@
#ifndef MEM_STATIC
# define MEM_STATIC
# define MEM_API static inline
# include "external/memfun/memfun.h"
#endif
// =============================================================================
// String conversions
internal bool32 char_is_upper(uint8 c)
{
return ('A' <= c && c <= 'Z');
}
internal bool32 char_is_lower(uint8 c)
{
return ('a' <= c && c <= 'z');
}
internal bool32 char_is_slash(uint8 c)
{
return (c == '/' || c == '\\');
}
internal uint8 lower_from_char(uint8 c)
{
if (char_is_upper(c))
{
c += ('a' - 'A');
}
return c;
}
internal uint8 upper_from_char(uint8 c)
{
if (char_is_lower(c))
{
c += ('A' - 'a');
}
return c;
}
internal uint8 correct_slash_from_char(uint8 c)
{
if (char_is_slash(c))
{
c = '/';
}
return c;
}
// ========================================================================== //
// String Length
internal uint64 cstring8_length(uint8* cstring)
{
uint64 length = 0;
if (cstring)
{
uint8* p = cstring;
for (; *p != '\0'; ++p)
;
length = (uint64)(p - cstring);
}
return length;
}
internal uint64 cstring16_length(uint16* cstring)
{
uint64 length = 0;
if (cstring)
{
uint16* p = cstring;
for (; *p != '\0'; ++p)
;
length = (uint64)(p - cstring);
}
return length;
}
internal uint64 cstring32_length(uint32* cstring)
{
uint64 length = 0;
if (cstring)
{
uint32* p = cstring;
for (; *p != '\0'; ++p)
;
length = (uint64)(p - cstring);
}
return length;
}
// ========================================================================== //
// String Constructor
internal String8 str8(uint8* str, uint64 size)
{
String8 result = { str, size };
return result;
}
internal String8 str8_zero()
{
String8 result = { 0 };
return result;
}
internal String16 str16(uint16* str, uint64 size)
{
String16 result = { str, size };
return result;
}
internal String16 str16_zero()
{
String16 result = { 0 };
return result;
}
internal String8 str8_cstring(const char* cstring)
{
String8 result = { (uint8*)cstring, cstring8_length((uint8*)cstring) };
return result;
}
internal String16 str16_cstring(uint16* cstring)
{
String16 result = { (uint16*)cstring, cstring16_length((uint16*)cstring) };
return result;
}
internal String32 str32_cstring(uint32* cstring)
{
String32 result = { (uint32*)cstring, cstring32_length((uint32*)cstring) };
return result;
}
// =============================================================================
// String Matching
internal bool32 str8_match(String8 a, String8 b, StringMatchFlags flags)
{
bool32 result = 0;
if (a.size == b.size && flags == 0)
{
result = MemIsEqual(a.str, b.str, b.size);
}
else if (a.size == b.size && flags == StringMatchFlag_CaseInsensitive)
{
result = MemCompareI(a.str, b.str, a.size) == 0;
}
else if (a.size == b.size || (flags * StringMatchFlag_RightSideSloppy))
{
bool32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive);
bool32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive);
uint64 size = Min(a.size, b.size);
result = 1;
for EachIndex(i, size)
{
uint8 at = a.str[i];
uint8 bt = b.str[i];
if (case_insensitive)
{
at = upper_from_char(at);
bt = upper_from_char(bt);
}
if (slash_insensitive)
{
at = correct_slash_from_char(at);
bt = correct_slash_from_char(bt);
}
if (at != bt)
{
result = 0;
break;
}
}
}
return result;
}
// =============================================================================
// String Formatting & Copying
internal String8 str8_copy(Arena* arena, String8 in)
{
String8 str;
str.size = in.size;
str.str = push_array_no_zero(arena, uint8, str.size + 1);
MemoryCopy(str.str, in.str, in.size);
str.str[str.size] = '\0';
return str;
}
internal String8 str8fv(Arena* arena, char* fmt, va_list args)
{
va_list args2;
va_copy(args2, args);
uint32 needed_bytes = juliet_vsnprintf(0, 0, fmt, args) + 1;
String8 result = { 0 };
result.str = push_array_no_zero(arena, uint8, needed_bytes);
result.size = juliet_vsnprintf((char*)result.str, needed_bytes, fmt, args2);
result.str[result.size] = '\0';
va_end(args2);
return result;
}
// =============================================================================
// Unicode String Encode/Decode
read_only global uint8 utf8_class[32] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 5,
};
internal UnicodeDecode utf8_decode(uint8* str, uint64 max)
{
UnicodeDecode result = { 1, max_uint32 };
uint8 byte = str[0];
uint8 byte_class = utf8_class[byte >> 3];
switch (byte_class)
{
case 1:
{
result.codepoint = byte;
break;
}
case 2:
{
if (1 < max)
{
uint8 cont_byte = str[1];
if (utf8_class[cont_byte >> 3] == 0)
{
result.codepoint = (byte & bitmask5) << 6;
result.codepoint |= (cont_byte & bitmask6);
result.increment = 2;
}
}
break;
}
case 3:
{
if (2 < max)
{
uint8 cont_byte[2] = { str[1], str[2] };
if (utf8_class[cont_byte[0] >> 3] == 0 && utf8_class[cont_byte[1] >> 3] == 0)
{
result.codepoint = (byte & bitmask4) << 12;
result.codepoint |= ((cont_byte[0] & bitmask6) << 6);
result.codepoint |= (cont_byte[1] & bitmask6);
result.increment = 3;
}
}
break;
}
case 4:
{
if (3 < max)
{
uint8 cont_byte[3] = { str[1], str[2], str[3] };
if (utf8_class[cont_byte[0] >> 3] == 0 && utf8_class[cont_byte[1] >> 3] == 0 && utf8_class[cont_byte[2] >> 3] == 0)
{
result.codepoint = (byte & bitmask3) << 18;
result.codepoint |= ((cont_byte[0] & bitmask6 << 12));
result.codepoint |= ((cont_byte[1] & bitmask6) << 6);
result.codepoint |= (cont_byte[2] & bitmask6);
result.increment = 4;
}
}
break;
}
}
return result;
}
internal UnicodeDecode utf16_decode(uint16* str, uint64 max)
{
UnicodeDecode result = { 1, max_uint32 };
result.codepoint = str[0];
result.increment = 1;
if (max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000)
{
result.codepoint = ((str[0] - 0xD800) << 10) | ((str[1] - 0xDC00) + 0x10000);
result.increment = 2;
}
return result;
}
internal uint32 utf8_encode(uint8* str, uint32 codepoint)
{
uint32 increment = 0;
if (codepoint <= 0x7f)
{
str[0] = (uint8)codepoint;
increment = 1;
}
else if (codepoint <= 0x7FF)
{
str[0] = (bitmask2 << 6) | ((codepoint >> 6) & bitmask5);
str[1] = bit8 | (codepoint & bitmask6);
increment = 2;
}
else if (codepoint <= 0xFFFF)
{
str[0] = (bitmask3 << 5) | ((codepoint >> 12) & bitmask4);
str[1] = bit8 | ((codepoint >> 6) & bitmask6);
str[2] = bit8 | (codepoint & bitmask6);
increment = 3;
}
else if (codepoint <= 0x10FFFF)
{
str[0] = (bitmask4 << 4) | ((codepoint >> 18) & bitmask3);
str[1] = bit8 | ((codepoint >> 12) & bitmask6);
str[2] = bit8 | (codepoint >> 6 & bitmask6);
str[3] = bit8 | (codepoint & bitmask6);
increment = 4;
}
else
{
str[0] = '?';
increment = 1;
}
return increment;
}
internal uint32 utf16_encode(uint16* str, uint32 codepoint)
{
uint32 increment = 1;
if (codepoint == max_uint32)
{
str[0] = (uint16)'?';
}
else if (codepoint < 0x10000)
{
str[0] = (uint16)codepoint;
}
else
{
uint32 v = codepoint - 0x10000;
str[0] = safe_cast_uint16(0xD800 + (v >> 10));
str[1] = safe_cast_uint16(0xDC00 + (v & bitmask10));
increment = 2;
}
return increment;
}
// =============================================================================
// Unicode String Conversions
internal String8 str8_from_16(Arena* arena, String16 in)
{
String8 result = str8_zero();
if (in.size)
{
uint64 capacity = in.size * 3;
uint8* str = push_array_no_zero(arena, uint8, capacity + 1);
uint16* ptr = in.str;
uint16* opl = ptr + in.size;
uint64 size = 0;
UnicodeDecode consume;
for (; ptr < opl; ptr += consume.increment)
{
consume = utf16_decode(ptr, opl - ptr);
size += utf8_encode(str + size, consume.codepoint);
}
str[size] = '\0';
arena_pop(arena, (capacity - size));
result = str8(str, size);
}
return result;
}
internal String16 str16_from_8(Arena* arena, String8 in)
{
String16 result = str16_zero();
if (in.size)
{
uint64 capacity = in.size * 2;
uint16* str = push_array_no_zero(arena, uint16, capacity + 1);
uint8* ptr = in.str;
uint8* opl = ptr + in.size;
uint64 size = 0;
UnicodeDecode consume;
for (; ptr < opl; ptr += consume.increment)
{
consume = utf8_decode(ptr, opl - ptr);
size += utf16_encode(str + size, consume.codepoint);
}
str[size] = '\0';
arena_pop(arena, (capacity - size) * 2);
result = str16(str, size);
}
return result;
}
+104
View File
@@ -0,0 +1,104 @@
#pragma once
// =============================================================================
// String Types
typedef struct String8 String8;
struct String8
{
uint8* str;
uint64 size;
};
typedef struct String16 String16;
struct String16
{
uint16* str;
uint64 size;
};
typedef struct String32 String32;
struct String32
{
uint32* str;
uint64 size;
};
// =============================================================================
// String Matching Types
typedef uint32 StringMatchFlags;
enum
{
StringMatchFlag_CaseInsensitive = (1 << 0),
StringMatchFlag_RightSideSloppy = (1 << 1),
StringMatchFlag_SlashInsensitive = (1 << 2),
};
// =============================================================================
// Unicode decoding Types
typedef struct UnicodeDecode UnicodeDecode;
struct UnicodeDecode
{
uint32 increment;
uint32 codepoint;
};
// =============================================================================
// String conversions
internal bool32 char_is_upper(uint8 c);
internal bool32 char_is_lower(uint8 c);
internal bool32 char_is_slash(uint8 c);
internal uint8 lower_from_char(uint8 c);
internal uint8 upper_from_char(uint8 c);
internal uint8 correct_slash_from_char(uint8 c);
// =============================================================================
// String Length
internal uint64 cstring8_length(uint8* cstring);
internal uint64 cstring16_length(uint16* cstring);
internal uint64 cstring32_length(uint32* cstring);
// =============================================================================
// String Constructor
#define str8_literal(S) str8((uint8*)(S), sizeof(S) - 1)
#define str8_struct(S) str8((uint8*)(S), sizeof(*(S)))
internal String8 str8(uint8* str, uint64 size);
internal String8 str8_zero();
internal String16 str16(uint16* str, uint64 size);
internal String16 str16_zero();
internal String8 str8_cstring(const char* cstring);
internal String16 str16_cstring(uint16* cstring);
internal String32 str32_cstring(uint32* cstring);
// =============================================================================
// String Matching
internal bool32 str8_match(String8 a, String8 b, StringMatchFlags flags);
#define str8_matchi(a, b) str8_match(a, b, StringMatchFlag_CaseInsensitive)
// =============================================================================
// String Formatting & Copying
internal String8 str8_copy(Arena* arena, String8 in);
internal String8 str8fv(Arena* arena, char* fmt, va_list args);
// =============================================================================
// Unicode String Encode/Decode
internal UnicodeDecode utf8_decode(uint8* str, uint64 max);
internal UnicodeDecode utf16_decode(uint16* str, uint64 max);
internal uint32 utf8_encode(uint8* str, uint32 codepoint);
internal uint32 utf16_encode(uint16* str, uint32 codepoint);
// =============================================================================
// Unicode String Conversions
internal String8 str8_from_16(Arena* arena, String16 in);
internal String16 str16_from_8(Arena* arena, String8 in);
+1
View File
@@ -0,0 +1 @@
// OS DEPEND see os/core/os_core.c
+11
View File
@@ -0,0 +1,11 @@
#pragma once
typedef struct SystemInfo SystemInfo;
struct SystemInfo
{
uint64 page_size;
uint64 large_page_size;
String8 machine_name;
};
internal SystemInfo* get_system_info();
+71
View File
@@ -0,0 +1,71 @@
// =============================================================================
// Globals
thread_static TCTX* tctx_thread_local;
// =============================================================================
// Thread Context Functions
// Thread Context allocation
internal TCTX* tctx_alloc()
{
#if BUILD_DEBUG
thread_static static char name[2][1024];
juliet_snprintf(name[0], sizeof(name[0]), "Scratch/0[TID:%u]", tid());
juliet_snprintf(name[1], sizeof(name[1]), "Scratch/1[TID:%u]", tid());
Arena* arena_0 = arena_alloc(.name = name[0]);
Arena* arena_1 = arena_alloc(.name = name[1]);
#else
Arena* arena_0 = arena_alloc();
Arena* arena_1 = arena_alloc();
#endif
TCTX* tctx = push_array(arena_0, TCTX, 1);
tctx->arenas[0] = arena_0;
tctx->arenas[1] = arena_1;
return tctx;
}
internal void tctx_release(TCTX* tctx)
{
arena_release(tctx->arenas[1]);
arena_release(tctx->arenas[0]);
}
internal void tctx_select(TCTX* tctx)
{
tctx_thread_local = tctx;
}
internal TCTX* tctx_selected()
{
return tctx_thread_local;
}
internal Arena* tctx_get_scratch(Arena** conflicts, uint64 count)
{
TCTX* tctx = tctx_selected();
Arena* result = 0;
Arena** arena_ptr = tctx->arenas;
for (uint64 i = 0; i < ArrayCount(tctx->arenas); ++i, ++arena_ptr)
{
Arena** conflict_ptr = conflicts;
bool32 has_conflict = 0;
for (uint64 j = 0; j < count; ++j, ++conflict_ptr)
{
if (*arena_ptr == *conflict_ptr)
{
has_conflict = 1;
break;
}
}
if (!has_conflict)
{
result = *arena_ptr;
break;
}
}
return result;
}
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
#define scratch_end(scratch) temp_end(scratch)
+29
View File
@@ -0,0 +1,29 @@
#pragma once
typedef struct TCTX TCTX;
struct TCTX
{
// Scratch arenas
Arena* arenas[2];
uint8 thread_name[32];
uint64 thread_name_size;
char* file_name;
uint64 line_number;
};
extern thread_static TCTX* tctx_thread_local;
// =============================================================================
// Thread Context Functions
// Thread Context allocation
internal TCTX* tctx_alloc();
internal void tctx_release(TCTX* tctx);
internal void tctx_select(TCTX* tctx);
internal TCTX* tctx_selected();
internal Arena* tctx_get_scratch(Arena** conflicts, uint64 count);
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
#define scratch_end(scratch) temp_end(scratch)
+18
View File
@@ -0,0 +1,18 @@
// =============================================================================
// Thread Info Helpers
internal void set_thread_name(String8 name)
{
set_platform_thread_name(name);
}
internal void set_thread_namef(char* fmt, ...)
{
TempArena scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = str8fv(scratch.arena, fmt, args);
set_thread_name(string);
va_end(args);
scratch_end(scratch);
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
// =============================================================================
// Synchronization primitives types
typedef struct RWMutex RWMutex;
struct RWMutex
{
uint64 handle[1];
};
// =============================================================================
// Thread Info Helpers
internal void set_thread_name(String8 name);
internal void set_thread_namef(char* fmt, ...);
// =============================================================================
// Thread Info
internal uint32 tid();
internal void set_platform_thread_name(String8 name);
// =============================================================================
// Synchronization primitive functions
// Read Write Mutexes functions
internal RWMutex rw_mutex_alloc();
internal void rw_mutex_release(RWMutex mutex);
internal void rw_mutex_take(RWMutex mutex, bool32 write_mode);
internal void rw_mutex_drop(RWMutex mutex, bool32 write_mode);
#define rw_mutex_take_r(m) rw_mutex_take((m), (0))
#define rw_mutex_take_w(m) rw_mutex_take((m), (1))
#define rw_mutex_drop_r(m) rw_mutex_drop((m), (0))
#define rw_mutex_drop_w(m) rw_mutex_drop((m), (1))
// Scope macros
#define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex))
#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex))
+4285
View File
File diff suppressed because it is too large. Load diff
+1
Vendored Submodule
+1
Submodule Juliet/external/xxHash added at c87183a77d.
+303
View File
@@ -0,0 +1,303 @@
internal void ja_init()
{
Arena* arena = arena_alloc();
ja_state = push_array(arena, JA_State, 1);
ja_state->arena = arena;
// Window cache
{
ja_state->window_request_gen_id = 1;
ja_state->window_state_slots_count = 64;
ja_state->window_state_slots = push_array(arena, JA_WindowStateSlot, ja_state->window_state_slots_count);
ja_state->first_window_state = ja_state->last_window_state = &ja_nil_window_state;
}
// Create window requests (2 for testing)
{
ja_window_request();
}
}
internal void ja_frame()
{
TempArena scratch = scratch_begin(0, 0);
ja_state->frame_depth += 1;
// =========================================================================
// Events from os
WM_EventList events = { 0 };
if (ja_state->frame_depth == 1)
{
bool32 wait = 0;
events = wm_get_events(scratch.arena, wait);
}
// =========================================================================
// Consume events
{
if (wm_key_press(&events, wm_window_zero(), 0, WM_Key_F1))
{
ja_window_request();
}
for (WM_Event *event = events.first, *next = 0; event != 0; event = next)
{
JA_WindowState* ws = ja_window_state_from_platform_handle(event->window);
bool32 take = 0;
if (event->kind == WM_EventKind_WindowClose)
{
if (ws != 0)
{
JA_WindowRequest* request = ja_window_request_from_id(ws->id);
AssertAlways(request != 0);
ja_window_close_request(request);
if (ja_state->window_request_count == 0)
{
ja_state->quit = 1;
}
}
else
{
ja_state->quit = 1;
}
take = 1;
}
if (take)
{
wm_eat_event(&events, event);
}
}
}
// Window management (open/render)
{
for EachNode(request, JA_WindowRequest, ja_state->window_request_first)
{
JA_WindowState* ws = ja_window_state_from_id(request->id);
// Will render here but for now just increase frame num
ws->frames_alive += 1;
}
}
// Window Garbage collect
{
for EachIndex(slot_idx, ja_state->window_state_slots_count)
{
for (JA_WindowState *ws = ja_state->window_state_slots[slot_idx].first, *next; ws != 0; ws = next)
{
next = ws->hash_next;
JA_WindowRequest* request = ja_window_request_from_id(ws->id);
if (request == 0 || ja_state->quit)
{
r_window_unequip(ws->plat_handle, ws->render_handle);
wm_window_close(ws->plat_handle);
arena_release(ws->arena);
DLL_remove_next_prev_zero(&ja_nil_window_state, ja_state->first_window_state,
ja_state->last_window_state, ws, order_next, order_previous);
DLL_remove_next_prev(ja_state->window_state_slots[slot_idx].first,
ja_state->window_state_slots[slot_idx].last, ws, hash_next, hash_previous);
SLL_stack_push_next(ja_state->free_window_state, ws, order_next);
}
}
}
}
// render frame
r_begin_frame();
for (JA_WindowState* w = ja_state->first_window_state; w != &ja_nil_window_state; w = w->order_next)
{
r_window_begin_frame(w->plat_handle, w->render_handle);
r_window_end_frame(w->plat_handle, w->render_handle);
}
r_end_frame();
// show window after first frame
if (ja_state->frame_depth == 1)
{
JA_IDList windows_to_show = { 0 };
for (JA_WindowState* ws = ja_state->first_window_state; ws != &ja_nil_window_state; ws = ws->order_next)
{
if (ws->frames_alive == 1)
{
ja_id_list_push(scratch.arena, &windows_to_show, ws->id);
}
}
for EachNode(node, JA_IDNode, windows_to_show.first)
{
JA_WindowState* ws = ja_window_state_from_id(node->val);
wm_window_first_paint(ws->plat_handle);
}
}
ja_state->frame_depth -= 1;
scratch_end(scratch);
}
internal void ja_shutdown()
{
arena_release(ja_state->arena);
}
// =============================================================================
// Id Functions
internal void ja_id_list_push(Arena* arena, JA_IDList* list, JA_ID id)
{
JA_IDNode* node = push_array(arena, JA_IDNode, 1);
SLL_queue_push(list->first, list->last, node);
list->count += 1;
node->val = id;
}
// =============================================================================
// Window Functions
internal JA_WindowState* ja_window_state_from_id(JA_ID id)
{
// scan existing windows
JA_WindowState* ws = &ja_nil_window_state;
if (id != 0 && id == ja_state->window_state_last_accessed_id && id == ja_state->window_state_last_accessed->id)
{
ws = ja_state->window_state_last_accessed;
}
else
{
uint64 hash = uint64_hash_from_string(str8_struct(&id));
uint64 slot_idx = hash % ja_state->window_state_slots_count;
JA_WindowStateSlot* slot = &ja_state->window_state_slots[slot_idx];
for (JA_WindowState* w = slot->first; w != 0; w = w->hash_next)
{
if (w->id == id)
{
ws = w;
break;
}
}
}
// allocate / open window if none found for this id
if (ws == &ja_nil_window_state)
{
ws = ja_state->free_window_state;
if (ws != 0)
{
SLL_stack_pop_next(ja_state->free_window_state, order_next);
}
else
{
ws = push_array_no_zero(ja_state->arena, JA_WindowState, 1);
}
MemoryZeroStruct(ws);
ws->id = id;
ws->arena = arena_alloc();
// hook up the window
uint64 hash = uint64_hash_from_string(str8_struct(&id));
uint64 slot_idx = hash % ja_state->window_state_slots_count;
JA_WindowStateSlot* slot = &ja_state->window_state_slots[slot_idx];
DLL_push_back_next_prev_zero(&ja_nil_window_state, ja_state->first_window_state, ja_state->last_window_state,
ws, order_next, order_previous);
DLL_push_back_next_prev(slot->first, slot->last, ws, hash_next, hash_previous);
}
if (ws != &ja_nil_window_state && wm_window_match(ws->plat_handle, wm_window_zero()))
{
TempArena scratch = scratch_begin(0, 0);
ws->frames_alive = 0;
// TODO: save fav monitor in config
WM_Monitor prim_m = wm_primary_monitor();
String8 prim_name = wm_name_from_monitor(scratch.arena, prim_m);
WM_Monitor fav_monitor = { 0 };
{
WM_MonitorArray monitors = wm_push_monitors_array(scratch.arena);
for EachIndex(idx, monitors.count)
{
String8 monitor_name = wm_name_from_monitor(scratch.arena, monitors.ptr[idx]);
if (str8_match(monitor_name, prim_name, StringMatchFlag_CaseInsensitive))
{
fav_monitor = monitors.ptr[idx];
break;
}
}
}
// TODO : put those in config, hardcoded for now
String8 title = str8_literal("Juliet");
ws->plat_handle = wm_window_open(rect2fp(50.f, 240.f, 1280.f, 720.f), WM_WindowFlag_UseDefaultPosition, title);
ws->render_handle = r_window_equip(ws->plat_handle);
WM_Monitor zero_monitor = { 0 };
if (!wm_monitor_match(zero_monitor, fav_monitor))
{
wm_window_set_monitor(ws->plat_handle, fav_monitor);
}
scratch_end(scratch);
}
ja_state->window_state_last_accessed_id = ws->id;
ja_state->window_state_last_accessed = ws;
return ws;
}
internal JA_WindowState* ja_window_state_from_platform_handle(WM_Window platform_handle)
{
JA_WindowState* ws = &ja_nil_window_state;
{
for (JA_WindowState* w_candidate = ja_state->first_window_state; w_candidate != &ja_nil_window_state;
w_candidate = w_candidate->order_next)
{
if (wm_window_match(w_candidate->plat_handle, platform_handle))
{
ws = w_candidate;
break;
}
}
}
return ws;
}
internal void ja_window_request()
{
JA_ID id = ja_state->window_request_gen_id++;
JA_WindowRequest* result = ja_state->free_window_request;
if (result != 0)
{
SLL_stack_pop(ja_state->free_window_request);
}
else
{
result = push_array_no_zero(ja_state->arena, JA_WindowRequest, 1);
}
result->id = id;
DLL_push_back(ja_state->window_request_first, ja_state->window_request_last, result);
ja_state->window_request_count += 1;
}
internal void ja_window_close_request(JA_WindowRequest* request)
{
DLL_remove(ja_state->window_request_first, ja_state->window_request_last, request);
SLL_stack_push(ja_state->free_window_request, request);
ja_state->window_request_count -= 1;
AssertAlways(ja_state->window_request_count >= 0);
}
internal JA_WindowRequest* ja_window_request_from_id(JA_ID id)
{
JA_WindowRequest* result = 0;
for EachNode(wr, JA_WindowRequest, ja_state->window_request_first)
{
if (wr->id == id)
{
result = wr;
break;
}
}
return result;
}
+108
View File
@@ -0,0 +1,108 @@
#pragma once
// =============================================================================
// Core Types
typedef uint64 JA_ID;
typedef struct JA_IDNode JA_IDNode;
struct JA_IDNode
{
JA_IDNode* next;
JA_ID val;
};
typedef struct JA_IDList JA_IDList;
struct JA_IDList
{
JA_IDNode* first;
JA_IDNode* last;
uint64 count;
};
// =============================================================================
// States Types
typedef struct JA_WindowRequest JA_WindowRequest;
struct JA_WindowRequest
{
JA_WindowRequest* next;
JA_WindowRequest* previous;
JA_ID id;
};
typedef struct JA_WindowState JA_WindowState;
struct JA_WindowState
{
// links and metadata
JA_WindowState* order_next;
JA_WindowState* order_previous;
JA_WindowState* hash_next;
JA_WindowState* hash_previous;
JA_ID id;
uint64 frames_alive;
// Info and handle
Arena* arena;
WM_Window plat_handle;
R_Handle render_handle;
};
typedef struct JA_WindowStateSlot JA_WindowStateSlot;
struct JA_WindowStateSlot
{
JA_WindowState* first;
JA_WindowState* last;
};
typedef struct JA_State JA_State;
struct JA_State
{
// Base
Arena* arena;
bool32 quit;
int32 frame_depth;
// Windows requests
JA_ID window_request_gen_id;
JA_WindowRequest* window_request_first;
JA_WindowRequest* window_request_last;
JA_WindowRequest* free_window_request;
uint64 window_request_count;
// Windows
JA_WindowState* free_window_state;
uint64 window_state_slots_count;
JA_WindowStateSlot* window_state_slots;
JA_WindowState* first_window_state;
JA_WindowState* last_window_state;
JA_ID window_state_last_accessed_id;
JA_WindowState* window_state_last_accessed;
};
// =============================================================================
// Globals
read_only global JA_WindowState ja_nil_window_state = { &ja_nil_window_state, &ja_nil_window_state };
global JA_State* ja_state = 0;
// =============================================================================
// Top level Functions
internal void ja_init();
internal void ja_frame();
internal void ja_shutdown();
// =============================================================================
// Id Functions
internal void ja_id_list_push(Arena* arena, JA_IDList* list, JA_ID id);
// =============================================================================
// Window Functions
internal JA_WindowState* ja_window_state_from_id(JA_ID id);
internal JA_WindowState* ja_window_state_from_platform_handle(WM_Window platform_handle);
internal void ja_window_request();
internal void ja_window_close_request(JA_WindowRequest* request);
internal JA_WindowRequest* ja_window_request_from_id(JA_ID id);
+1
View File
@@ -0,0 +1 @@
#include "julietapp_core.c"
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "julietapp_core.h"
+38
View File
@@ -0,0 +1,38 @@
// clang-format off
// ========================================================================= //
// Includes
// Headers
#include "core/core_inc.h"
#include "shell/shell_inc.h"
#include "window_manager/window_manager_inc.h"
#include "render/render_inc.h"
#include "julietapp/julietapp_inc.h"
// C
#include "core/core_inc.c"
#include "shell/shell_inc.c"
#include "window_manager/window_manager_inc.c"
#include "render/render_inc.c"
#include "julietapp/julietapp_inc.c"
// clang-format on
internal bool32 frame()
{
ja_frame();
return ja_state->quit;
}
internal void entry_point()
{
wm_init();
r_init();
ja_init();
for (bool32 quit = 0; !quit;)
{
quit = update();
}
ja_shutdown();
r_shutdown();
}
+392
View File
@@ -0,0 +1,392 @@
// TODO : Adapt stuff from D3D12GraphicsDevice.c specially all the shenanigans with dxgi factory and stuff
// TODO : Support more kind of format (HDR)
// =============================================================================
// Helpers
internal R_D3D12_Window* r_d3d12_window_from_handle(R_Handle handle)
{
R_D3D12_Window* window = (R_D3D12_Window*)handle.u64[0];
if (window == 0)
{
window = &r_d3d12_nil_window;
}
return window;
}
internal R_Handle r_d3d12_handle_from_window(R_D3D12_Window* window)
{
R_Handle handle = { 0 };
handle.u64[0] = (uint64)window;
return handle;
}
// =============================================================================
// Wait Function
internal void r_d3d12_wait()
{
r_d3d12_state->fence_value += 1;
ID3D12CommandQueue_Signal(r_d3d12_state->direct_command_queue, r_d3d12_state->fence, r_d3d12_state->fence_value);
if (ID3D12Fence_GetCompletedValue(r_d3d12_state->fence) < r_d3d12_state->fence_value)
{
ID3D12Fence_SetEventOnCompletion(r_d3d12_state->fence, r_d3d12_state->fence_value, r_d3d12_state->fence_event);
WaitForSingleObject(r_d3d12_state->fence_event, INFINITE);
}
}
// =============================================================================
// top level layer initialization
void r_init()
{
HRESULT error = 0;
Arena* arena = arena_alloc();
r_d3d12_state = push_array(arena, R_D3D12_State, 1);
r_d3d12_state->arena = arena;
r_d3d12_state->device_rw_mutex = rw_mutex_alloc();
// Create base device
D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_12_1;
UINT dxgi_flags = 0;
#if BUILD_DEBUG
ID3D12Debug1* debug_controller = 0;
if (SUCCEEDED(D3D12GetDebugInterface(&IID_ID3D12Debug1, (void**)&debug_controller)))
{
ID3D12Debug1_EnableDebugLayer(debug_controller);
ID3D12Debug1_SetEnableGPUBasedValidation(debug_controller, TRUE);
ID3D12Debug1_Release(debug_controller);
}
dxgi_flags |= DXGI_CREATE_FACTORY_DEBUG;
#endif
error = CreateDXGIFactory2(dxgi_flags, &IID_IDXGIFactory4, (void**)&r_d3d12_state->dxgi_factory);
if (FAILED(error))
{
char buffer[256] = { 0 };
juliet_snprintf(buffer, sizeof(buffer), "D3D12 DXGI factory creation failure (%lx). Process is terminating", error);
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
abort_self(1);
}
// dxgi setup (device and adapter)
IDXGIFactory6* factory6 = 0;
error = IDXGIFactory4_QueryInterface(r_d3d12_state->dxgi_factory, &IID_IDXGIFactory6, (void**)&factory6);
if (SUCCEEDED(error))
{
// Prioritize discrete GPU
error = IDXGIFactory6_EnumAdapterByGpuPreference(factory6, 0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
&IID_IDXGIAdapter1, (void**)&r_d3d12_state->dxgi_adapter);
IDXGIFactory6_Release(factory6);
}
else
{
// Pray device 0 is the discrete gpu
error = IDXGIFactory4_EnumAdapters1(r_d3d12_state->dxgi_factory, 0, &r_d3d12_state->dxgi_adapter);
}
error = D3D12CreateDevice((IUnknown*)r_d3d12_state->dxgi_adapter, feature_level, &IID_ID3D12Device4,
(void**)&r_d3d12_state->device);
// Try warp as hardware is no available
if (FAILED(error))
{
IDXGIAdapter1_Release(r_d3d12_state->dxgi_adapter);
error = IDXGIFactory4_EnumWarpAdapter(r_d3d12_state->dxgi_factory, &IID_IDXGIAdapter, (void**)&r_d3d12_state->dxgi_adapter);
if (SUCCEEDED(error))
{
error = D3D12CreateDevice((IUnknown*)r_d3d12_state->dxgi_adapter, feature_level, &IID_ID3D12Device4,
(void**)&r_d3d12_state->device);
}
}
if (FAILED(error))
{
char buffer[256] = { 0 };
juliet_snprintf(buffer, sizeof(buffer), "D3D12 device factory creation failure (%lx). Process is terminating", error);
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
abort_self(1);
}
// break on error
#if BUILD_DEBUG
ID3D12InfoQueue* info = 0;
error = ID3D12Device4_QueryInterface(r_d3d12_state->device, &IID_ID3D12InfoQueue, (void**)&info);
if (SUCCEEDED(error))
{
error = ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
error = ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
ID3D12InfoQueue_Release(info);
}
#endif
// Create basic graphics queue
D3D12_COMMAND_QUEUE_DESC queue_desc = { 0 };
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
error = ID3D12Device4_CreateCommandQueue(r_d3d12_state->device, &queue_desc, &IID_ID3D12CommandQueue,
(void**)&r_d3d12_state->direct_command_queue);
if (FAILED(error))
{
char buffer[256] = { 0 };
juliet_snprintf(buffer, sizeof(buffer), "D3D12 direct command queue creation failure (%lx). Process is terminating", error);
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
abort_self(1);
}
// Create command allocator and command list
for EachIndex(i, 2)
{
ID3D12Device4_CreateCommandAllocator(r_d3d12_state->device, D3D12_COMMAND_LIST_TYPE_DIRECT,
&IID_ID3D12CommandAllocator, (void**)&r_d3d12_state->command_allocators[i]);
}
ID3D12Device4_CreateCommandList1(r_d3d12_state->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_LIST_FLAG_NONE,
&IID_ID3D12GraphicsCommandList, (void**)&r_d3d12_state->command_list);
ID3D12Device4_CreateFence(r_d3d12_state->device, 0, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, (void**)&r_d3d12_state->fence);
r_d3d12_state->fence_event = CreateEventW(0, FALSE, FALSE, 0);
}
void r_shutdown()
{
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
r_d3d12_wait();
CloseHandle(r_d3d12_state->fence_event);
ID3D12Fence_Release(r_d3d12_state->fence);
for EachIndex(i,2)
{
ID3D12CommandAllocator_Release(r_d3d12_state->command_allocators[i]);
}
ID3D12CommandList_Release(r_d3d12_state->command_list);
ID3D12CommandQueue_Release(r_d3d12_state->direct_command_queue);
ID3D12Device4_Release(r_d3d12_state->device);
IDXGIAdapter1_Release(r_d3d12_state->dxgi_adapter);
IDXGIFactory4_Release(r_d3d12_state->dxgi_factory);
}
rw_mutex_release(r_d3d12_state->device_rw_mutex);
arena_release(r_d3d12_state->arena);
}
// =============================================================================
// window setup/teardown
R_Handle r_window_equip(WM_Window handle)
{
R_Handle result = { 0 };
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
R_D3D12_Window* window = r_d3d12_state->first_free_window;
if (window != 0)
{
SLL_stack_pop(r_d3d12_state->first_free_window);
MemoryZeroStruct(window);
}
else
{
window = push_array(r_d3d12_state->arena, R_D3D12_Window, 1);
}
HWND hwnd = { 0 };
{
W32_WM_Window* w32_layer_window = w32_wm_window_from_handle(handle);
hwnd = w32_wm_hwnd_from_window(w32_layer_window);
}
// Create swapchain
DXGI_SWAP_CHAIN_DESC1 swapchain_desc = { 0 };
swapchain_desc.Width = 0; // Use all window width
swapchain_desc.Height = 0; // Use all window height
swapchain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapchain_desc.Stereo = 0;
swapchain_desc.SampleDesc.Count = 1;
swapchain_desc.SampleDesc.Quality = 0;
swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapchain_desc.BufferCount = 2; // Double buffering
swapchain_desc.Scaling = DXGI_SCALING_NONE;
swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapchain_desc.Flags = 0;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapchain_fullscreen_desc = { 0 };
swapchain_fullscreen_desc.RefreshRate.Numerator = 0;
swapchain_fullscreen_desc.RefreshRate.Denominator = 0;
swapchain_fullscreen_desc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapchain_fullscreen_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapchain_fullscreen_desc.Windowed = TRUE;
IDXGISwapChain1* swapchain1 = 0;
HRESULT error = IDXGIFactory4_CreateSwapChainForHwnd(r_d3d12_state->dxgi_factory,
(IUnknown*)r_d3d12_state->direct_command_queue, hwnd,
&swapchain_desc, &swapchain_fullscreen_desc, 0, &swapchain1);
if (FAILED(error))
{
char buffer[256];
juliet_snprintf(buffer, sizeof(buffer), "DXGI swap chain creation failure (%lx). Process is terminating.", error);
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
abort_self(1);
}
IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void**)&window->swapchain);
IDXGISwapChain1_Release(swapchain1);
IDXGIFactory4_MakeWindowAssociation(r_d3d12_state->dxgi_factory, hwnd, DXGI_MWA_NO_ALT_ENTER);
// Create framebuffer and rtv for swapchain
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc = { 0 };
rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtv_heap_desc.NumDescriptors = 2;
rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ID3D12Device4_CreateDescriptorHeap(r_d3d12_state->device, &rtv_heap_desc, &IID_ID3D12DescriptorHeap,
(void**)&window->rtv_heap);
UINT rtv_stride = ID3D12Device4_GetDescriptorHandleIncrementSize(r_d3d12_state->device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = { 0 };
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(window->rtv_heap, &rtv_handle);
for (UINT i = 0; i < 2; ++i)
{
window->rtv_handles[i] = rtv_handle;
IDXGISwapChain3_GetBuffer(window->swapchain, i, &IID_ID3D12Resource, (void**)&window->framebuffer[i]);
ID3D12Device4_CreateRenderTargetView(r_d3d12_state->device, window->framebuffer[i], 0, window->rtv_handles[i]);
rtv_handle.ptr += rtv_stride;
}
// Save resolution in case of resize
Rect2f client_rect = wm_client_rect_from_window(handle);
Vector2i resolution = { (int32)(client_rect.x1 - client_rect.x0), (int32)(client_rect.y1 - client_rect.y0) };
window->last_resolution = resolution;
result = r_d3d12_handle_from_window(window);
}
return result;
}
void r_window_unequip(WM_Window handle, R_Handle handle_equip)
{
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
r_d3d12_wait();
R_D3D12_Window* window = r_d3d12_window_from_handle(handle_equip);
if (window != 0 && window != &r_d3d12_nil_window)
{
for EachIndex(i, 2)
{
ID3D12Resource_Release(window->framebuffer[i]);
}
ID3D12DescriptorHeap_Release(window->rtv_heap);
IDXGISwapChain1_Release(window->swapchain);
SLL_stack_push(r_d3d12_state->first_free_window, window);
}
}
}
// frame markers
void r_begin_frame()
{
// No-op
}
void r_end_frame()
{
// pouet
}
void r_window_begin_frame(WM_Window window, R_Handle window_equip)
{
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
R_D3D12_Window* r_window = r_d3d12_window_from_handle(window_equip);
// Get resolution
Rect2f client_rect = wm_client_rect_from_window(window);
Vector2i resolution = { (int32)(client_rect.x1 - client_rect.x0), (int32)(client_rect.y1 - client_rect.y0) };
// change resolution
if (resolution.x > 0 && resolution.y > 0 &&
(r_window->last_resolution.x != resolution.x || r_window->last_resolution.y != resolution.y))
{
r_window->last_resolution = resolution;
// resize swap chain
r_d3d12_wait();
for EachIndex(i,2)
{
if (r_window->framebuffer[i] != 0)
{
ID3D12Resource_Release(r_window->framebuffer[i]);
r_window->framebuffer[i] = 0;
}
}
IDXGISwapChain3_ResizeBuffers(r_window->swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
for EachIndex(i,2)
{
IDXGISwapChain3_GetBuffer(r_window->swapchain, i, &IID_ID3D12Resource, (void**)&r_window->framebuffer[i]);
ID3D12Device4_CreateRenderTargetView(r_d3d12_state->device, r_window->framebuffer[i], 0, r_window->rtv_handles[i]);
}
}
// Open the command list for that window that frame
// TODO : multiple command list as we have multiple windows
r_window->framebuffer_idx = IDXGISwapChain3_GetCurrentBackBufferIndex(r_window->swapchain);
ID3D12CommandAllocator* allocator = r_d3d12_state->command_allocators[r_window->framebuffer_idx];
ID3D12GraphicsCommandList* cmd_list = r_d3d12_state->command_list;
ID3D12CommandAllocator_Reset(allocator);
ID3D12GraphicsCommandList1_Reset(cmd_list, allocator, 0);
// Barrier to transition from Present (end of frame) to render target
D3D12_RESOURCE_BARRIER barrier = { 0 };
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = r_window->framebuffer[r_window->framebuffer_idx];
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
ID3D12GraphicsCommandList_ResourceBarrier(cmd_list, 1, &barrier);
// HARDCODED
// BLUE
float32 background[4] = { 0.1f, 0.2f, 0.8f, 1.0f };
ID3D12GraphicsCommandList_ClearRenderTargetView(cmd_list, r_window->rtv_handles[r_window->framebuffer_idx],
background, 0, 0);
}
}
void r_window_end_frame(WM_Window window, R_Handle window_equip)
{
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
R_D3D12_Window* r_window = r_d3d12_window_from_handle(window_equip);
ID3D12GraphicsCommandList* cmd_list = r_d3d12_state->command_list;
// Transition from render target to present
D3D12_RESOURCE_BARRIER barrier = { 0 };
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = r_window->framebuffer[r_window->framebuffer_idx];
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
ID3D12GraphicsCommandList_ResourceBarrier(cmd_list, 1, &barrier);
// Close command list and push it onto the command queue
ID3D12GraphicsCommandList_Close(cmd_list);
ID3D12CommandQueue_ExecuteCommandLists(r_d3d12_state->direct_command_queue, 1, (ID3D12CommandList**)&cmd_list);
IDXGISwapChain3_Present(r_window->swapchain, 1, 0);
// Fence until gpu finishes work
r_d3d12_wait();
}
}
+72
View File
@@ -0,0 +1,72 @@
#pragma once
#define COBJMACROS
#define CINTERFACE
#include <d3d12.h>
#include <dxgi1_6.h>
#undef COBJMACROS
#undef CINTERFACE
#pragma comment(lib, "d3d12")
#pragma comment(lib, "dxgi")
#pragma comment(lib, "dxguid")
// =============================================================================
// D3D12 States Types
typedef struct R_D3D12_Window R_D3D12_Window;
struct R_D3D12_Window
{
R_D3D12_Window* next;
// SwapChain and framebuffer
IDXGISwapChain3* swapchain;
ID3D12Resource* framebuffer[2];
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[2];
ID3D12DescriptorHeap* rtv_heap;
uint8 framebuffer_idx;
// last state
Vector2i last_resolution;
};
typedef struct R_D3D12_State R_D3D12_State;
struct R_D3D12_State
{
// states
Arena* arena;
R_D3D12_Window* first_free_window;
RWMutex device_rw_mutex;
// base d3d12 object
ID3D12Device4* device;
IDXGIFactory4* dxgi_factory;
IDXGIAdapter1* dxgi_adapter;
// Commands
ID3D12CommandQueue* direct_command_queue;
ID3D12CommandAllocator* command_allocators[2];
ID3D12GraphicsCommandList* command_list;
// Fence
ID3D12Fence* fence;
uint64 fence_value;
HANDLE fence_event;
};
// =============================================================================
// Globals
global R_D3D12_State* r_d3d12_state = 0;
global read_only R_D3D12_Window r_d3d12_nil_window = { &r_d3d12_nil_window };
// =============================================================================
// Helpers
internal R_D3D12_Window* r_d3d12_window_from_handle(R_Handle handle);
internal R_Handle r_d3d12_handle_from_window(R_D3D12_Window* window);
// =============================================================================
// Wait Function
internal void r_d3d12_wait();
View File
Whitespace-only changes.
+30
View File
@@ -0,0 +1,30 @@
#pragma once
// =============================================================================
// Handle type
typedef union R_Handle R_Handle;
union R_Handle
{
uint64 u64[1];
uint32 u32[2];
uint16 u16[4];
};
// =============================================================================
// top level layer initialization
void r_init();
void r_shutdown();
// =============================================================================
// window setup/teardown
R_Handle r_window_equip(WM_Window window);
void r_window_unequip(WM_Window window, R_Handle window_equip);
// frame markers
void r_begin_frame();
void r_end_frame();
void r_window_begin_frame(WM_Window window, R_Handle window_equip);
void r_window_end_frame(WM_Window window, R_Handle window_equip);
+5
View File
@@ -0,0 +1,5 @@
#include "render.c"
#if R_BACKEND == R_BACKEND_D3D12
# include "d3d12/render_d3d12.c"
#endif
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#define R_BACKEND_D3D12 0
#if !defined(R_BACKEND)
# define R_BACKEND R_BACKEND_D3D12
#endif
#include "render.h"
#if R_BACKEND == R_BACKEND_D3D12
# include "d3d12/render_d3d12.h"
#else
# error Renderer backend non specified
#endif
View File
Whitespace-only changes.
+6
View File
@@ -0,0 +1,6 @@
#pragma once
// =============================================================================
// Shell operations
internal void sh_message(bool32 error, String8 title, String8 message);
+7
View File
@@ -0,0 +1,7 @@
#include "shell.c"
#if OS_WINDOWS
# include "win32/shell/win32_shell.c"
#else
# error Shell functions not implemented for this operating system
#endif
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "shell.h"
#if OS_WINDOWS
# include "win32/shell/win32_shell.h"
#else
# error Shell functions not implemented for this operating system
#endif
+290
View File
@@ -0,0 +1,290 @@
typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDescription);
#define W32_KERNEL32_EXT_X_LIST X(SetThreadDescription)
#define X(x) global W32_##x##_Type* w32_##x##_func;
W32_KERNEL32_EXT_X_LIST
#undef X
// =============================================================================
// Entity Functions
internal W32_Entity* w32_entity_alloc(W32_EntityKind kind)
{
W32_Entity* result = 0;
EnterCriticalSection(&w32_state.entity_mutex);
{
result = w32_state.entity_free;
if (result)
{
SLL_stack_pop(w32_state.entity_free);
}
else
{
result = push_array_no_zero(w32_state.entity_arena, W32_Entity, 1);
}
MemoryZeroStruct(result);
}
LeaveCriticalSection(&w32_state.entity_mutex);
result->kind = kind;
return result;
}
internal void w32_entity_release(W32_Entity* entity)
{
entity->kind = W32_EntityKind_Null;
EnterCriticalSection(&w32_state.entity_mutex);
SLL_stack_push(w32_state.entity_free, entity);
LeaveCriticalSection(&w32_state.entity_mutex);
}
// =============================================================================
// Time functions
internal uint64 now_time_us()
{
uint64 result = 0;
LARGE_INTEGER large_int_counter;
if (QueryPerformanceCounter(&large_int_counter))
{
result = (large_int_counter.QuadPart * Million(1)) / w32_state.microsecond_resolution;
}
return result;
}
internal void sleep_ms(uint32 ms)
{
Sleep(ms);
}
// =============================================================================
// System
internal SystemInfo* get_system_info()
{
return &w32_state.system_info;
}
// =============================================================================
// Thread Info
internal uint32 tid()
{
DWORD id = GetCurrentThreadId();
return (uint32)id;
}
internal void set_platform_thread_name(String8 name)
{
TempArena scratch = scratch_begin(0, 0);
// Win10 and +
if (w32_SetThreadDescription_func)
{
String16 name16 = str16_from_8(scratch.arena, name);
HRESULT hr = w32_SetThreadDescription_func(GetCurrentThread(), (WCHAR*)name16.str);
}
// Old way by raising exception
{
String8 name_copy = str8_copy(scratch.arena, name);
#pragma pack(push, 8)
typedef struct THREADNAME_INFO THREADNAME_INFO;
struct THREADNAME_INFO
{
uint32 dwType; // Must be 0x1000.
char* szName; // Pointer to name (in user addr space).
uint32 dwThreadID; // Thread ID (-1=caller thread).
uint32 dwFlags; // Reserved for future use, must be zero.
};
#pragma pack(pop)
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = (char*)name_copy.str;
info.dwThreadID = tid();
info.dwFlags = 0;
#pragma warning(push)
#pragma warning(disable : 6320 6322)
__try
{
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void*), (const ULONG_PTR*)&info);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
#pragma warning(pop)
}
scratch_end(scratch);
}
// =============================================================================
// Synchronization primitive functions
// read write mutexes
internal RWMutex rw_mutex_alloc()
{
W32_Entity* entity = w32_entity_alloc(W32_EntityKind_RWMutex);
InitializeSRWLock(&entity->rw_mutex);
RWMutex result = { IntFromPtr(entity) };
return result;
}
internal void rw_mutex_release(RWMutex rw_mutex)
{
W32_Entity* entity = (W32_Entity*)PtrFromInt(rw_mutex.handle[0]);
w32_entity_release(entity);
}
internal void rw_mutex_take(RWMutex rw_mutex, bool32 write_mode)
{
W32_Entity* entity = (W32_Entity*)PtrFromInt(rw_mutex.handle[0]);
if (write_mode)
{
AcquireSRWLockExclusive(&entity->rw_mutex);
}
else
{
AcquireSRWLockShared(&entity->rw_mutex);
}
}
internal void rw_mutex_drop(RWMutex rw_mutex, bool32 write_mode)
{
W32_Entity* entity = (W32_Entity*)PtrFromInt(rw_mutex.handle[0]);
if (write_mode)
{
ReleaseSRWLockExclusive(&entity->rw_mutex);
}
else
{
ReleaseSRWLockShared(&entity->rw_mutex);
}
}
// =============================================================================
// Memory
internal void* reserve_memory(uint64 size)
{
void* result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
return result;
}
internal bool32 commit_memory(void* ptr, uint64 size)
{
bool32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0);
return result;
}
internal void* reserve_memory_large(uint64 size)
{
// Windows do not allow commiting large pages
void* result = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
return result;
}
internal bool32 commit_memory_large(void* ptr, uint64 size)
{
(void)ptr;
(void)size;
return 1;
}
internal void decommit_memory(void* ptr, uint64 size)
{
VirtualFree(ptr, size, MEM_DECOMMIT);
}
internal void release_memory(void* ptr, uint64 size)
{
(void)size; // Unused on windows
VirtualFree(ptr, 0, MEM_RELEASE);
}
// =============================================================================
// Aborting
internal void abort_self(uint64 exit_code)
{
ExitProcess((int)exit_code);
}
// =============================================================================
// Entry points
internal void w32_entry_point(int argc, WCHAR** wargv)
{
// Dynamically load some windows function that are not guaranteed in all sdk
{
#define X(x) w32_##x##_func = (void*)GetProcAddress(module, Stringify(x));
HMODULE module;
module = LoadLibraryA("kernek32.dll");
W32_KERNEL32_EXT_X_LIST
FreeLibrary(module);
#undef X
}
SYSTEM_INFO sys_info = { 0 };
GetSystemInfo(&sys_info);
{
w32_state.microsecond_resolution = 1;
LARGE_INTEGER large_int_resolution;
if (QueryPerformanceCounter(&large_int_resolution))
{
w32_state.microsecond_resolution = large_int_resolution.QuadPart;
}
}
SystemInfo* info = &w32_state.system_info;
info->page_size = sys_info.dwPageSize;
info->large_page_size = GetLargePageMinimum();
Arena* args_arena = arena_alloc(.reserve_size = MB(1), .commit_size = KB(32));
char** argv = push_array(args_arena, char*, argc);
for (int i = 0; i < argc; ++i)
{
String16 arg16 = str16_cstring((uint16*)wargv[i]);
String8 arg8 = str8_from_16(args_arena, arg16);
argv[i] = (char*)arg8.str;
}
// Thread context
TCTX* tctx = tctx_alloc();
tctx_select(tctx);
// setup w32 state
Arena* arena = arena_alloc();
{
w32_state.arena = arena;
{
SystemInfo* info = &w32_state.system_info;
DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
uint8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
if (GetComputerNameA((char*)buffer, &size))
{
info->machine_name = str8_copy(arena, str8(buffer, size));
}
}
}
// setup entity storage
InitializeCriticalSection(&w32_state.entity_mutex);
w32_state.entity_arena = arena_alloc();
main_thread_core_entry_point(argc, argv);
tctx_release(tctx);
}
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
{
(void)hInstance;
(void)hPrevInstance;
(void)lpCmdLine;
(void)nShowCmd;
w32_entry_point(__argc, __wargv);
return 0;
}
+57
View File
@@ -0,0 +1,57 @@
#pragma once
// clang-format off
#include <windows.h>
#include <windowsx.h>
#pragma comment(lib, "user32")
#pragma comment(lib, "shell32")
// clang-format on
// =============================================================================
// Entity Types
typedef enum W32_EntityKind
{
W32_EntityKind_Null,
W32_EntityKind_RWMutex,
} W32_EntityKind;
typedef struct W32_Entity W32_Entity;
struct W32_Entity
{
W32_Entity* next;
W32_EntityKind kind;
union
{
SRWLOCK rw_mutex;
};
};
// =============================================================================
// W32 state types
typedef struct W32_State W32_State;
struct W32_State
{
Arena* arena;
// info
SystemInfo system_info;
uint64 microsecond_resolution;
// entities
CRITICAL_SECTION entity_mutex;
Arena* entity_arena;
W32_Entity* entity_free;
};
// =============================================================================
// W32 globals
global W32_State w32_state = { 0 };
// =============================================================================
// Entity Functions
internal W32_Entity* w32_entity_alloc(W32_EntityKind kind);
internal void w32_entity_release(W32_Entity* entity);
+11
View File
@@ -0,0 +1,11 @@
// =============================================================================
// Shell operations
internal void sh_message(bool32 error, String8 title, String8 message)
{
TempArena scratch = scratch_begin(0, 0);
String16 title16 = str16_from_8(scratch.arena, title);
String16 message16 = str16_from_8(scratch.arena, message);
MessageBoxW(0, (WCHAR*)message16.str, (WCHAR*)title16.str, MB_OK | (!!error * MB_ICONERROR));
scratch_end(scratch);
}
+1
View File
@@ -0,0 +1 @@
#pragma once
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,97 @@
#pragma once
// clang-format off
#include <dwmapi.h>
#include <shellscalingapi.h>
#pragma comment(lib, "dwmapi")
// clang-format on
// =============================================================================
// Windows Type
typedef struct W32_WM_Window W32_WM_Window;
struct W32_WM_Window
{
W32_WM_Window* next;
W32_WM_Window* previous;
HWND hwnd;
HDC hdc;
WINDOWPLACEMENT last_window_placement;
float32 dpi;
bool32 first_paint_done;
bool32 maximized;
bool32 custom_border;
float32 custom_border_title_thickness;
float32 custom_border_edge_thickness;
bool32 custom_border_composition_enabled;
Arena* paint_arena;
};
// =============================================================================
// Monitor gathering bundle
typedef struct W32_WM_MonitorGatherNode W32_WM_MonitorGatherNode;
struct W32_WM_MonitorGatherNode
{
W32_WM_MonitorGatherNode* next;
WM_Monitor handle;
};
typedef struct W32_WM_MonitorGatherBundle W32_WM_MonitorGatherBundle;
struct W32_WM_MonitorGatherBundle
{
Arena* arena;
W32_WM_MonitorGatherNode* first_monitor;
W32_WM_MonitorGatherNode* last_monitor;
uint64 monitor_count;
};
// =============================================================================
// Windows Global State
typedef struct W32_WM_State W32_WM_State;
struct W32_WM_State
{
Arena* arena;
uint32 gfx_thread_tid;
HINSTANCE hIstance;
HCURSOR hCursor;
WM_SystemInfo gfx_info;
W32_WM_Window* first_window;
W32_WM_Window* last_window;
W32_WM_Window* free_window;
WM_Key key_from_vkey_table[256];
};
// =============================================================================
// Globals
global W32_WM_State* w32_wm_state = 0;
global WM_EventList w32_wm_event_list = { 0 };
global Arena* w32_wm_event_arena = 0;
global bool32 w32_wm_resizing = 0;
global bool32 w32_wm_new_window_custom_border = 0;
// =============================================================================
// Helpers
internal Rect2f w32_wm_rect2f_from_rect(RECT rect);
// =============================================================================
// Windows
internal WM_Window w32_wm_handle_from_window(W32_WM_Window* window);
internal W32_WM_Window* w32_wm_window_from_handle(WM_Window handle);
internal W32_WM_Window* w32_wm_window_from_hwnd(HWND hwnd);
internal HWND w32_wm_hwnd_from_window(W32_WM_Window* window);
internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd);
internal void w32_wm_window_release(W32_WM_Window* window);
internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window);
internal WM_Key w32_wm_os_key_from_vkey(WPARAM vKey);
internal WPARAM w32_wm_vkey_from_os_key(WM_Key key);
internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// =============================================================================
// Monitors
internal BOOL w32_wm_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr);
+71
View File
@@ -0,0 +1,71 @@
// =============================================================================
// Handle type helpers
internal WM_Window wm_window_zero()
{
WM_Window result = { 0 };
return result;
}
internal bool32 wm_window_match(WM_Window a, WM_Window b)
{
bool32 result = MemoryMatchStruct(&a, &b);
return result;
}
internal bool32 wm_monitor_match(WM_Monitor a, WM_Monitor b)
{
bool32 result = MemoryMatchStruct(&a, &b);
return result;
}
// =============================================================================
// Event Functions
internal void wm_eat_event(WM_EventList* events, WM_Event* event)
{
DLL_remove(events->first, events->last, event);
events->count -= 1;
}
internal bool32 wm_key_press(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key)
{
bool32 result = 0;
for (WM_Event* event = events->first; event != 0; event = event->next)
{
if ((wm_window_match(event->window, window) || wm_window_match(window, wm_window_zero())) &&
event->kind == WM_EventKind_Press && event->key == key && event->modifiers == modifiers)
{
result = 1;
wm_eat_event(events, event);
break;
}
}
return result;
}
internal bool32 wm_key_release(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key)
{
bool32 result = 0;
for (WM_Event* event = events->first; event != 0; event = event->next)
{
if ((wm_window_match(event->window, window) || wm_window_match(window, wm_window_zero())) &&
event->kind == WM_EventKind_Release && event->key == key && event->modifiers == modifiers)
{
result = 1;
wm_eat_event(events, event);
break;
}
}
return result;
}
internal WM_Event* wm_event_list_push_new(Arena* arena, WM_EventList* events, WM_EventKind kind)
{
WM_Event* evt = push_array(arena, WM_Event, 1);
DLL_push_back(events->first, events->last, evt);
events->count += 1;
evt->timestamp_us = now_time_us();
evt->kind = kind;
return evt;
}
+162
View File
@@ -0,0 +1,162 @@
#pragma once
// =============================================================================
// System Types
typedef struct WM_SystemInfo WM_SystemInfo;
struct WM_SystemInfo
{
float32 double_click_time;
float32 caret_blink_time;
float32 default_refresh_rate;
};
// =============================================================================
// Window Types
typedef uint32 WM_WindowFlags;
enum
{
WM_WindowFlag_CustomBorder = (1 << 0),
WM_WindowFlag_UseDefaultPosition = (1 << 1),
};
typedef struct WM_Window WM_Window;
struct WM_Window
{
uint64 handle[1];
};
// =============================================================================
// Monitor Types
typedef struct WM_Monitor WM_Monitor;
struct WM_Monitor
{
uint64 handle[1];
};
typedef struct WM_MonitorArray WM_MonitorArray;
struct WM_MonitorArray
{
WM_Monitor* ptr;
uint64 count;
};
#include "window_manager_key.h"
// =============================================================================
// Curosr Types
typedef enum WM_Cursor
{
WM_Cursor_Pointer,
WM_Cursor_COUNT
} WM_Cursor;
// =============================================================================
// Event Types
typedef enum WM_EventKind
{
WM_EventKind_Null,
WM_EventKind_Press,
WM_EventKind_Release,
WM_EventKind_MouseMove,
WM_EventKind_Text,
WM_EventKind_WindowClose,
WM_EventKind_COUNT
} WM_EventKind;
typedef uint32 WM_Modifiers;
enum
{
WM_Modifier_Ctrl = (1 << 0),
WM_Modifier_Shift = (1 << 1),
WM_Modifier_Alt = (1 << 2),
};
typedef struct WM_Event WM_Event;
struct WM_Event
{
WM_Event* next;
WM_Event* previous;
uint64 timestamp_us;
WM_Window window;
WM_EventKind kind;
WM_Modifiers modifiers;
WM_Key key;
bool32 is_repeat;
bool32 right_sided;
uint32 character;
uint32 repeat_count;
};
typedef struct WM_EventList WM_EventList;
struct WM_EventList
{
uint64 count;
WM_Event* first;
WM_Event* last;
};
// =============================================================================
// Application defined frame hook
internal bool32 frame();
// =============================================================================
// Handle type helpers
internal WM_Window wm_window_zero();
internal bool32 wm_window_match(WM_Window a, WM_Window b);
internal bool32 wm_monitor_match(WM_Monitor a, WM_Monitor b);
// =============================================================================
// Event Functions
internal void wm_eat_event(WM_EventList* events, WM_Event* event);
internal bool32 wm_key_press(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key);
internal bool32 wm_key_release(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key);
internal WM_Event* wm_event_list_push_new(Arena* arena, WM_EventList* events, WM_EventKind kind);
// =============================================================================
// Windows Management Functions
// =============================================================================
// Main Initialization API
internal void wm_init();
// =============================================================================
// Windows
internal WM_Window wm_widow_open(Rect2f rect, WM_WindowFlags flags, String8 title);
internal void wm_window_close(WM_Window handle);
internal void wm_window_first_paint(WM_Window window_handle);
internal void wm_window_set_monitor(WM_Window window, WM_Monitor monitor);
internal Rect2f wm_rect_from_window(WM_Window window_handle);
internal Rect2f wm_client_rect_from_window(WM_Window window);
// =============================================================================
// Monitors
internal WM_MonitorArray wm_push_monitors_array(Arena* arena);
internal WM_Monitor wm_primary_monitor();
internal WM_Monitor wm_monitor_from_window(WM_Window window);
internal String8 wm_name_from_monitor(Arena* arena, WM_Monitor monitor);
internal Vector2f wm_dim_from_monitor(WM_Monitor monitor);
internal float32 wm_dpi_from_monitor(WM_Monitor monitor);
// =============================================================================
// Events
internal void wm_send_wakeup_event();
internal WM_EventList wm_get_events(Arena* arena, bool32 wait);
internal WM_Modifiers wm_get_modifiers();
internal bool32 wm_key_is_down(WM_Key key);
internal Vector2f wm_mouse_from_window(WM_Window window);
// =============================================================================
// Cursors
internal void wm_set_cursor(WM_Cursor cursor);
@@ -0,0 +1,7 @@
#include "window_manager.c"
#if OS_WINDOWS
# include "win32/window_manager/window_manager.c"
#else
# error No window manager for this operating system
#endif
@@ -0,0 +1,10 @@
#pragma once
#include "window_manager.h"
#include "window_manager_key.h"
#if OS_WINDOWS
# include "win32/window_manager/window_manager.h"
#else
# error No Window manager for this operating system
#endif
+149
View File
@@ -0,0 +1,149 @@
#pragma once
typedef enum WM_Key
{
WM_Key_Null,
WM_Key_Esc,
WM_Key_F1,
WM_Key_F2,
WM_Key_F3,
WM_Key_F4,
WM_Key_F5,
WM_Key_F6,
WM_Key_F7,
WM_Key_F8,
WM_Key_F9,
WM_Key_F10,
WM_Key_F11,
WM_Key_F12,
WM_Key_F13,
WM_Key_F14,
WM_Key_F15,
WM_Key_F16,
WM_Key_F17,
WM_Key_F18,
WM_Key_F19,
WM_Key_F20,
WM_Key_F21,
WM_Key_F22,
WM_Key_F23,
WM_Key_F24,
WM_Key_Tick,
WM_Key_0,
WM_Key_1,
WM_Key_2,
WM_Key_3,
WM_Key_4,
WM_Key_5,
WM_Key_6,
WM_Key_7,
WM_Key_8,
WM_Key_9,
WM_Key_Minus,
WM_Key_Equal,
WM_Key_Backspace,
WM_Key_Tab,
WM_Key_Q,
WM_Key_W,
WM_Key_E,
WM_Key_R,
WM_Key_T,
WM_Key_Y,
WM_Key_U,
WM_Key_I,
WM_Key_O,
WM_Key_P,
WM_Key_LeftBracket,
WM_Key_RightBracket,
WM_Key_BackSlash,
WM_Key_CapsLock,
WM_Key_A,
WM_Key_S,
WM_Key_D,
WM_Key_F,
WM_Key_G,
WM_Key_H,
WM_Key_J,
WM_Key_K,
WM_Key_L,
WM_Key_Semicolon,
WM_Key_Quote,
WM_Key_Return,
WM_Key_Shift,
WM_Key_Z,
WM_Key_X,
WM_Key_C,
WM_Key_V,
WM_Key_B,
WM_Key_N,
WM_Key_M,
WM_Key_Comma,
WM_Key_Period,
WM_Key_Slash,
WM_Key_Ctrl,
WM_Key_Alt,
WM_Key_Space,
WM_Key_Menu,
WM_Key_ScrollLock,
WM_Key_Pause,
WM_Key_Insert,
WM_Key_Home,
WM_Key_PageUp,
WM_Key_Delete,
WM_Key_End,
WM_Key_PageDown,
WM_Key_Up,
WM_Key_Left,
WM_Key_Down,
WM_Key_Right,
WM_Key_Ex0,
WM_Key_Ex1,
WM_Key_Ex2,
WM_Key_Ex3,
WM_Key_Ex4,
WM_Key_Ex5,
WM_Key_Ex6,
WM_Key_Ex7,
WM_Key_Ex8,
WM_Key_Ex9,
WM_Key_Ex10,
WM_Key_Ex11,
WM_Key_Ex12,
WM_Key_Ex13,
WM_Key_Ex14,
WM_Key_Ex15,
WM_Key_Ex16,
WM_Key_Ex17,
WM_Key_Ex18,
WM_Key_Ex19,
WM_Key_Ex20,
WM_Key_Ex21,
WM_Key_Ex22,
WM_Key_Ex23,
WM_Key_Ex24,
WM_Key_Ex25,
WM_Key_Ex26,
WM_Key_Ex27,
WM_Key_Ex28,
WM_Key_Ex29,
WM_Key_NumLock,
WM_Key_NumSlash,
WM_Key_NumStar,
WM_Key_NumMinus,
WM_Key_NumPlus,
WM_Key_NumPeriod,
WM_Key_Num0,
WM_Key_Num1,
WM_Key_Num2,
WM_Key_Num3,
WM_Key_Num4,
WM_Key_Num5,
WM_Key_Num6,
WM_Key_Num7,
WM_Key_Num8,
WM_Key_Num9,
WM_Key_LeftMouseButton,
WM_Key_MiddleMouseButton,
WM_Key_RightMouseButton,
WM_Key_COUNT,
} WM_Key;
+3
View File
@@ -0,0 +1,3 @@
@echo off
call "%~dp0..\new_build.bat" %*
exit /b %ERRORLEVEL%
+3
View File
@@ -0,0 +1,3 @@
@echo off
call "%~dp0..\new_generate.bat" %*
exit /b %ERRORLEVEL%
+125
View File
@@ -0,0 +1,125 @@
@echo off
setlocal enabledelayedexpansion
cd /D "%~dp0"
:: --- Usage Notes -------------------------------------------------------------
::
:: Central build script for Juliet modular architecture.
:: Takes alphanumeric arguments to control target, compiler, and build configuration.
::
:: Examples:
:: new_build
:: new_build julietapp
:: new_build julietapp clang
:: new_build julietapp release
:: new_build julietapp msvc debug asan
:: new_build clean
::
:: --- Unpack Arguments -------------------------------------------------------
for %%a in (%*) do set "%%~a=1"
if "%clean%"=="1" (
if exist build (
echo [clean] Removing build directory...
rmdir /s /q build
)
exit /b 0
)
:: --- Compiler Selection & Auto-Detection -------------------------------------
if not "%msvc%"=="1" if not "%clang%"=="1" set clang=1
if "%msvc%"=="1" (
where cl.exe >nul 2>nul
if errorlevel 1 (
if exist "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" (
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul 2>&1
)
)
)
if not "%release%"=="1" set debug=1
if "%debug%"=="1" set release=0 && echo [debug mode]
if "%release%"=="1" set debug=0 && echo [release mode]
if "%clang%"=="1" set msvc=0 && echo [clang compile]
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
:: Default target: julietapp
if "%~1"=="" echo [default mode, assuming `julietapp` build] && set julietapp=1
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `julietapp` build] && set julietapp=1
if "%~1"=="debug" if "%~2"=="" echo [default mode, assuming `julietapp` build] && set julietapp=1
if "%~1"=="clang" if "%~2"=="" echo [default mode, assuming `julietapp` build] && set julietapp=1
if "%~1"=="msvc" if "%~2"=="" echo [default mode, assuming `julietapp` build] && set julietapp=1
:: --- Unpack Command Line Build Arguments ------------------------------------
set auto_compile_flags=
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
if "%ubsan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=undefined && echo [ubsan enabled]
:: --- Natvis Options ---------------------------------------------------------
set natvis_flags=
if exist "%~dp0Natvis\Juliet.natvis" (
if "%msvc%"=="1" set natvis_flags=%natvis_flags% /NATVIS:"%~dp0Natvis\Juliet.natvis"
if "%clang%"=="1" set natvis_flags=%natvis_flags% -Xlinker /NATVIS:"%~dp0Natvis\Juliet.natvis"
)
if exist "%~dp0Natvis\String.natvis" (
if "%msvc%"=="1" set natvis_flags=%natvis_flags% /NATVIS:"%~dp0Natvis\String.natvis"
if "%clang%"=="1" set natvis_flags=%natvis_flags% -Xlinker /NATVIS:"%~dp0Natvis\String.natvis"
)
:: --- Compile/Link Line Definitions ------------------------------------------
set cl_common= /I..\Juliet\ /nologo /FC /Z7 /Zc:preprocessor /utf-8
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /DEBUG %natvis_flags% /opt:ref /opt:icf
set cl_out= /out:
set cl_obj_out= /Fo:
set cl_linker=
set clang_common= -mcx16 -I..\Juliet\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /DEBUG %natvis_flags% -Xlinker /opt:ref -Xlinker /opt:noicf
set clang_out= -o
set clang_obj_out= -o
set clang_linker= -Xlinker
:: --- Per-Build Settings -----------------------------------------------------
if "%msvc%"=="1" set linker=%cl_linker%
if "%clang%"=="1" set linker=%clang_linker%
if "%msvc%"=="1" set only_compile=/c
if "%clang%"=="1" set only_compile=-c
if "%msvc%"=="1" set link_dll=/link /DLL
if "%clang%"=="1" set link_dll=-Xlinker -DLL
:: --- Choose Compile/Link Lines ----------------------------------------------
if "%msvc%"=="1" set compile_debug=%cl_debug%
if "%msvc%"=="1" set compile_release=%cl_release%
if "%msvc%"=="1" set compile_link=%cl_link%
if "%msvc%"=="1" set out=%cl_out%
if "%msvc%"=="1" set obj_out=%cl_obj_out%
if "%clang%"=="1" set compile_debug=%clang_debug%
if "%clang%"=="1" set compile_release=%clang_release%
if "%clang%"=="1" set compile_link=%clang_link%
if "%clang%"=="1" set out=%clang_out%
if "%clang%"=="1" set obj_out=%clang_obj_out%
if "%debug%"=="1" set compile=%compile_debug%
if "%release%"=="1" set compile=%compile_release%
:: --- Prep Directories -------------------------------------------------------
if not exist build mkdir build
:: --- Build Targets (@build_targets) -----------------------------------------
pushd build
if "%julietapp%"=="1" set didbuild=1 && %compile% ..\Juliet\julietapp\julietapp_main.c %compile_link% %out%julietapp.exe || exit /b 1
popd
:: --- Warn On No Builds ------------------------------------------------------
if "%didbuild%"=="" (
echo [WARNING] no valid build target specified; must use build target names like `new_build julietapp`.
exit /b 1
)
echo [build success]
exit /b 0
+66
View File
@@ -0,0 +1,66 @@
@echo off
setlocal enabledelayedexpansion
cd /D "%~dp0"
:: --- Usage Notes -------------------------------------------------------------
::
:: Generates clangd compile_commands.json and Visual Studio project/solution files.
::
:: Examples:
:: new_generate (generates compile_commands.json and VS files)
:: new_generate compile_commands (generates only compile_commands.json)
:: new_generate vs (generates only vs/new_Juliet.sln and projects)
::
set GEN_TOOL=misc\new_project_gen.exe
set GEN_SRC=tools\new_project_gen.c
:: Auto-detect compiler for building the generator tool
set COMPILER=
where clang.exe >nul 2>nul
if not errorlevel 1 (
set COMPILER=clang
) else (
where cl.exe >nul 2>nul
if not errorlevel 1 (
set COMPILER=cl
) else (
if exist "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" (
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul 2>&1
)
where cl.exe >nul 2>nul
if not errorlevel 1 (
set COMPILER=cl
)
)
)
if "%COMPILER%"=="" (
echo [ERROR] Neither clang nor cl found in PATH.
exit /b 1
)
:: Recompile generator tool if needed
set RECOMPILE=0
if not exist "%GEN_TOOL%" set RECOMPILE=1
if exist "Intermediate\new_project_gen.stamp" (
set /p CACHED_STAMP=<"Intermediate\new_project_gen.stamp"
for %%I in ("%GEN_SRC%") do (
if "%%~tI_%%~zI" neq "!CACHED_STAMP!" set RECOMPILE=1
)
) else set RECOMPILE=1
if "!RECOMPILE!"=="1" (
echo [GENERATE] Compiling %GEN_SRC% -^> %GEN_TOOL%...
if not exist misc mkdir misc
if not exist Intermediate mkdir Intermediate
if "%COMPILER%"=="clang" (
call clang -O2 -Wall -Wextra -Werror "%GEN_SRC%" -o "%GEN_TOOL%" || exit /b 1
) else (
call cl /nologo /O2 /W4 /WX "%GEN_SRC%" /Fe"%GEN_TOOL%" || exit /b 1
)
for %%I in ("%GEN_SRC%") do (echo %%~tI_%%~zI)>"Intermediate\new_project_gen.stamp"
)
"%GEN_TOOL%" %*
exit /b %ERRORLEVEL%
+41
View File
@@ -0,0 +1,41 @@
# Modular Architecture & Tooling TODO
This document tracks upcoming tasks for Juliet's modular architecture (`core`, `appbin`, future `render`, `ui`, etc.) and the build/LSP generation tooling.
---
## 1. Tooling & Project Generator (`tools/new_project_gen.c`)
- [x] **Dynamic Preceding Include Parser**:
- Implemented dynamic parser `get_preceding_includes_from_inc_h(layer_name, target_file_path)` in `tools/new_project_gen.c`.
- Reads `<layer>_inc.h` line-by-line and collects all `#include "..."` statements that appear strictly **above** the target header being analyzed.
- Automatically injects those preceding includes via `/FI` so that any header opened in Neovim/clangd has its exact required preprocessor context with zero hardcoding.
- [x] **Multi-Layer Cascade**:
- Deduces layer hierarchy from `appbin_main.c` and supplies lower layer includes (`/FIcore/core_inc.h`, etc.) to upper layers automatically.
---
## 2. Core Module Implementation (`Juliet/core/`)
- [ ] **Fill `core.c`**:
- Implement base core routines (OS helpers, string utilities, arena allocation implementations, math helpers).
- [ ] **Win32 Core Cleanup**:
- Fix argument passing in `win32_core.c:55` (`main_thread_core_entry_point(argc, &argv)` vs `char** argv`).
- Implement proper command line argument parsing into `String8`/`String16` arenas.
- [ ] **Unit Tests for Core**:
- Create standalone test executable or test entry point validating arena allocation, commit/decommit, and string routines.
---
## 3. Future Layers
- [ ] **Render Layer (`Juliet/render/`)**:
- Create `render_inc.h`, `render_inc.c`.
- Implement D3D12 device initialization, command queues, swap chain, and memory allocators.
- Add `#include "render/render_inc.h"` and `#include "render/render_inc.c"` to `appbin_main.c`.
- [ ] **UI Layer (`Juliet/ui/`)**:
- Create `ui_inc.h`, `ui_inc.c`.
- Implement UI hierarchy, layout, text rendering, and input handling.
---
## 4. Build System & LSP Maintenance
- [ ] Run `new_generate.bat` after adding new layers or changing layer include order in `appbin_main.c`.
- [ ] Keep `new_build.bat` as the single-pass unity compiler command for lightning-fast build times.
File diff suppressed because it is too large. Load diff