Compare commits

...
10 Commits
Author SHA1 Message Date
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
60 changed files with 4193 additions and 3 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. global/static variables: lower_snake_case prefixed. Exemple: g_my_global.
const variables: lower_snake_case prefixed. Exemple: k_my_const_var. const variables: lower_snake_case prefixed. Exemple: k_my_const_var.
Defines and Macros: ALL_CAPS_SNAKE. Exemple: MY_MACRO 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.
+2
View File
@@ -44,6 +44,7 @@ IncludeCategories:
IncludeIsMainRegex: '([-_](test|unittest))?$' IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentAccessModifiers: false IndentAccessModifiers: false
IndentCaseBlocks: true IndentCaseBlocks: true
IndentPPDirectives: AfterHash
IndentWidth: 4 IndentWidth: 4
InsertNewlineAtEOF: true InsertNewlineAtEOF: true
MacroBlockBegin: '' MacroBlockBegin: ''
@@ -57,6 +58,7 @@ PenaltyBreakString: 100
PenaltyExcessCharacter: 1 PenaltyExcessCharacter: 1
PenaltyReturnTypeOnItsOwnLine: 1000 PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left PointerAlignment: Left
PPIndentWidth: 1
SortIncludes: CaseInsensitive SortIncludes: CaseInsensitive
SpacesInAngles: Never SpacesInAngles: Never
SpacesInContainerLiterals: false SpacesInContainerLiterals: false
+14 -3
View File
@@ -3,6 +3,10 @@ CompileFlags:
- --driver-mode=cl - --driver-mode=cl
- -Wno-unknown-pragmas - -Wno-unknown-pragmas
- -Wno-unused-command-line-argument - -Wno-unused-command-line-argument
- -Wno-unused-function
- -Wno-undefined-internal
- -Wno-initializer-overrides
- /IJuliet
Remove: Remove:
- /Yu* - /Yu*
- /Yc* - /Yc*
@@ -16,8 +20,15 @@ CompileFlags:
Diagnostics: Diagnostics:
UnusedIncludes: None UnusedIncludes: None
Suppress:
- unused-function
- undefined-internal
- initializer-overrides
InlayHints: InlayHints:
Enabled: Yes Enabled: true
ParameterNames: Yes ParameterNames: true
DeducedTypes: Yes DeducedTypes: true
Designators: true
BlockEnd: false
TypeNameLimit: 24
+1
View File
@@ -9,6 +9,7 @@
# Binaries # Binaries
[Bb]in/ [Bb]in/
[Bb]uild/
[Ll]ib/ [Ll]ib/
.idea/ .idea/
.vs/ .vs/
+6
View File
@@ -1,3 +1,9 @@
[submodule "External/Imgui"] [submodule "External/Imgui"]
path = External/Imgui path = External/Imgui
url = https://github.com/ocornut/imgui.git url = https://github.com/ocornut/imgui.git
[submodule "Juliet/external/stb"]
path = Juliet/external/stb
url = https://github.com/nothings/stb.git
[submodule "Juliet/external/xxHash"]
path = Juliet/external/xxHash
url = https://github.com/Cyan4973/xxHash.git
+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/stb_sprintf.h"
+269
View File
@@ -0,0 +1,269 @@
#pragma once
#include <stdint.h>
// =============================================================================
// Third party includes
#define STB_SPRINTF_DECORATE(name) juliet_##name
#define STB_SPRINTF_STATIC
#include "external/stb/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 EachIndex(it, count) (uint64 it = 0; it < (count); ++it)
// =============================================================================
// Memory Helpers
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
#define MemorySet(dst, src, size) memset((dst), (src), (size))
#define MemoryZero(ptr, size) memset((ptr), 0, (size))
#define MemoryZeroStruct(s) MemoryZero((s), sizeof(*(s)))
// =============================================================================
// 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)
// clang-format off
#define DLL_insert_NPZ(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))))
// clang-format on
#define DLL_push_back_NPZ(nil, first, last, node, next, previous) \
DLL_insert_NPZ(nil, first, last, last, node, next, previous)
#define DLL_remove_NPZ(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)))
// Single (link & head) lists (= stacks)
#define SLL_stack_push_node(first, node, next) ((node)->next = (first), (first) = (node))
#define SLL_stack_pop_node(first, next) ((first) = (first)->next);
#define SLL_stack_push(first, node) SLL_stack_push_node(first, node, next)
#define SLL_stack_pop(first) SLL_stack_pop_node(first, next)
// Double linked list helpers
#define DLL_push_back(first, last, node) DLL_push_back_NPZ(0, first, last, node, next, previous)
#define DLL_remove(first, last, node) DLL_remove_NPZ(0, first, last, node, next, previous)
// =============================================================================
// 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]))
// =============================================================================
// 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_node(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)))
+91
View File
@@ -0,0 +1,91 @@
#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
// ========================================================================== //
// 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();
+25
View File
@@ -0,0 +1,25 @@
// =============================================================================
// 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)
{
return 0;
}
+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;
}
+59
View File
@@ -0,0 +1,59 @@
#pragma once
// =============================================================================
// Vector Types
typedef union Vector2f Vector2f;
union Vector2f
{
struct
{
float32 x;
float32 y;
};
float32 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);
+300
View File
@@ -0,0 +1,300 @@
// ========================================================================== //
// String Length
#include "core/core_arena.h"
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 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;
}
+76
View File
@@ -0,0 +1,76 @@
#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;
};
// ========================================================================== //
// Unicode decoding Types
typedef struct UnicodeDecode UnicodeDecode;
struct UnicodeDecode
{
uint32 increment;
uint32 codepoint;
};
// ========================================================================== //
// 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 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);
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
// =============================================================================
// 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);
Vendored Submodule
+1
Submodule Juliet/external/stb added at 2c980bb598.
Vendored Submodule
+1
Submodule Juliet/external/xxHash added at d9dfb8203c.
+84
View File
@@ -0,0 +1,84 @@
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_state_gen_id = 1;
ja_state->first_window_state = ja_state->last_window_state = &ja_nil_window_state;
}
internal void ja_frame()
{
TempArena scratch = scratch_begin(0, 0);
// =========================================================================
// Events from os
WM_EventList events = { 0 };
bool32 wait = 0;
events = wm_get_events(scratch.arena, wait);
// if (hello.handle[0] == 0)
// {
// hello = wm_window_open(rect2fp(50.f, 50.f, 1280.f, 720.f), WM_WindowFlag_UseDefaultPosition,
// str8_literal("Hello")); wm_window_first_paint(hello);
// }
// =========================================================================
// Consume events
{
for (WM_Event *event = events.first, *next = 0; event != 0; event = next)
{
bool32 take = 0;
if (event->kind == WM_EventKind_WindowClose)
{
ja_state->quit = 1;
take = 1;
}
if (take)
{
wm_eat_event(&events, event);
}
}
}
// Window management (open/render)
{
for
EachIndex(slot_idx, ja_state->window_state_gen_id)
{
JA_WindowState* ws = ja_window_state_from_id(slot_idx);
}
}
scratch_end(scratch);
}
internal void ja_shutdown()
{
// wm_window_close(aaa);
arena_clear(ja_state->arena);
}
// =============================================================================
// 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));
}
// allocate / open window if none found for this id
return ws;
}
+53
View File
@@ -0,0 +1,53 @@
#pragma once
// =============================================================================
// Core Types
typedef uint64 JA_ID;
// =============================================================================
// States Types
typedef struct JA_WindowState JA_WindowState;
struct JA_WindowState
{
JA_WindowState* order_next;
JA_WindowState* order_previous;
JA_WindowState* hash_next;
JA_WindowState* hash_previous;
JA_ID id;
WM_Window plat_handle;
};
typedef struct JA_State JA_State;
struct JA_State
{
// Base
Arena* arena;
bool32 quit;
// Windows
JA_WindowState* first_window_state;
JA_WindowState* last_window_state;
JA_WindowState* window_state_last_accessed;
JA_ID window_state_last_accessed_id;
JA_ID window_state_gen_id;
};
// =============================================================================
// 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();
// =============================================================================
// Window Functions
internal JA_WindowState* ja_window_state_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"
+34
View File
@@ -0,0 +1,34 @@
// clang-format off
// ========================================================================= //
// Includes
// Headers
#include "core/core_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 "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();
ja_init();
for (bool32 quit = 0; !quit;)
{
quit = update();
}
ja_shutdown();
}
View File
Whitespace-only changes.
+1
View File
@@ -0,0 +1 @@
#pragma once
View File
Whitespace-only changes.
+1
View File
@@ -0,0 +1 @@
#pragma once
+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
+209
View File
@@ -0,0 +1,209 @@
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
// =============================================================================
// 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);
}
// =============================================================================
// 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));
}
}
}
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;
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
// clang-format off
#include <windows.h>
#include <windowsx.h>
#pragma comment(lib, "user32")
#pragma comment(lib, "shell32")
// clang-format on
typedef struct W32_State W32_State;
struct W32_State
{
Arena* arena;
SystemInfo system_info;
uint64 microsecond_resolution;
};
global W32_State w32_state = { 0 };
@@ -0,0 +1,626 @@
// Windows SDK function than can be missing
typedef BOOL w32_SetProcessDpiAwarenessContext_Type(void* value);
typedef UINT w32_GetDpiForWindow_Type(HWND hwnd);
typedef HRESULT w32_GetDpiForMonitor_Type(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY);
typedef int w32_GetSystemMetricsForDpi_Type(int nIndex, UINT dpi);
#define w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void*)-4)
global w32_GetDpiForWindow_Type* w32_GetDpiForWindow_func = 0;
global w32_GetDpiForMonitor_Type* w32_GetDpiForMonitor_func = 0;
global w32_GetSystemMetricsForDpi_Type* w32_GetSystemMetricsForDpi_func = 0;
// =============================================================================
// Helpers
internal Rect2f w32_wm_rect2f_from_rect(RECT rect)
{
Rect2f result = { 0 };
result.x0 = (float32)rect.left;
result.x1 = (float32)rect.right;
result.y0 = (float32)rect.top;
result.y1 = (float32)rect.bottom;
return result;
}
// =============================================================================
// Windows
internal WM_Window w32_wm_handle_from_window(W32_WM_Window* window)
{
WM_Window handle = { (uint64)window };
return handle;
}
internal W32_WM_Window* w32_wm_window_from_handle(WM_Window handle)
{
W32_WM_Window* window = (W32_WM_Window*)handle.handle[0];
return window;
}
internal W32_WM_Window* w32_wm_window_from_hwnd(HWND hwnd)
{
W32_WM_Window* result = 0;
for (W32_WM_Window* cw = w32_wm_state->first_window; cw; cw = cw->next)
{
if (cw->hwnd == hwnd)
{
result = cw;
break;
}
}
return result;
}
internal HWND w32_wm_hwnd_from_window(W32_WM_Window* window)
{
return window->hwnd;
}
internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd)
{
W32_WM_Window* result = w32_wm_state->free_window;
if (result)
{
SLL_stack_pop(w32_wm_state->free_window);
}
else
{
result = push_array_no_zero(w32_wm_state->arena, W32_WM_Window, 1);
}
MemoryZeroStruct(result);
if (result)
{
DLL_push_back(w32_wm_state->first_window, w32_wm_state->last_window, result);
}
result->last_window_placement.length = sizeof(WINDOWPLACEMENT);
result->hwnd = hwnd;
result->hdc = GetDC(hwnd);
return result;
}
internal void w32_wm_window_release(W32_WM_Window* window)
{
if (window->paint_arena != 0)
{
arena_release(window->paint_arena);
}
ReleaseDC(window->hwnd, window->hdc);
DestroyWindow(window->hwnd);
DLL_remove(w32_wm_state->first_window, w32_wm_state->last_window, window);
SLL_stack_push(w32_wm_state->free_window, window);
}
internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window)
{
WM_Event* result = 0;
result->window = w32_wm_handle_from_window(window);
result->modifiers = wm_get_modifiers();
return result;
}
internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
bool32 good = 1;
if (w32_wm_event_arena == 0)
{
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
good = 0;
}
if (good)
{
W32_WM_Window* window = w32_wm_window_from_hwnd(hwnd);
WM_Window window_handle = w32_wm_handle_from_window(window);
bool32 release = 0;
switch (uMsg)
{
default:
{
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
break;
}
case WM_ENTERSIZEMOVE:
{
w32_wm_resizing = 1;
break;
}
case WM_EXITSIZEMOVE:
{
w32_wm_resizing = 0;
break;
}
case WM_SIZE:
case WM_PAINT:
{
PAINTSTRUCT ps = { 0 };
BeginPaint(hwnd, &ps);
update();
EndPaint(hwnd, &ps);
DwmFlush();
break;
}
case WM_CLOSE:
{
w32_wm_push_event(WM_EventKind_WindowClose, window);
wm_send_wakeup_event();
break;
}
case WM_SETCURSOR:
{
Rect2f window_rect = wm_client_rect_from_window(window_handle);
Vector2f mouse = wm_mouse_from_window(window_handle);
bool32 on_border = 0;
DWORD window_style = window ? GetWindowLong(window->hwnd, GWL_STYLE) : 0;
bool32 is_fullscreen = !(window_style & WS_OVERLAPPEDWINDOW);
if (window != 0 && window->custom_border && !is_fullscreen)
{
bool32 on_border_x = (mouse.x <= window->custom_border_edge_thickness ||
window_rect.x1 - window->custom_border_edge_thickness <= mouse.x);
bool32 on_border_y = (mouse.y <= window->custom_border_edge_thickness ||
window_rect.y1 - window->custom_border_edge_thickness <= mouse.y);
on_border = on_border_x || on_border_y;
}
if (!w32_wm_resizing && !on_border && contains_2f(window_rect, mouse))
{
SetCursor(w32_wm_state->hCursor);
}
else
{
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
break;
}
case WM_DPICHANGED:
{
float32 new_dpi = (float32)(wParam & 0xFFFF);
RECT suggested_new_rect = *(RECT*)lParam;
window->dpi = new_dpi;
SetWindowPos(window->hwnd, 0, suggested_new_rect.left, suggested_new_rect.top,
suggested_new_rect.right - suggested_new_rect.left,
suggested_new_rect.bottom - suggested_new_rect.top, 0);
break;
}
case WM_NCPAINT:
{
if (w32_wm_new_window_custom_border || (window != 0 && window->custom_border && !window->custom_border_composition_enabled))
{
result = 0;
}
else
{
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
break;
}
case WM_DWMCOMPOSITIONCHANGED:
{
if (window != 0 && window->custom_border)
{
BOOL enabled = 0;
DwmIsCompositionEnabled(&enabled);
window->custom_border_composition_enabled = enabled;
if (enabled)
{
MARGINS m = { 0, 0, 1, 0 };
DwmExtendFrameIntoClientArea(hwnd, &m);
DWORD dwmncrp_enabled = DWMNCRP_ENABLED;
DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &enabled, sizeof(dwmncrp_enabled));
}
}
else
{
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
break;
}
case WM_WINDOWPOSCHANGED:
{
result = 0;
break;
}
case WM_NCACTIVATE:
{
if (!w32_wm_new_window_custom_border && (window == 0 || window->custom_border == 0))
{
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
else
{
result = DefWindowProcW(hwnd, uMsg, wParam, -1);
}
break;
}
case WM_NCCALCSIZE:
{
if (w32_wm_new_window_custom_border || (window && window->custom_border))
{
float32 dpi = w32_GetDpiForWindow_func ? (float32)w32_GetDpiForWindow_func(hwnd) : 96.f;
}
else
{
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
}
break;
}
}
}
return result;
}
internal void wm_init()
{
// Setup based state
Arena* arena = arena_alloc();
w32_wm_state = push_array(arena, W32_WM_State, 1);
w32_wm_state->arena = arena;
w32_wm_state->gfx_thread_tid = (uint32)GetCurrentThreadId();
w32_wm_state->hIstance = GetModuleHandle(0);
// Set dpi awareness
w32_SetProcessDpiAwarenessContext_Type* SetProcessDpiAwarenessContext_func = 0;
HMODULE module = LoadLibraryA("user32.dll");
if (module != 0)
{
SetProcessDpiAwarenessContext_func =
(w32_SetProcessDpiAwarenessContext_Type*)GetProcAddress(module, "SetProcessDpiAwarenessContext");
w32_GetDpiForWindow_func = (w32_GetDpiForWindow_Type*)GetProcAddress(module, "GetDpiForWindow");
w32_GetDpiForMonitor_func = (w32_GetDpiForMonitor_Type*)GetProcAddress(module, "GetDpiForMonitor");
w32_GetSystemMetricsForDpi_func =
(w32_GetSystemMetricsForDpi_Type*)GetProcAddress(module, "GetSystemMetricsForDpi");
FreeLibrary(module);
}
if (SetProcessDpiAwarenessContext_func != 0)
{
SetProcessDpiAwarenessContext_func(w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
else
{
HMODULE shcore = LoadLibraryA("shcore.dll");
if (shcore)
{
typedef HRESULT(WINAPI * SetProcessDpiAwareness_t)(int);
SetProcessDpiAwareness_t SetProcessDpiAwareness = (void*)GetProcAddress(shcore, "SetProcessDpiAwareness");
if (SetProcessDpiAwareness)
{
SetProcessDpiAwareness(2);
}
FreeLibrary(shcore);
}
SetProcessDPIAware();
}
// Window class
{
WNDCLASSEXW wndclass = { sizeof(wndclass) };
wndclass.lpfnWndProc = w32_wm_wnd_proc;
wndclass.hInstance = w32_wm_state->hIstance;
wndclass.lpszClassName = L"juliet-window";
wndclass.hCursor = LoadCursorA(0, IDC_ARROW);
wndclass.hIcon = LoadIcon(w32_wm_state->hIstance, MAKEINTRESOURCE(1));
wndclass.style = CS_VREDRAW | CS_HREDRAW;
ATOM wndatom = RegisterClassExW(&wndclass);
(void)wndatom;
}
// Get gfx system info
w32_wm_state->gfx_info.double_click_time = GetDoubleClickTime() / 1000.f;
w32_wm_state->gfx_info.caret_blink_time = GetCaretBlinkTime() / 1000.f;
DEVMODEW devmodew = { 0 };
if (EnumDisplaySettingsW(0, ENUM_CURRENT_SETTINGS, &devmodew))
{
w32_wm_state->gfx_info.default_refresh_rate = (float32)devmodew.dmDisplayFrequency;
}
// initial cursor
wm_set_cursor(WM_Cursor_Pointer);
// fill the vkey to wmKey table
w32_wm_state->key_from_vkey_table[(unsigned int)'A'] = WM_Key_A;
w32_wm_state->key_from_vkey_table[(unsigned int)'B'] = WM_Key_B;
w32_wm_state->key_from_vkey_table[(unsigned int)'C'] = WM_Key_C;
w32_wm_state->key_from_vkey_table[(unsigned int)'D'] = WM_Key_D;
w32_wm_state->key_from_vkey_table[(unsigned int)'E'] = WM_Key_E;
w32_wm_state->key_from_vkey_table[(unsigned int)'F'] = WM_Key_F;
w32_wm_state->key_from_vkey_table[(unsigned int)'G'] = WM_Key_G;
w32_wm_state->key_from_vkey_table[(unsigned int)'H'] = WM_Key_H;
w32_wm_state->key_from_vkey_table[(unsigned int)'I'] = WM_Key_I;
w32_wm_state->key_from_vkey_table[(unsigned int)'J'] = WM_Key_J;
w32_wm_state->key_from_vkey_table[(unsigned int)'K'] = WM_Key_K;
w32_wm_state->key_from_vkey_table[(unsigned int)'L'] = WM_Key_L;
w32_wm_state->key_from_vkey_table[(unsigned int)'M'] = WM_Key_M;
w32_wm_state->key_from_vkey_table[(unsigned int)'N'] = WM_Key_N;
w32_wm_state->key_from_vkey_table[(unsigned int)'O'] = WM_Key_O;
w32_wm_state->key_from_vkey_table[(unsigned int)'P'] = WM_Key_P;
w32_wm_state->key_from_vkey_table[(unsigned int)'Q'] = WM_Key_Q;
w32_wm_state->key_from_vkey_table[(unsigned int)'R'] = WM_Key_R;
w32_wm_state->key_from_vkey_table[(unsigned int)'S'] = WM_Key_S;
w32_wm_state->key_from_vkey_table[(unsigned int)'T'] = WM_Key_T;
w32_wm_state->key_from_vkey_table[(unsigned int)'U'] = WM_Key_U;
w32_wm_state->key_from_vkey_table[(unsigned int)'V'] = WM_Key_V;
w32_wm_state->key_from_vkey_table[(unsigned int)'W'] = WM_Key_W;
w32_wm_state->key_from_vkey_table[(unsigned int)'X'] = WM_Key_X;
w32_wm_state->key_from_vkey_table[(unsigned int)'Y'] = WM_Key_Y;
w32_wm_state->key_from_vkey_table[(unsigned int)'Z'] = WM_Key_Z;
// Num
for (uint64 i = '0', j = WM_Key_0; i <= '9'; ++i, ++j)
{
w32_wm_state->key_from_vkey_table[i] = (WM_Key)j;
}
// Numpad num
for (uint64 i = VK_NUMPAD0, j = WM_Key_Num0; i <= VK_NUMPAD9; ++i, ++j)
{
w32_wm_state->key_from_vkey_table[i] = (WM_Key)j;
}
// F1-24
for (uint64 i = VK_F1, j = WM_Key_F1; i <= VK_F24; ++i, ++j)
{
w32_wm_state->key_from_vkey_table[i] = (WM_Key)j;
}
// Other keys
w32_wm_state->key_from_vkey_table[VK_SPACE] = WM_Key_Space;
w32_wm_state->key_from_vkey_table[VK_OEM_3] = WM_Key_Tick;
w32_wm_state->key_from_vkey_table[VK_OEM_MINUS] = WM_Key_Minus;
w32_wm_state->key_from_vkey_table[VK_OEM_PLUS] = WM_Key_Equal;
w32_wm_state->key_from_vkey_table[VK_OEM_4] = WM_Key_LeftBracket;
w32_wm_state->key_from_vkey_table[VK_OEM_6] = WM_Key_RightBracket;
w32_wm_state->key_from_vkey_table[VK_OEM_1] = WM_Key_Semicolon;
w32_wm_state->key_from_vkey_table[VK_OEM_7] = WM_Key_Quote;
w32_wm_state->key_from_vkey_table[VK_OEM_COMMA] = WM_Key_Comma;
w32_wm_state->key_from_vkey_table[VK_OEM_PERIOD] = WM_Key_Period;
w32_wm_state->key_from_vkey_table[VK_OEM_2] = WM_Key_Slash;
w32_wm_state->key_from_vkey_table[VK_OEM_5] = WM_Key_BackSlash;
w32_wm_state->key_from_vkey_table[VK_TAB] = WM_Key_Tab;
w32_wm_state->key_from_vkey_table[VK_PAUSE] = WM_Key_Pause;
w32_wm_state->key_from_vkey_table[VK_ESCAPE] = WM_Key_Esc;
w32_wm_state->key_from_vkey_table[VK_UP] = WM_Key_Up;
w32_wm_state->key_from_vkey_table[VK_LEFT] = WM_Key_Left;
w32_wm_state->key_from_vkey_table[VK_DOWN] = WM_Key_Down;
w32_wm_state->key_from_vkey_table[VK_RIGHT] = WM_Key_Right;
w32_wm_state->key_from_vkey_table[VK_BACK] = WM_Key_Backspace;
w32_wm_state->key_from_vkey_table[VK_RETURN] = WM_Key_Return;
w32_wm_state->key_from_vkey_table[VK_DELETE] = WM_Key_Delete;
w32_wm_state->key_from_vkey_table[VK_INSERT] = WM_Key_Insert;
w32_wm_state->key_from_vkey_table[VK_PRIOR] = WM_Key_PageUp;
w32_wm_state->key_from_vkey_table[VK_NEXT] = WM_Key_PageDown;
w32_wm_state->key_from_vkey_table[VK_HOME] = WM_Key_Home;
w32_wm_state->key_from_vkey_table[VK_END] = WM_Key_End;
w32_wm_state->key_from_vkey_table[VK_CAPITAL] = WM_Key_CapsLock;
w32_wm_state->key_from_vkey_table[VK_NUMLOCK] = WM_Key_NumLock;
w32_wm_state->key_from_vkey_table[VK_SCROLL] = WM_Key_ScrollLock;
w32_wm_state->key_from_vkey_table[VK_APPS] = WM_Key_Menu;
w32_wm_state->key_from_vkey_table[VK_CONTROL] = WM_Key_Ctrl;
w32_wm_state->key_from_vkey_table[VK_LCONTROL] = WM_Key_Ctrl;
w32_wm_state->key_from_vkey_table[VK_RCONTROL] = WM_Key_Ctrl;
w32_wm_state->key_from_vkey_table[VK_SHIFT] = WM_Key_Shift;
w32_wm_state->key_from_vkey_table[VK_LSHIFT] = WM_Key_Shift;
w32_wm_state->key_from_vkey_table[VK_RSHIFT] = WM_Key_Shift;
w32_wm_state->key_from_vkey_table[VK_MENU] = WM_Key_Alt;
w32_wm_state->key_from_vkey_table[VK_LMENU] = WM_Key_Alt;
w32_wm_state->key_from_vkey_table[VK_RMENU] = WM_Key_Alt;
w32_wm_state->key_from_vkey_table[VK_DIVIDE] = WM_Key_NumSlash;
w32_wm_state->key_from_vkey_table[VK_MULTIPLY] = WM_Key_NumStar;
w32_wm_state->key_from_vkey_table[VK_SUBTRACT] = WM_Key_NumMinus;
w32_wm_state->key_from_vkey_table[VK_ADD] = WM_Key_NumPlus;
w32_wm_state->key_from_vkey_table[VK_DECIMAL] = WM_Key_NumPeriod;
for (uint64 i = 0xDF, j = 0; i < 0xFF; i += 1, j += 1)
{
w32_wm_state->key_from_vkey_table[i] = (WM_Key)((uint64)WM_Key_Ex0 + j);
}
}
// =============================================================================
// Windows
internal WM_Window wm_window_open(Rect2f rect, WM_WindowFlags flags, String8 title)
{
bool32 custom_border = !!(flags & WM_WindowFlag_CustomBorder);
bool32 use_default_position = !!(flags & WM_WindowFlag_UseDefaultPosition);
Vector2f position = rect.p0;
Vector2f dimension = dimension_2f(rect);
HWND hwnd = 0;
{
TempArena scratch = scratch_begin(0, 0);
String16 titel16 = str16_from_8(scratch.arena, title);
w32_wm_new_window_custom_border = custom_border;
DWORD style_flags = WS_EX_APPWINDOW;
hwnd = CreateWindowExW(style_flags, L"juliet-window", (WCHAR*)titel16.str, WS_OVERLAPPEDWINDOW | WS_SIZEBOX,
use_default_position ? CW_USEDEFAULT : (int32)position.x,
use_default_position ? CW_USEDEFAULT : (int32)position.y, (int32)dimension.x,
(int32)dimension.y, 0, 0, w32_wm_state->hIstance, 0);
DragAcceptFiles(hwnd, 1);
w32_wm_new_window_custom_border = 0;
scratch_end(scratch);
}
W32_WM_Window* window = w32_wm_window_alloc(hwnd);
{
if (w32_GetDpiForWindow_func != 0)
{
window->dpi = (float32)w32_GetDpiForWindow_func(hwnd);
}
else
{
window->dpi = 96.f;
}
}
{
BOOL enabled = 0;
DwmIsCompositionEnabled(&enabled);
window->custom_border_composition_enabled = enabled;
}
if (flags & WM_WindowFlag_CustomBorder)
{
window->custom_border = 1;
window->paint_arena = arena_alloc();
}
WM_Window result = w32_wm_handle_from_window(window);
return result;
}
internal void wm_window_close(WM_Window handle)
{
W32_WM_Window* window = w32_wm_window_from_handle(handle);
if (window != 0)
{
w32_wm_window_release(window);
}
}
internal void wm_window_first_paint(WM_Window window_handle)
{
W32_WM_Window* window = w32_wm_window_from_handle(window_handle);
if (window)
{
window->first_paint_done = 1;
ShowWindow(window->hwnd, SW_SHOW);
if (window->maximized)
{
ShowWindow(window->hwnd, SW_MAXIMIZE);
}
}
}
internal Rect2f wm_client_rect_from_window(WM_Window handle)
{
Rect2f result = { 0 };
W32_WM_Window* window = w32_wm_window_from_handle(handle);
if (window)
{
RECT rect = { 0 };
GetClientRect(w32_wm_hwnd_from_window(window), &rect);
result = w32_wm_rect2f_from_rect(rect);
}
return result;
}
// =============================================================================
// Events
internal void wm_send_wakeup_event()
{
PostThreadMessageW(w32_wm_state->gfx_thread_tid, 0x401, 0, 0);
}
internal WM_EventList wm_get_events(Arena* arena, bool32 wait)
{
w32_wm_event_arena = arena;
MemoryZeroStruct(&w32_wm_event_list);
MSG msg = { 0 };
if (!wait || GetMessageW(&msg, 0, 0, 0))
{
bool32 first_wait = wait;
for (; first_wait || PeekMessageW(&msg, 0, 0, 0, PM_REMOVE); first_wait = 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
if (msg.message == WM_QUIT)
{
w32_wm_push_event(WM_EventKind_WindowClose, 0);
}
}
}
return w32_wm_event_list;
}
internal WM_Modifiers wm_get_modifiers()
{
WM_Modifiers modifiers = 0;
if (GetKeyState(VK_CONTROL) * 0x8000)
{
modifiers |= WM_Modifier_Ctrl;
}
if (GetKeyState(VK_SHIFT) * 0x8000)
{
modifiers |= WM_Modifier_Shift;
}
if (GetKeyState(VK_MENU) * 0x8000)
{
modifiers |= WM_Modifier_Alt;
}
return modifiers;
}
internal Vector2f wm_mouse_from_window(WM_Window handle)
{
Vector2f result = { 0 };
POINT p;
if (GetCursorPos(&p))
{
W32_WM_Window* window = w32_wm_window_from_handle(handle);
ScreenToClient(window->hwnd, &p);
result.x = (float32)p.x;
result.y = (float32)p.y;
}
return result;
}
// =============================================================================
// Cursors
internal void wm_set_cursor(WM_Cursor cursor)
{
bool32 valid_cursor = 1;
HCURSOR hcursor = 0;
switch (cursor)
{
default:
{
valid_cursor = 0;
break;
};
#define WIN32_CURSOR_X_LIST(X) X(Pointer, IDC_ARROW)
#define CURSOR_CASE(Entry, IDC) \
case WM_Cursor_##Entry: \
{ \
local_persist HCURSOR curs = 0; \
if (curs == 0) \
{ \
curs = LoadCursor(NULL, IDC); \
} \
hcursor = curs; \
break; \
}
WIN32_CURSOR_X_LIST(CURSOR_CASE)
#undef CURSOR_CASE
#undef WIN32_CURSOR_X_LIST
}
if (valid_cursor && !w32_wm_resizing)
{
if (hcursor != w32_wm_state->hCursor)
{
PostMessageW(0, WM_SETCURSOR, 0, 0);
POINT p = { 0 };
GetCursorPos(&p);
SetCursorPos(p.x, p.y);
}
w32_wm_state->hCursor = hcursor;
}
}
@@ -0,0 +1,70 @@
#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;
};
// =============================================================================
// 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 WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window);
internal void w32_wm_window_release(W32_WM_Window* window);
+18
View File
@@ -0,0 +1,18 @@
// =============================================================================
// Event Functions
internal void wm_eat_event(WM_EventList* events, WM_Event* event)
{
DLL_remove(events->first, events->last, event);
events->count -= 1;
}
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;
}
+135
View File
@@ -0,0 +1,135 @@
#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_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;
};
typedef struct WM_EventList WM_EventList;
struct WM_EventList
{
uint64 count;
WM_Event* first;
WM_Event* last;
};
// =============================================================================
// Application defined frame hook
internal bool32 frame();
// =============================================================================
// Event Functions
internal void wm_eat_event(WM_EventList* events, WM_Event* event);
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 Rect2f wm_client_rect_from_window(WM_Window window);
// =============================================================================
// Events
internal void wm_send_wakeup_event();
internal WM_EventList wm_get_events(Arena* arena, bool32 wait);
internal WM_Modifiers wm_get_modifiers();
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