Compare commits
12
Commits
main
..
cf86dd10a7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf86dd10a7 | ||
|
|
5995dd9a47 | ||
|
|
d5c6c79a76 | ||
|
|
7e8e626e24 | ||
|
|
f96b2e99cf | ||
|
|
4ec42f4bee | ||
|
|
886e722c71 | ||
|
|
575379e264 | ||
|
|
17e26fdd00 | ||
|
|
5d6ca639fd | ||
|
|
16664c68b5 | ||
|
|
ee1878cce7 |
No files matched your search
@@ -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.
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
# Binaries
|
# Binaries
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
|
[Bb]uild/
|
||||||
[Ll]ib/
|
[Ll]ib/
|
||||||
.idea/
|
.idea/
|
||||||
.vs/
|
.vs/
|
||||||
|
|||||||
+11
@@ -1,3 +1,14 @@
|
|||||||
[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
|
||||||
|
# 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
|
||||||
Vendored
+1
-1
Submodule External/Imgui updated: 9b7699f325...c1aaac65e8.
@@ -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"
|
||||||
@@ -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);
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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)))
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
internal void main_thread_core_entry_point(int argc, char** argv);
|
||||||
|
internal bool32 update();
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
Whitespace-only changes.
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__))
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
// OS DEPEND see os/core/os_core.c
|
||||||
@@ -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);
|
||||||
Whitespace-only changes.
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Aborting (os dependent see os/core/os_core.c)
|
||||||
|
|
||||||
|
internal void abort_self(uint64 exit_code);
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
// OS DEPEND see os/core/os_core.c
|
||||||
@@ -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();
|
||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
+1
Submodule Juliet/external/stb_sprintf added at 2ffb3379e8.
+1
Submodule Juliet/external/xxHash added at c87183a77d.
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include "julietapp_core.c"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "julietapp_core.h"
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
|||||||
|
#pragma once
|
||||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
|||||||
|
#pragma once
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include "render.c"
|
||||||
|
|
||||||
|
#if R_BACKEND == R_BACKEND_D3D12
|
||||||
|
# include "d3d12/render_d3d12.c"
|
||||||
|
#endif
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
@echo off
|
||||||
|
call "%~dp0..\new_build.bat" %*
|
||||||
|
exit /b %ERRORLEVEL%
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
@echo off
|
||||||
|
call "%~dp0..\new_generate.bat" %*
|
||||||
|
exit /b %ERRORLEVEL%
|
||||||
+125
@@ -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
|
||||||
@@ -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%
|
||||||
@@ -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
Reference in new issue
Block a user