Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fa75c116e | ||
|
|
2881b2c9d5 | ||
|
|
d79cf42a3d | ||
|
|
17af5348e9 | ||
|
|
dec8cbd059 | ||
|
|
f580776964 | ||
|
|
d2d9981efe | ||
|
|
f6b48a1c11 | ||
|
|
bf13f269fe | ||
|
|
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.
|
||||||
+5
-6
@@ -44,10 +44,14 @@ 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: ''
|
||||||
MacroBlockEnd: ''
|
MacroBlockEnd: ''
|
||||||
|
Macros:
|
||||||
|
- 'EachIndex(it, count)=(uint64 it = 0; it < (count); ++it)'
|
||||||
|
- 'EachNode(it, Type, first)=(Type* it = first; it != 0; it = it->next)'
|
||||||
NamespaceIndentation: All
|
NamespaceIndentation: All
|
||||||
ObjCSpaceAfterProperty: true
|
ObjCSpaceAfterProperty: true
|
||||||
PenaltyBreakBeforeFirstCallParameter: 100
|
PenaltyBreakBeforeFirstCallParameter: 100
|
||||||
@@ -57,15 +61,10 @@ 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
|
||||||
Standard: Cpp11
|
Standard: Cpp11
|
||||||
StatementMacros:
|
|
||||||
- UPROPERTY
|
|
||||||
- UCLASS
|
|
||||||
- USTRUCT
|
|
||||||
- GENERATED_BODY
|
|
||||||
- UENUM
|
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
...
|
...
|
||||||
@@ -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_sprintf/stb_sprintf.h"
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Third party includes
|
||||||
|
|
||||||
|
#define STB_SPRINTF_DECORATE(name) juliet_##name
|
||||||
|
#define STB_SPRINTF_STATIC
|
||||||
|
#include "external/stb_sprintf/stb_sprintf.h"
|
||||||
|
|
||||||
|
#define internal static
|
||||||
|
#define global static
|
||||||
|
#define local_persist static
|
||||||
|
|
||||||
|
#if (COMPILER_CLANG && OS_WINDOWS) || COMPILER_MSVC
|
||||||
|
# pragma section(".rdata$", read)
|
||||||
|
# define read_only __declspec(allocate(".rdata$"))
|
||||||
|
#elif (COMPILER_CLANG && OS_LINUX)
|
||||||
|
# define read_only __attribute__((section(".rodata")))
|
||||||
|
#else
|
||||||
|
// Note: not possible with GCC
|
||||||
|
# define read_only
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if COMPILER_CLANG || COMPILER_GCC
|
||||||
|
# define thread_static __thread
|
||||||
|
#elif COMPILER_MSVC
|
||||||
|
# define thread_static __declspec(thread)
|
||||||
|
#else
|
||||||
|
# error thread_static not defined for this compiler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Units
|
||||||
|
|
||||||
|
#define KB(d) ((uint64)(d) << 10)
|
||||||
|
#define MB(d) ((uint64)(d) << 20)
|
||||||
|
#define GB(d) ((uint64)(d) << 30)
|
||||||
|
#define Million(n) ((n) * 1000000)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Branch predictor hints
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# define Expect(expr, val) __builtin_expect((expr), (val))
|
||||||
|
#else
|
||||||
|
# define Expect(expr, val) (expr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Likely(expr) Expect(expr, 1)
|
||||||
|
#define Unlikely(expr) Expect(expr, 0)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Min Max Clamp
|
||||||
|
|
||||||
|
#define Min(A, B) (((A) < (B) ? (A) : (B)))
|
||||||
|
#define Max(A, B) (((A) > (B) ? (A) : (B)))
|
||||||
|
#define ClampTop(A, X) Min(A, X)
|
||||||
|
#define ClampBottom(X, B) Max(X, B)
|
||||||
|
#define Clamp(A, X, B) (((X) < (A)) ? (A) : ((X) > (B)) ? (B) : (X))
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Alignment
|
||||||
|
#if COMPILER_CLANG || COMPILER_GCC
|
||||||
|
# define AlignOf(Type) __alignof(Type)
|
||||||
|
#elif COMPILER_MSVC
|
||||||
|
# define AlignOf(Type) __alignof(Type)
|
||||||
|
#else
|
||||||
|
# error AlignOf not defined for this compiler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// For loop helpers
|
||||||
|
|
||||||
|
#define DeferLoop(begin, end) for (int _i_ = ((begin), 0); !_i_; ++_i_, (end))
|
||||||
|
|
||||||
|
#define EachIndex(it, count) (uint64 it = 0; it < (count); ++it)
|
||||||
|
#define EachNode(it, Type, first) (Type* it = first; it != 0; it = it->next)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Memory Helpers
|
||||||
|
|
||||||
|
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
|
||||||
|
#define MemorySet(dst, src, size) memset((dst), (src), (size))
|
||||||
|
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
|
||||||
|
|
||||||
|
#define MemoryZero(ptr, size) memset((ptr), 0, (size))
|
||||||
|
#define MemoryZeroStruct(s) MemoryZero((s), sizeof(*(s)))
|
||||||
|
#define MemoryZeroArray(arr) MemoryZero((arr), sizeof(arr))
|
||||||
|
|
||||||
|
#define MemoryMatch(a, b, size) (MemoryCompare((a), (b), (size)) == 0)
|
||||||
|
#define MemoryMatchStruct(a, b) MemoryMatch((a), (b), sizeof(*(a)))
|
||||||
|
#define MemoryMatchArray(a, b) MemoryMatch((a), (b), sizeof(a))
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Asserts
|
||||||
|
|
||||||
|
#if COMPILER_CLANG || COMPILER_GCC
|
||||||
|
# define Trap() __builtin_trap()
|
||||||
|
#elif COMPILER_MSVC
|
||||||
|
# define Trap() __debugbreak()
|
||||||
|
#else
|
||||||
|
# error Unknown trap intrinsic for this compiler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define AssertAlways(cond) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (!(cond)) \
|
||||||
|
{ \
|
||||||
|
Trap(); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
#if BUILD_DEBUG
|
||||||
|
# define Assert(cond) AssertAlways(cond)
|
||||||
|
#else
|
||||||
|
# define Assert(cond) (void)(cond)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define StaticAssert(cond, ID) global uint8 GLUE(ID, __LINE__)[(cond) ? 1 : -1]
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Linked List macro
|
||||||
|
|
||||||
|
// Linked list macro helpers
|
||||||
|
#define CheckNil(nil, ptr) ((ptr) == 0 || (ptr) == nil)
|
||||||
|
#define SetNil(nil, ptr) ((ptr) = nil)
|
||||||
|
|
||||||
|
// Doubly-linked-lists
|
||||||
|
// clang-format off
|
||||||
|
#define DLL_insert_next_prev_zero(nil, first, last, ptr, node, next, previous) \
|
||||||
|
(CheckNil(nil, first) ? ((first) = (last) = (node), SetNil(nil, (node)->next), SetNil(nil, (node)->previous)) \
|
||||||
|
: CheckNil(nil, ptr) ? ((node)->next = (first), (first)->previous = (node), (first) = (node), SetNil(nil, (node)->previous)) \
|
||||||
|
: ((ptr) == (last)) ? ((last)->next = (node), (node )->previous = (last), (last ) = (node), SetNil(nil, (node)->next)) \
|
||||||
|
: (((CheckNil(nil, ptr) && CheckNil(nil, (ptr)->next)) ? (0) : ((ptr)->next->previous = (node))), \
|
||||||
|
((node)->next = (ptr)->next), ((ptr)->next = (node)), ((node)->previous = (ptr))))
|
||||||
|
#define DLL_push_back_next_prev_zero(nil, first, last, node, next, previous) \
|
||||||
|
DLL_insert_next_prev_zero(nil, first, last, last, node, next, previous)
|
||||||
|
#define DLL_remove_next_prev_zero(nil, first, last, node, next, previous) \
|
||||||
|
(((node) == (first) ? (first) = (node)->next : (0)), ((node) == (last) ? (last) = (last)->previous : (0)), \
|
||||||
|
(CheckNil(nil, (node)->previous) ? (0) : ((node)->previous->next = (node)->next)), \
|
||||||
|
(CheckNil(nil, (node)->next) ? (0) : ((node)->next->previous = (node)->previous)))
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// Single link double head lists (= queues)
|
||||||
|
#define SLL_queue_push_next_zero(nil, first, last, node, next) \
|
||||||
|
(CheckNil(nil, first) ? ((first) = (last) = (node), SetNil(nil, (node)->next)) \
|
||||||
|
: ((last)->next = (node), (last) = (node), SetNil(nil, (node)->next)))
|
||||||
|
|
||||||
|
// Single (link & head) lists (= stacks)
|
||||||
|
#define SLL_stack_push_next(first, node, next) ((node)->next = (first), (first) = (node))
|
||||||
|
#define SLL_stack_pop_next(first, next) ((first) = (first)->next);
|
||||||
|
|
||||||
|
// Double linked list helpers
|
||||||
|
#define DLL_push_back_next_prev(first, last, node, next, previous) \
|
||||||
|
DLL_push_back_next_prev_zero(0, first, last, node, next, previous)
|
||||||
|
#define DLL_remove_next_prev(first, last, node, next, prev) DLL_remove_next_prev_zero(0, first, last, node, next, prev)
|
||||||
|
#define DLL_push_back(first, last, node) DLL_push_back_next_prev_zero(0, first, last, node, next, previous)
|
||||||
|
#define DLL_remove(first, last, node) DLL_remove_next_prev_zero(0, first, last, node, next, previous)
|
||||||
|
|
||||||
|
// Queue helpers
|
||||||
|
#define SLL_queue_push(first, last, node) SLL_queue_push_next_zero(0, first, last, node, next)
|
||||||
|
|
||||||
|
// Stack helpers
|
||||||
|
#define SLL_stack_push(first, node) SLL_stack_push_next(first, node, next)
|
||||||
|
#define SLL_stack_pop(first) SLL_stack_pop_next(first, next)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
#define AlignPow2(x, align) (((x) + (align) - 1) & (~((align) - 1)))
|
||||||
|
|
||||||
|
#define Stringify_(S) #S
|
||||||
|
#define Stringify(S) Stringify_(S)
|
||||||
|
|
||||||
|
#define GLUE_(A, B) A##B
|
||||||
|
#define GLUE(A, B) GLUE_(A, B)
|
||||||
|
|
||||||
|
#define ArrayCount(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
#if ARCH_64BIT
|
||||||
|
# define IntFromPtr(ptr) ((uint64)(ptr))
|
||||||
|
#else
|
||||||
|
# error Missing pointer to integer cast for this architecture
|
||||||
|
#endif
|
||||||
|
#define PtrFromInt(i) (void*)(i)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Core Types
|
||||||
|
|
||||||
|
typedef uint8_t uint8;
|
||||||
|
typedef uint16_t uint16;
|
||||||
|
typedef uint32_t uint32;
|
||||||
|
typedef uint64_t uint64;
|
||||||
|
typedef int8_t int8;
|
||||||
|
typedef int16_t int16;
|
||||||
|
typedef int32_t int32;
|
||||||
|
typedef int64_t int64;
|
||||||
|
typedef float float32;
|
||||||
|
typedef double float64;
|
||||||
|
|
||||||
|
typedef int8 bool8;
|
||||||
|
typedef int16 bool16;
|
||||||
|
typedef int32 bool32;
|
||||||
|
typedef int64 bool64;
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Core Constants
|
||||||
|
|
||||||
|
global uint8 max_uint8 = 0xFF;
|
||||||
|
global uint16 max_uint16 = 0xFFFF;
|
||||||
|
global uint32 max_uint32 = 0xFFFFFFFF;
|
||||||
|
global uint64 max_uint64 = 0xFFFFFFFFFFFFFFFFll;
|
||||||
|
|
||||||
|
global int8 max_int8 = (int8)0x7F;
|
||||||
|
global int16 max_int16 = (int16)0x7FFF;
|
||||||
|
global int32 max_int32 = (int32)0x7FFFFFFF;
|
||||||
|
global int64 max_int64 = (int64)0x7FFFFFFFFFFFFFFFll;
|
||||||
|
|
||||||
|
global const uint32 bitmask1 = 0x00000001;
|
||||||
|
global const uint32 bitmask2 = 0x00000003;
|
||||||
|
global const uint32 bitmask3 = 0x00000007;
|
||||||
|
global const uint32 bitmask4 = 0x0000000f;
|
||||||
|
global const uint32 bitmask5 = 0x0000001f;
|
||||||
|
global const uint32 bitmask6 = 0x0000003f;
|
||||||
|
global const uint32 bitmask7 = 0x0000007f;
|
||||||
|
global const uint32 bitmask8 = 0x000000ff;
|
||||||
|
global const uint32 bitmask9 = 0x000001ff;
|
||||||
|
global const uint32 bitmask10 = 0x000003ff;
|
||||||
|
global const uint32 bitmask11 = 0x000007ff;
|
||||||
|
global const uint32 bitmask12 = 0x00000fff;
|
||||||
|
global const uint32 bitmask13 = 0x00001fff;
|
||||||
|
global const uint32 bitmask14 = 0x00003fff;
|
||||||
|
global const uint32 bitmask15 = 0x00007fff;
|
||||||
|
global const uint32 bitmask16 = 0x0000ffff;
|
||||||
|
global const uint32 bitmask17 = 0x0001ffff;
|
||||||
|
global const uint32 bitmask18 = 0x0003ffff;
|
||||||
|
global const uint32 bitmask19 = 0x0007ffff;
|
||||||
|
global const uint32 bitmask20 = 0x000fffff;
|
||||||
|
global const uint32 bitmask21 = 0x001fffff;
|
||||||
|
global const uint32 bitmask22 = 0x003fffff;
|
||||||
|
global const uint32 bitmask23 = 0x007fffff;
|
||||||
|
global const uint32 bitmask24 = 0x00ffffff;
|
||||||
|
global const uint32 bitmask25 = 0x01ffffff;
|
||||||
|
global const uint32 bitmask26 = 0x03ffffff;
|
||||||
|
global const uint32 bitmask27 = 0x07ffffff;
|
||||||
|
global const uint32 bitmask28 = 0x0fffffff;
|
||||||
|
global const uint32 bitmask29 = 0x1fffffff;
|
||||||
|
global const uint32 bitmask30 = 0x3fffffff;
|
||||||
|
global const uint32 bitmask31 = 0x7fffffff;
|
||||||
|
global const uint32 bitmask32 = 0xffffffff;
|
||||||
|
|
||||||
|
global const uint32 bit1 = (1 << 0);
|
||||||
|
global const uint32 bit2 = (1 << 1);
|
||||||
|
global const uint32 bit3 = (1 << 2);
|
||||||
|
global const uint32 bit4 = (1 << 3);
|
||||||
|
global const uint32 bit5 = (1 << 4);
|
||||||
|
global const uint32 bit6 = (1 << 5);
|
||||||
|
global const uint32 bit7 = (1 << 6);
|
||||||
|
global const uint32 bit8 = (1 << 7);
|
||||||
|
global const uint32 bit9 = (1 << 8);
|
||||||
|
global const uint32 bit10 = (1 << 9);
|
||||||
|
global const uint32 bit11 = (1 << 10);
|
||||||
|
global const uint32 bit12 = (1 << 11);
|
||||||
|
global const uint32 bit13 = (1 << 12);
|
||||||
|
global const uint32 bit14 = (1 << 13);
|
||||||
|
global const uint32 bit15 = (1 << 14);
|
||||||
|
global const uint32 bit16 = (1 << 15);
|
||||||
|
global const uint32 bit17 = (1 << 16);
|
||||||
|
global const uint32 bit18 = (1 << 17);
|
||||||
|
global const uint32 bit19 = (1 << 18);
|
||||||
|
global const uint32 bit20 = (1 << 19);
|
||||||
|
global const uint32 bit21 = (1 << 20);
|
||||||
|
global const uint32 bit22 = (1 << 21);
|
||||||
|
global const uint32 bit23 = (1 << 22);
|
||||||
|
global const uint32 bit24 = (1 << 23);
|
||||||
|
global const uint32 bit25 = (1 << 24);
|
||||||
|
global const uint32 bit26 = (1 << 25);
|
||||||
|
global const uint32 bit27 = (1 << 26);
|
||||||
|
global const uint32 bit28 = (1 << 27);
|
||||||
|
global const uint32 bit29 = (1 << 28);
|
||||||
|
global const uint32 bit30 = (1 << 29);
|
||||||
|
global const uint32 bit31 = (1 << 30);
|
||||||
|
global const uint32 bit32 = (1 << 31);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Safe Casts
|
||||||
|
|
||||||
|
internal uint16 safe_cast_uint16(uint32 val);
|
||||||
|
internal uint32 safe_cast_uint32(uint64 val);
|
||||||
|
internal int32 safe_cast_int32(int64 val);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Time functions
|
||||||
|
|
||||||
|
internal uint64 now_time_us();
|
||||||
|
internal void sleep_ms(uint32 ms);
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Arena Functions
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
internal Arena* arena_alloc_internal(ArenaParams* params)
|
||||||
|
{
|
||||||
|
uint64 committed = params->commit_size;
|
||||||
|
uint64 reserved = params->reserve_size;
|
||||||
|
|
||||||
|
// Initial block
|
||||||
|
void* base = NULL;
|
||||||
|
if (params->flags & ArenaFlag_LargePages)
|
||||||
|
{
|
||||||
|
uint64 page_size = get_system_info()->large_page_size;
|
||||||
|
reserved = AlignPow2(reserved, page_size);
|
||||||
|
committed = AlignPow2(committed, page_size);
|
||||||
|
|
||||||
|
base = reserve_memory_large(reserved);
|
||||||
|
commit_memory_large(base, committed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint64 page_size = get_system_info()->page_size;
|
||||||
|
reserved = AlignPow2(reserved, page_size);
|
||||||
|
committed = AlignPow2(committed, page_size);
|
||||||
|
|
||||||
|
base = reserve_memory(reserved);
|
||||||
|
commit_memory(base, committed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Unlikely(base == 0))
|
||||||
|
{
|
||||||
|
abort_self(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena* arena = base;
|
||||||
|
arena->current = arena;
|
||||||
|
arena->commit_size = params->commit_size;
|
||||||
|
arena->reserve_size = params->reserve_size;
|
||||||
|
arena->base_position = 0;
|
||||||
|
arena->position = ARENA_HEADER_SIZE;
|
||||||
|
arena->committed = committed;
|
||||||
|
arena->reserved = reserved;
|
||||||
|
|
||||||
|
#if BUILD_DEBUG
|
||||||
|
arena->alloc_file = params->alloc_file;
|
||||||
|
arena->alloc_line = params->alloc_line;
|
||||||
|
arena->name = params->name;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void arena_release(Arena* arena)
|
||||||
|
{
|
||||||
|
for (Arena *p = arena->current, *prev = 0; p != 0; p = prev)
|
||||||
|
{
|
||||||
|
prev = p->previous;
|
||||||
|
release_memory(p, p->reserved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Arena Push/Pop core Functions
|
||||||
|
|
||||||
|
internal void* arena_push(Arena* arena, uint64 size, uint64 align, bool32 zero)
|
||||||
|
{
|
||||||
|
Arena* current = arena->current;
|
||||||
|
uint64 pos_pre = AlignPow2(current->position, align);
|
||||||
|
uint64 pos_post = pos_pre + size;
|
||||||
|
|
||||||
|
uint64 size_to_zero = 0;
|
||||||
|
if (zero)
|
||||||
|
{
|
||||||
|
size_to_zero = Min(current->committed, pos_post) - pos_pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current->reserved < pos_post && !(arena->flags & ArenaFlag_NoChain))
|
||||||
|
{
|
||||||
|
Arena* new_block = 0;
|
||||||
|
if (new_block == 0)
|
||||||
|
{
|
||||||
|
uint64 reserved_size = arena->reserve_size;
|
||||||
|
uint64 committed_size = arena->commit_size;
|
||||||
|
if (size + ARENA_HEADER_SIZE > reserved_size)
|
||||||
|
{
|
||||||
|
reserved_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
||||||
|
committed_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
||||||
|
}
|
||||||
|
new_block = arena_alloc(.reserve_size = reserved_size, .commit_size = committed_size, .flags = arena->flags,
|
||||||
|
|
||||||
|
#if BUILD_DEBUG
|
||||||
|
.alloc_file = arena->alloc_file, .alloc_line = arena->alloc_line
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
size_to_zero = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_to_zero = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_block->base_position = current->base_position + current->reserved;
|
||||||
|
SLL_stack_push_next(arena->current, new_block, previous);
|
||||||
|
|
||||||
|
current = new_block;
|
||||||
|
pos_pre = AlignPow2(current->position, align);
|
||||||
|
pos_post = pos_pre + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// commit new pages if needed
|
||||||
|
if (current->committed < pos_post)
|
||||||
|
{
|
||||||
|
uint64 committed_past_aligned = pos_post + current->commit_size - 1;
|
||||||
|
committed_past_aligned -= committed_past_aligned % current->commit_size;
|
||||||
|
uint64 committed_past_clamped = ClampTop(committed_past_aligned, current->reserved);
|
||||||
|
uint64 committed_size = committed_past_clamped - current->committed;
|
||||||
|
uint8* committed_ptr = (uint8*)current + current->committed;
|
||||||
|
if (current->flags & ArenaFlag_LargePages)
|
||||||
|
{
|
||||||
|
commit_memory_large(committed_ptr, committed_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commit_memory(committed_ptr, committed_size);
|
||||||
|
}
|
||||||
|
current->committed = committed_past_clamped;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* result = 0;
|
||||||
|
if (current->committed >= pos_post)
|
||||||
|
{
|
||||||
|
result = (uint8*)current + pos_pre;
|
||||||
|
current->position = pos_post;
|
||||||
|
MemoryZero(result, size_to_zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Unlikely(result == 0))
|
||||||
|
{
|
||||||
|
abort_self(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint64 arena_pos(Arena* arena)
|
||||||
|
{
|
||||||
|
Arena* current = arena->current;
|
||||||
|
uint64 position = current->base_position + current->position;
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void arena_pop_to(Arena* arena, uint64 position)
|
||||||
|
{
|
||||||
|
uint64 clamped_pos = ClampBottom(ARENA_HEADER_SIZE, position);
|
||||||
|
Arena* current = arena->current;
|
||||||
|
|
||||||
|
for (Arena* previous = 0; current->base_position >= clamped_pos; current = previous)
|
||||||
|
{
|
||||||
|
previous = current->previous;
|
||||||
|
release_memory(current, current->reserved);
|
||||||
|
}
|
||||||
|
arena->current = current;
|
||||||
|
uint64 new_position = clamped_pos - current->base_position;
|
||||||
|
AssertAlways(new_position <= current->position);
|
||||||
|
current->position = new_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void arena_clear(Arena* arena)
|
||||||
|
{
|
||||||
|
arena_pop_to(arena, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void arena_pop(Arena* arena, uint64 amount)
|
||||||
|
{
|
||||||
|
uint64 pos_old = arena_pos(arena);
|
||||||
|
Assert(pos_old > amount);
|
||||||
|
uint64 pos_new = pos_old - amount;
|
||||||
|
arena_pop_to(arena, pos_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temp arena
|
||||||
|
internal TempArena temp_begin(Arena* arena)
|
||||||
|
{
|
||||||
|
uint64 position = arena_pos(arena);
|
||||||
|
TempArena temp = { arena, position };
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void temp_end(TempArena temp)
|
||||||
|
{
|
||||||
|
arena_pop_to(temp.arena, temp.position);
|
||||||
|
}
|
||||||
@@ -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,98 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// Compiler defines | Clang
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
|
||||||
|
# define COMPILER_CLANG 1
|
||||||
|
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# define OS_WINDOWS 1
|
||||||
|
# else
|
||||||
|
# error Compiler / OS combo is not supported
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||||
|
# define ARCH_X64 1
|
||||||
|
# else
|
||||||
|
# error Architecture not supported
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
|
# define COMPILER_MSVC 1
|
||||||
|
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# define OS_WINDOWS 1
|
||||||
|
# else
|
||||||
|
# error Compiler / OS combo is not supported
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(_M_AMD64)
|
||||||
|
# define ARCH_X64 1
|
||||||
|
# else
|
||||||
|
# error Architecture not supported
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error Compiler not supported.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// Architecture
|
||||||
|
|
||||||
|
#if defined(ARCH_X64)
|
||||||
|
# define ARCH_64BIT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// Language
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
# define LANG_CPP 1
|
||||||
|
#else
|
||||||
|
# define LANG_C 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// Build Options
|
||||||
|
|
||||||
|
#if !defined(BUILD_DEBUG)
|
||||||
|
# define BUILD_DEBUG 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// Zeroing unused Options
|
||||||
|
|
||||||
|
#if !defined(ARCH_X64)
|
||||||
|
# define ARCH_X64 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_X86)
|
||||||
|
# define ARCH_X86 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(COMPILER_CLANG)
|
||||||
|
# define COMPILER_CLANG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(COMPILER_MSVC)
|
||||||
|
# define COMPILER_MSVC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(OS_WINDOWS)
|
||||||
|
# define OS_WINDOWS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(LANG_CPP)
|
||||||
|
# define LANG_CPP 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(LANG_C)
|
||||||
|
# define LANG_C 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !ARCH_X64
|
||||||
|
# error Trying to build unsupported architecture. Only x64 is supported.
|
||||||
|
#endif
|
||||||
@@ -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,26 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Hash Functions
|
||||||
|
|
||||||
|
#pragma push_macro("__cpuid")
|
||||||
|
#undef __cpuid
|
||||||
|
#if !defined(XXH_IMPLEMENTATION)
|
||||||
|
# define XXH_INLINE_ALL
|
||||||
|
# define XXH_IMPLEMENTATION
|
||||||
|
# define XXH_STATIC_LINKING_ONLY
|
||||||
|
# include "external/xxHash/xxhash.h"
|
||||||
|
#endif
|
||||||
|
#pragma pop_macro("__cpuid")
|
||||||
|
|
||||||
|
#define HASH_SEED 4259
|
||||||
|
|
||||||
|
internal uint64 uint64_hash_from_string(String8 string)
|
||||||
|
{
|
||||||
|
uint64 result = uint64_hash_from_seed_string(HASH_SEED, string);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint64 uint64_hash_from_seed_string(uint64 seed, String8 string)
|
||||||
|
{
|
||||||
|
uint64 result = XXH3_64bits_withSeed(string.str, string.size, seed);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -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,70 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Vector Types
|
||||||
|
|
||||||
|
typedef union Vector2f Vector2f;
|
||||||
|
union Vector2f
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float32 x;
|
||||||
|
float32 y;
|
||||||
|
};
|
||||||
|
float32 v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union Vector2i Vector2i;
|
||||||
|
union Vector2i
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int32 x;
|
||||||
|
int32 y;
|
||||||
|
};
|
||||||
|
int32 v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Rect Types
|
||||||
|
|
||||||
|
typedef union Rect2f Rect2f;
|
||||||
|
union Rect2f
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
Vector2f min;
|
||||||
|
Vector2f max;
|
||||||
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
Vector2f p0;
|
||||||
|
Vector2f p1;
|
||||||
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float32 x0;
|
||||||
|
float32 y0;
|
||||||
|
float32 x1;
|
||||||
|
float32 y1;
|
||||||
|
};
|
||||||
|
Vector2f v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Functions
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Vectors
|
||||||
|
|
||||||
|
#define vector2f(x, y) vector_2f((x), (y))
|
||||||
|
internal Vector2f vector_2f(float32 x, float32 y);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Rectangles
|
||||||
|
|
||||||
|
#define rect2f(min, max) rect_2f((min), (max))
|
||||||
|
#define rect2fp(x, y, z, w) rect2f(vector2f((x), (y)), vector2f((z), (w)))
|
||||||
|
internal Rect2f rect_2f(Vector2f min, Vector2f max);
|
||||||
|
internal bool32 contains_2f(Rect2f rect, Vector2f x);
|
||||||
|
internal Vector2f dimension_2f(Rect2f rect);
|
||||||
@@ -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,395 @@
|
|||||||
|
#ifndef MEM_STATIC
|
||||||
|
# define MEM_STATIC
|
||||||
|
# define MEM_API static inline
|
||||||
|
# include "external/memfun/memfun.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String conversions
|
||||||
|
|
||||||
|
internal bool32 char_is_upper(uint8 c)
|
||||||
|
{
|
||||||
|
return ('A' <= c && c <= 'Z');
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool32 char_is_lower(uint8 c)
|
||||||
|
{
|
||||||
|
return ('a' <= c && c <= 'z');
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool32 char_is_slash(uint8 c)
|
||||||
|
{
|
||||||
|
return (c == '/' || c == '\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint8 lower_from_char(uint8 c)
|
||||||
|
{
|
||||||
|
if (char_is_upper(c))
|
||||||
|
{
|
||||||
|
c += ('a' - 'A');
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint8 upper_from_char(uint8 c)
|
||||||
|
{
|
||||||
|
if (char_is_lower(c))
|
||||||
|
{
|
||||||
|
c += ('A' - 'a');
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint8 correct_slash_from_char(uint8 c)
|
||||||
|
{
|
||||||
|
if (char_is_slash(c))
|
||||||
|
{
|
||||||
|
c = '/';
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// String Length
|
||||||
|
|
||||||
|
internal uint64 cstring8_length(uint8* cstring)
|
||||||
|
{
|
||||||
|
uint64 length = 0;
|
||||||
|
if (cstring)
|
||||||
|
{
|
||||||
|
uint8* p = cstring;
|
||||||
|
for (; *p != '\0'; ++p)
|
||||||
|
;
|
||||||
|
length = (uint64)(p - cstring);
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint64 cstring16_length(uint16* cstring)
|
||||||
|
{
|
||||||
|
uint64 length = 0;
|
||||||
|
if (cstring)
|
||||||
|
{
|
||||||
|
uint16* p = cstring;
|
||||||
|
for (; *p != '\0'; ++p)
|
||||||
|
;
|
||||||
|
length = (uint64)(p - cstring);
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint64 cstring32_length(uint32* cstring)
|
||||||
|
{
|
||||||
|
uint64 length = 0;
|
||||||
|
if (cstring)
|
||||||
|
{
|
||||||
|
uint32* p = cstring;
|
||||||
|
for (; *p != '\0'; ++p)
|
||||||
|
;
|
||||||
|
length = (uint64)(p - cstring);
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================== //
|
||||||
|
// String Constructor
|
||||||
|
|
||||||
|
internal String8 str8(uint8* str, uint64 size)
|
||||||
|
{
|
||||||
|
String8 result = { str, size };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8 str8_zero()
|
||||||
|
{
|
||||||
|
String8 result = { 0 };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String16 str16(uint16* str, uint64 size)
|
||||||
|
{
|
||||||
|
String16 result = { str, size };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String16 str16_zero()
|
||||||
|
{
|
||||||
|
String16 result = { 0 };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8 str8_cstring(const char* cstring)
|
||||||
|
{
|
||||||
|
String8 result = { (uint8*)cstring, cstring8_length((uint8*)cstring) };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String16 str16_cstring(uint16* cstring)
|
||||||
|
{
|
||||||
|
String16 result = { (uint16*)cstring, cstring16_length((uint16*)cstring) };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String32 str32_cstring(uint32* cstring)
|
||||||
|
{
|
||||||
|
String32 result = { (uint32*)cstring, cstring32_length((uint32*)cstring) };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String Matching
|
||||||
|
|
||||||
|
internal bool32 str8_match(String8 a, String8 b, StringMatchFlags flags)
|
||||||
|
{
|
||||||
|
bool32 result = 0;
|
||||||
|
if (a.size == b.size && flags == 0)
|
||||||
|
{
|
||||||
|
result = MemIsEqual(a.str, b.str, b.size);
|
||||||
|
}
|
||||||
|
else if (a.size == b.size && flags == StringMatchFlag_CaseInsensitive)
|
||||||
|
{
|
||||||
|
result = MemCompareI(a.str, b.str, a.size) == 0;
|
||||||
|
}
|
||||||
|
else if (a.size == b.size || (flags * StringMatchFlag_RightSideSloppy))
|
||||||
|
{
|
||||||
|
bool32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive);
|
||||||
|
bool32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive);
|
||||||
|
uint64 size = Min(a.size, b.size);
|
||||||
|
result = 1;
|
||||||
|
for EachIndex(i, size)
|
||||||
|
{
|
||||||
|
uint8 at = a.str[i];
|
||||||
|
uint8 bt = b.str[i];
|
||||||
|
if (case_insensitive)
|
||||||
|
{
|
||||||
|
at = upper_from_char(at);
|
||||||
|
bt = upper_from_char(bt);
|
||||||
|
}
|
||||||
|
if (slash_insensitive)
|
||||||
|
{
|
||||||
|
at = correct_slash_from_char(at);
|
||||||
|
bt = correct_slash_from_char(bt);
|
||||||
|
}
|
||||||
|
if (at != bt)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String Formatting & Copying
|
||||||
|
|
||||||
|
internal String8 str8_copy(Arena* arena, String8 in)
|
||||||
|
{
|
||||||
|
String8 str;
|
||||||
|
str.size = in.size;
|
||||||
|
str.str = push_array_no_zero(arena, uint8, str.size + 1);
|
||||||
|
MemoryCopy(str.str, in.str, in.size);
|
||||||
|
str.str[str.size] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8 str8fv(Arena* arena, char* fmt, va_list args)
|
||||||
|
{
|
||||||
|
va_list args2;
|
||||||
|
va_copy(args2, args);
|
||||||
|
uint32 needed_bytes = juliet_vsnprintf(0, 0, fmt, args) + 1;
|
||||||
|
String8 result = { 0 };
|
||||||
|
result.str = push_array_no_zero(arena, uint8, needed_bytes);
|
||||||
|
result.size = juliet_vsnprintf((char*)result.str, needed_bytes, fmt, args2);
|
||||||
|
result.str[result.size] = '\0';
|
||||||
|
va_end(args2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Unicode String Encode/Decode
|
||||||
|
|
||||||
|
read_only global uint8 utf8_class[32] = {
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
internal UnicodeDecode utf8_decode(uint8* str, uint64 max)
|
||||||
|
{
|
||||||
|
UnicodeDecode result = { 1, max_uint32 };
|
||||||
|
uint8 byte = str[0];
|
||||||
|
uint8 byte_class = utf8_class[byte >> 3];
|
||||||
|
switch (byte_class)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
result.codepoint = byte;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
if (1 < max)
|
||||||
|
{
|
||||||
|
uint8 cont_byte = str[1];
|
||||||
|
if (utf8_class[cont_byte >> 3] == 0)
|
||||||
|
{
|
||||||
|
result.codepoint = (byte & bitmask5) << 6;
|
||||||
|
result.codepoint |= (cont_byte & bitmask6);
|
||||||
|
result.increment = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
if (2 < max)
|
||||||
|
{
|
||||||
|
uint8 cont_byte[2] = { str[1], str[2] };
|
||||||
|
if (utf8_class[cont_byte[0] >> 3] == 0 && utf8_class[cont_byte[1] >> 3] == 0)
|
||||||
|
{
|
||||||
|
result.codepoint = (byte & bitmask4) << 12;
|
||||||
|
result.codepoint |= ((cont_byte[0] & bitmask6) << 6);
|
||||||
|
result.codepoint |= (cont_byte[1] & bitmask6);
|
||||||
|
result.increment = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
if (3 < max)
|
||||||
|
{
|
||||||
|
uint8 cont_byte[3] = { str[1], str[2], str[3] };
|
||||||
|
if (utf8_class[cont_byte[0] >> 3] == 0 && utf8_class[cont_byte[1] >> 3] == 0 && utf8_class[cont_byte[2] >> 3] == 0)
|
||||||
|
{
|
||||||
|
result.codepoint = (byte & bitmask3) << 18;
|
||||||
|
result.codepoint |= ((cont_byte[0] & bitmask6 << 12));
|
||||||
|
result.codepoint |= ((cont_byte[1] & bitmask6) << 6);
|
||||||
|
result.codepoint |= (cont_byte[2] & bitmask6);
|
||||||
|
result.increment = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal UnicodeDecode utf16_decode(uint16* str, uint64 max)
|
||||||
|
{
|
||||||
|
UnicodeDecode result = { 1, max_uint32 };
|
||||||
|
result.codepoint = str[0];
|
||||||
|
result.increment = 1;
|
||||||
|
if (max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000)
|
||||||
|
{
|
||||||
|
result.codepoint = ((str[0] - 0xD800) << 10) | ((str[1] - 0xDC00) + 0x10000);
|
||||||
|
result.increment = 2;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint32 utf8_encode(uint8* str, uint32 codepoint)
|
||||||
|
{
|
||||||
|
uint32 increment = 0;
|
||||||
|
if (codepoint <= 0x7f)
|
||||||
|
{
|
||||||
|
str[0] = (uint8)codepoint;
|
||||||
|
increment = 1;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0x7FF)
|
||||||
|
{
|
||||||
|
str[0] = (bitmask2 << 6) | ((codepoint >> 6) & bitmask5);
|
||||||
|
str[1] = bit8 | (codepoint & bitmask6);
|
||||||
|
increment = 2;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xFFFF)
|
||||||
|
{
|
||||||
|
str[0] = (bitmask3 << 5) | ((codepoint >> 12) & bitmask4);
|
||||||
|
str[1] = bit8 | ((codepoint >> 6) & bitmask6);
|
||||||
|
str[2] = bit8 | (codepoint & bitmask6);
|
||||||
|
increment = 3;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0x10FFFF)
|
||||||
|
{
|
||||||
|
str[0] = (bitmask4 << 4) | ((codepoint >> 18) & bitmask3);
|
||||||
|
str[1] = bit8 | ((codepoint >> 12) & bitmask6);
|
||||||
|
str[2] = bit8 | (codepoint >> 6 & bitmask6);
|
||||||
|
str[3] = bit8 | (codepoint & bitmask6);
|
||||||
|
increment = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str[0] = '?';
|
||||||
|
increment = 1;
|
||||||
|
}
|
||||||
|
return increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal uint32 utf16_encode(uint16* str, uint32 codepoint)
|
||||||
|
{
|
||||||
|
uint32 increment = 1;
|
||||||
|
if (codepoint == max_uint32)
|
||||||
|
{
|
||||||
|
str[0] = (uint16)'?';
|
||||||
|
}
|
||||||
|
else if (codepoint < 0x10000)
|
||||||
|
{
|
||||||
|
str[0] = (uint16)codepoint;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32 v = codepoint - 0x10000;
|
||||||
|
str[0] = safe_cast_uint16(0xD800 + (v >> 10));
|
||||||
|
str[1] = safe_cast_uint16(0xDC00 + (v & bitmask10));
|
||||||
|
increment = 2;
|
||||||
|
}
|
||||||
|
return increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Unicode String Conversions
|
||||||
|
|
||||||
|
internal String8 str8_from_16(Arena* arena, String16 in)
|
||||||
|
{
|
||||||
|
String8 result = str8_zero();
|
||||||
|
if (in.size)
|
||||||
|
{
|
||||||
|
uint64 capacity = in.size * 3;
|
||||||
|
uint8* str = push_array_no_zero(arena, uint8, capacity + 1);
|
||||||
|
uint16* ptr = in.str;
|
||||||
|
uint16* opl = ptr + in.size;
|
||||||
|
uint64 size = 0;
|
||||||
|
UnicodeDecode consume;
|
||||||
|
for (; ptr < opl; ptr += consume.increment)
|
||||||
|
{
|
||||||
|
consume = utf16_decode(ptr, opl - ptr);
|
||||||
|
size += utf8_encode(str + size, consume.codepoint);
|
||||||
|
}
|
||||||
|
str[size] = '\0';
|
||||||
|
arena_pop(arena, (capacity - size));
|
||||||
|
result = str8(str, size);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String16 str16_from_8(Arena* arena, String8 in)
|
||||||
|
{
|
||||||
|
String16 result = str16_zero();
|
||||||
|
if (in.size)
|
||||||
|
{
|
||||||
|
uint64 capacity = in.size * 2;
|
||||||
|
uint16* str = push_array_no_zero(arena, uint16, capacity + 1);
|
||||||
|
uint8* ptr = in.str;
|
||||||
|
uint8* opl = ptr + in.size;
|
||||||
|
uint64 size = 0;
|
||||||
|
UnicodeDecode consume;
|
||||||
|
for (; ptr < opl; ptr += consume.increment)
|
||||||
|
{
|
||||||
|
consume = utf8_decode(ptr, opl - ptr);
|
||||||
|
size += utf16_encode(str + size, consume.codepoint);
|
||||||
|
}
|
||||||
|
str[size] = '\0';
|
||||||
|
arena_pop(arena, (capacity - size) * 2);
|
||||||
|
result = str16(str, size);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String Types
|
||||||
|
|
||||||
|
typedef struct String8 String8;
|
||||||
|
struct String8
|
||||||
|
{
|
||||||
|
uint8* str;
|
||||||
|
uint64 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct String16 String16;
|
||||||
|
struct String16
|
||||||
|
{
|
||||||
|
uint16* str;
|
||||||
|
uint64 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct String32 String32;
|
||||||
|
struct String32
|
||||||
|
{
|
||||||
|
uint32* str;
|
||||||
|
uint64 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String Matching Types
|
||||||
|
|
||||||
|
typedef uint32 StringMatchFlags;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
StringMatchFlag_CaseInsensitive = (1 << 0),
|
||||||
|
StringMatchFlag_RightSideSloppy = (1 << 1),
|
||||||
|
StringMatchFlag_SlashInsensitive = (1 << 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Unicode decoding Types
|
||||||
|
|
||||||
|
typedef struct UnicodeDecode UnicodeDecode;
|
||||||
|
struct UnicodeDecode
|
||||||
|
{
|
||||||
|
uint32 increment;
|
||||||
|
uint32 codepoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String conversions
|
||||||
|
|
||||||
|
internal bool32 char_is_upper(uint8 c);
|
||||||
|
internal bool32 char_is_lower(uint8 c);
|
||||||
|
internal bool32 char_is_slash(uint8 c);
|
||||||
|
internal uint8 lower_from_char(uint8 c);
|
||||||
|
internal uint8 upper_from_char(uint8 c);
|
||||||
|
internal uint8 correct_slash_from_char(uint8 c);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String Length
|
||||||
|
|
||||||
|
internal uint64 cstring8_length(uint8* cstring);
|
||||||
|
internal uint64 cstring16_length(uint16* cstring);
|
||||||
|
internal uint64 cstring32_length(uint32* cstring);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String Constructor
|
||||||
|
|
||||||
|
#define str8_literal(S) str8((uint8*)(S), sizeof(S) - 1)
|
||||||
|
|
||||||
|
#define str8_struct(S) str8((uint8*)(S), sizeof(*(S)))
|
||||||
|
|
||||||
|
internal String8 str8(uint8* str, uint64 size);
|
||||||
|
internal String8 str8_zero();
|
||||||
|
internal String16 str16(uint16* str, uint64 size);
|
||||||
|
internal String16 str16_zero();
|
||||||
|
internal String8 str8_cstring(const char* cstring);
|
||||||
|
internal String16 str16_cstring(uint16* cstring);
|
||||||
|
internal String32 str32_cstring(uint32* cstring);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String Matching
|
||||||
|
|
||||||
|
internal bool32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
||||||
|
#define str8_matchi(a, b) str8_match(a, b, StringMatchFlag_CaseInsensitive)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// String Formatting & Copying
|
||||||
|
|
||||||
|
internal String8 str8_copy(Arena* arena, String8 in);
|
||||||
|
internal String8 str8fv(Arena* arena, char* fmt, va_list args);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Unicode String Encode/Decode
|
||||||
|
|
||||||
|
internal UnicodeDecode utf8_decode(uint8* str, uint64 max);
|
||||||
|
internal UnicodeDecode utf16_decode(uint16* str, uint64 max);
|
||||||
|
internal uint32 utf8_encode(uint8* str, uint32 codepoint);
|
||||||
|
internal uint32 utf16_encode(uint16* str, uint32 codepoint);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Unicode String Conversions
|
||||||
|
|
||||||
|
internal String8 str8_from_16(Arena* arena, String16 in);
|
||||||
|
internal String16 str16_from_8(Arena* arena, String8 in);
|
||||||
@@ -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,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Synchronization primitives types
|
||||||
|
|
||||||
|
typedef struct RWMutex RWMutex;
|
||||||
|
struct RWMutex
|
||||||
|
{
|
||||||
|
uint64 handle[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Thread Info Helpers
|
||||||
|
internal void set_thread_name(String8 name);
|
||||||
|
internal void set_thread_namef(char* fmt, ...);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Thread Info
|
||||||
|
|
||||||
|
internal uint32 tid();
|
||||||
|
internal void set_platform_thread_name(String8 name);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Synchronization primitive functions
|
||||||
|
|
||||||
|
// Read Write Mutexes functions
|
||||||
|
|
||||||
|
internal RWMutex rw_mutex_alloc();
|
||||||
|
internal void rw_mutex_release(RWMutex mutex);
|
||||||
|
internal void rw_mutex_take(RWMutex mutex, bool32 write_mode);
|
||||||
|
internal void rw_mutex_drop(RWMutex mutex, bool32 write_mode);
|
||||||
|
#define rw_mutex_take_r(m) rw_mutex_take((m), (0))
|
||||||
|
#define rw_mutex_take_w(m) rw_mutex_take((m), (1))
|
||||||
|
#define rw_mutex_drop_r(m) rw_mutex_drop((m), (0))
|
||||||
|
#define rw_mutex_drop_w(m) rw_mutex_drop((m), (1))
|
||||||
|
|
||||||
|
// Scope macros
|
||||||
|
#define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex))
|
||||||
|
#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex))
|
||||||
Vendored
+4285
File diff suppressed because it is too large.
Load diff
+1
Submodule Juliet/external/stb_sprintf added at 2ffb3379e8.
+1
Submodule Juliet/external/xxHash added at c87183a77d.
@@ -0,0 +1,303 @@
|
|||||||
|
internal void ja_init()
|
||||||
|
{
|
||||||
|
Arena* arena = arena_alloc();
|
||||||
|
ja_state = push_array(arena, JA_State, 1);
|
||||||
|
ja_state->arena = arena;
|
||||||
|
|
||||||
|
// Window cache
|
||||||
|
{
|
||||||
|
ja_state->window_request_gen_id = 1;
|
||||||
|
ja_state->window_state_slots_count = 64;
|
||||||
|
ja_state->window_state_slots = push_array(arena, JA_WindowStateSlot, ja_state->window_state_slots_count);
|
||||||
|
ja_state->first_window_state = ja_state->last_window_state = &ja_nil_window_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create window requests (2 for testing)
|
||||||
|
{
|
||||||
|
ja_window_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ja_frame()
|
||||||
|
{
|
||||||
|
TempArena scratch = scratch_begin(0, 0);
|
||||||
|
ja_state->frame_depth += 1;
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Events from os
|
||||||
|
WM_EventList events = { 0 };
|
||||||
|
if (ja_state->frame_depth == 1)
|
||||||
|
{
|
||||||
|
bool32 wait = 0;
|
||||||
|
events = wm_get_events(scratch.arena, wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Consume events
|
||||||
|
{
|
||||||
|
if (wm_key_press(&events, wm_window_zero(), 0, WM_Key_F1))
|
||||||
|
{
|
||||||
|
ja_window_request();
|
||||||
|
}
|
||||||
|
for (WM_Event *event = events.first, *next = 0; event != 0; event = next)
|
||||||
|
{
|
||||||
|
JA_WindowState* ws = ja_window_state_from_platform_handle(event->window);
|
||||||
|
bool32 take = 0;
|
||||||
|
if (event->kind == WM_EventKind_WindowClose)
|
||||||
|
{
|
||||||
|
if (ws != 0)
|
||||||
|
{
|
||||||
|
JA_WindowRequest* request = ja_window_request_from_id(ws->id);
|
||||||
|
AssertAlways(request != 0);
|
||||||
|
ja_window_close_request(request);
|
||||||
|
|
||||||
|
if (ja_state->window_request_count == 0)
|
||||||
|
{
|
||||||
|
ja_state->quit = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ja_state->quit = 1;
|
||||||
|
}
|
||||||
|
take = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (take)
|
||||||
|
{
|
||||||
|
wm_eat_event(&events, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window management (open/render)
|
||||||
|
{
|
||||||
|
for EachNode(request, JA_WindowRequest, ja_state->window_request_first)
|
||||||
|
{
|
||||||
|
JA_WindowState* ws = ja_window_state_from_id(request->id);
|
||||||
|
|
||||||
|
// Will render here but for now just increase frame num
|
||||||
|
ws->frames_alive += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window Garbage collect
|
||||||
|
{
|
||||||
|
for EachIndex(slot_idx, ja_state->window_state_slots_count)
|
||||||
|
{
|
||||||
|
for (JA_WindowState *ws = ja_state->window_state_slots[slot_idx].first, *next; ws != 0; ws = next)
|
||||||
|
{
|
||||||
|
next = ws->hash_next;
|
||||||
|
JA_WindowRequest* request = ja_window_request_from_id(ws->id);
|
||||||
|
if (request == 0 || ja_state->quit)
|
||||||
|
{
|
||||||
|
r_window_unequip(ws->plat_handle, ws->render_handle);
|
||||||
|
wm_window_close(ws->plat_handle);
|
||||||
|
arena_release(ws->arena);
|
||||||
|
DLL_remove_next_prev_zero(&ja_nil_window_state, ja_state->first_window_state,
|
||||||
|
ja_state->last_window_state, ws, order_next, order_previous);
|
||||||
|
DLL_remove_next_prev(ja_state->window_state_slots[slot_idx].first,
|
||||||
|
ja_state->window_state_slots[slot_idx].last, ws, hash_next, hash_previous);
|
||||||
|
SLL_stack_push_next(ja_state->free_window_state, ws, order_next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// render frame
|
||||||
|
r_begin_frame();
|
||||||
|
for (JA_WindowState* w = ja_state->first_window_state; w != &ja_nil_window_state; w = w->order_next)
|
||||||
|
{
|
||||||
|
r_window_begin_frame(w->plat_handle, w->render_handle);
|
||||||
|
r_window_end_frame(w->plat_handle, w->render_handle);
|
||||||
|
}
|
||||||
|
r_end_frame();
|
||||||
|
|
||||||
|
// show window after first frame
|
||||||
|
if (ja_state->frame_depth == 1)
|
||||||
|
{
|
||||||
|
JA_IDList windows_to_show = { 0 };
|
||||||
|
for (JA_WindowState* ws = ja_state->first_window_state; ws != &ja_nil_window_state; ws = ws->order_next)
|
||||||
|
{
|
||||||
|
if (ws->frames_alive == 1)
|
||||||
|
{
|
||||||
|
ja_id_list_push(scratch.arena, &windows_to_show, ws->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for EachNode(node, JA_IDNode, windows_to_show.first)
|
||||||
|
{
|
||||||
|
JA_WindowState* ws = ja_window_state_from_id(node->val);
|
||||||
|
wm_window_first_paint(ws->plat_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ja_state->frame_depth -= 1;
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ja_shutdown()
|
||||||
|
{
|
||||||
|
arena_release(ja_state->arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Id Functions
|
||||||
|
|
||||||
|
internal void ja_id_list_push(Arena* arena, JA_IDList* list, JA_ID id)
|
||||||
|
{
|
||||||
|
JA_IDNode* node = push_array(arena, JA_IDNode, 1);
|
||||||
|
SLL_queue_push(list->first, list->last, node);
|
||||||
|
list->count += 1;
|
||||||
|
node->val = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Window Functions
|
||||||
|
|
||||||
|
internal JA_WindowState* ja_window_state_from_id(JA_ID id)
|
||||||
|
{
|
||||||
|
// scan existing windows
|
||||||
|
JA_WindowState* ws = &ja_nil_window_state;
|
||||||
|
if (id != 0 && id == ja_state->window_state_last_accessed_id && id == ja_state->window_state_last_accessed->id)
|
||||||
|
{
|
||||||
|
ws = ja_state->window_state_last_accessed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint64 hash = uint64_hash_from_string(str8_struct(&id));
|
||||||
|
uint64 slot_idx = hash % ja_state->window_state_slots_count;
|
||||||
|
JA_WindowStateSlot* slot = &ja_state->window_state_slots[slot_idx];
|
||||||
|
for (JA_WindowState* w = slot->first; w != 0; w = w->hash_next)
|
||||||
|
{
|
||||||
|
if (w->id == id)
|
||||||
|
{
|
||||||
|
ws = w;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate / open window if none found for this id
|
||||||
|
if (ws == &ja_nil_window_state)
|
||||||
|
{
|
||||||
|
ws = ja_state->free_window_state;
|
||||||
|
if (ws != 0)
|
||||||
|
{
|
||||||
|
SLL_stack_pop_next(ja_state->free_window_state, order_next);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ws = push_array_no_zero(ja_state->arena, JA_WindowState, 1);
|
||||||
|
}
|
||||||
|
MemoryZeroStruct(ws);
|
||||||
|
|
||||||
|
ws->id = id;
|
||||||
|
ws->arena = arena_alloc();
|
||||||
|
|
||||||
|
// hook up the window
|
||||||
|
uint64 hash = uint64_hash_from_string(str8_struct(&id));
|
||||||
|
uint64 slot_idx = hash % ja_state->window_state_slots_count;
|
||||||
|
JA_WindowStateSlot* slot = &ja_state->window_state_slots[slot_idx];
|
||||||
|
DLL_push_back_next_prev_zero(&ja_nil_window_state, ja_state->first_window_state, ja_state->last_window_state,
|
||||||
|
ws, order_next, order_previous);
|
||||||
|
DLL_push_back_next_prev(slot->first, slot->last, ws, hash_next, hash_previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ws != &ja_nil_window_state && wm_window_match(ws->plat_handle, wm_window_zero()))
|
||||||
|
{
|
||||||
|
TempArena scratch = scratch_begin(0, 0);
|
||||||
|
|
||||||
|
ws->frames_alive = 0;
|
||||||
|
|
||||||
|
// TODO: save fav monitor in config
|
||||||
|
WM_Monitor prim_m = wm_primary_monitor();
|
||||||
|
String8 prim_name = wm_name_from_monitor(scratch.arena, prim_m);
|
||||||
|
|
||||||
|
WM_Monitor fav_monitor = { 0 };
|
||||||
|
{
|
||||||
|
WM_MonitorArray monitors = wm_push_monitors_array(scratch.arena);
|
||||||
|
for EachIndex(idx, monitors.count)
|
||||||
|
{
|
||||||
|
String8 monitor_name = wm_name_from_monitor(scratch.arena, monitors.ptr[idx]);
|
||||||
|
if (str8_match(monitor_name, prim_name, StringMatchFlag_CaseInsensitive))
|
||||||
|
{
|
||||||
|
fav_monitor = monitors.ptr[idx];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : put those in config, hardcoded for now
|
||||||
|
String8 title = str8_literal("Juliet");
|
||||||
|
ws->plat_handle = wm_window_open(rect2fp(50.f, 240.f, 1280.f, 720.f), WM_WindowFlag_UseDefaultPosition, title);
|
||||||
|
ws->render_handle = r_window_equip(ws->plat_handle);
|
||||||
|
WM_Monitor zero_monitor = { 0 };
|
||||||
|
if (!wm_monitor_match(zero_monitor, fav_monitor))
|
||||||
|
{
|
||||||
|
wm_window_set_monitor(ws->plat_handle, fav_monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
ja_state->window_state_last_accessed_id = ws->id;
|
||||||
|
ja_state->window_state_last_accessed = ws;
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal JA_WindowState* ja_window_state_from_platform_handle(WM_Window platform_handle)
|
||||||
|
{
|
||||||
|
JA_WindowState* ws = &ja_nil_window_state;
|
||||||
|
{
|
||||||
|
for (JA_WindowState* w_candidate = ja_state->first_window_state; w_candidate != &ja_nil_window_state;
|
||||||
|
w_candidate = w_candidate->order_next)
|
||||||
|
{
|
||||||
|
if (wm_window_match(w_candidate->plat_handle, platform_handle))
|
||||||
|
{
|
||||||
|
ws = w_candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ja_window_request()
|
||||||
|
{
|
||||||
|
JA_ID id = ja_state->window_request_gen_id++;
|
||||||
|
JA_WindowRequest* result = ja_state->free_window_request;
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
SLL_stack_pop(ja_state->free_window_request);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = push_array_no_zero(ja_state->arena, JA_WindowRequest, 1);
|
||||||
|
}
|
||||||
|
result->id = id;
|
||||||
|
DLL_push_back(ja_state->window_request_first, ja_state->window_request_last, result);
|
||||||
|
ja_state->window_request_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ja_window_close_request(JA_WindowRequest* request)
|
||||||
|
{
|
||||||
|
DLL_remove(ja_state->window_request_first, ja_state->window_request_last, request);
|
||||||
|
SLL_stack_push(ja_state->free_window_request, request);
|
||||||
|
|
||||||
|
ja_state->window_request_count -= 1;
|
||||||
|
AssertAlways(ja_state->window_request_count >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal JA_WindowRequest* ja_window_request_from_id(JA_ID id)
|
||||||
|
{
|
||||||
|
JA_WindowRequest* result = 0;
|
||||||
|
for EachNode(wr, JA_WindowRequest, ja_state->window_request_first)
|
||||||
|
{
|
||||||
|
if (wr->id == id)
|
||||||
|
{
|
||||||
|
result = wr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Core Types
|
||||||
|
typedef uint64 JA_ID;
|
||||||
|
|
||||||
|
typedef struct JA_IDNode JA_IDNode;
|
||||||
|
struct JA_IDNode
|
||||||
|
{
|
||||||
|
JA_IDNode* next;
|
||||||
|
JA_ID val;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct JA_IDList JA_IDList;
|
||||||
|
struct JA_IDList
|
||||||
|
{
|
||||||
|
JA_IDNode* first;
|
||||||
|
JA_IDNode* last;
|
||||||
|
uint64 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// States Types
|
||||||
|
|
||||||
|
typedef struct JA_WindowRequest JA_WindowRequest;
|
||||||
|
struct JA_WindowRequest
|
||||||
|
{
|
||||||
|
JA_WindowRequest* next;
|
||||||
|
JA_WindowRequest* previous;
|
||||||
|
JA_ID id;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct JA_WindowState JA_WindowState;
|
||||||
|
struct JA_WindowState
|
||||||
|
{
|
||||||
|
// links and metadata
|
||||||
|
JA_WindowState* order_next;
|
||||||
|
JA_WindowState* order_previous;
|
||||||
|
JA_WindowState* hash_next;
|
||||||
|
JA_WindowState* hash_previous;
|
||||||
|
JA_ID id;
|
||||||
|
uint64 frames_alive;
|
||||||
|
|
||||||
|
// Info and handle
|
||||||
|
Arena* arena;
|
||||||
|
WM_Window plat_handle;
|
||||||
|
R_Handle render_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct JA_WindowStateSlot JA_WindowStateSlot;
|
||||||
|
struct JA_WindowStateSlot
|
||||||
|
{
|
||||||
|
JA_WindowState* first;
|
||||||
|
JA_WindowState* last;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct JA_State JA_State;
|
||||||
|
struct JA_State
|
||||||
|
{
|
||||||
|
// Base
|
||||||
|
Arena* arena;
|
||||||
|
bool32 quit;
|
||||||
|
int32 frame_depth;
|
||||||
|
|
||||||
|
// Windows requests
|
||||||
|
JA_ID window_request_gen_id;
|
||||||
|
JA_WindowRequest* window_request_first;
|
||||||
|
JA_WindowRequest* window_request_last;
|
||||||
|
JA_WindowRequest* free_window_request;
|
||||||
|
uint64 window_request_count;
|
||||||
|
|
||||||
|
// Windows
|
||||||
|
JA_WindowState* free_window_state;
|
||||||
|
uint64 window_state_slots_count;
|
||||||
|
JA_WindowStateSlot* window_state_slots;
|
||||||
|
JA_WindowState* first_window_state;
|
||||||
|
JA_WindowState* last_window_state;
|
||||||
|
JA_ID window_state_last_accessed_id;
|
||||||
|
JA_WindowState* window_state_last_accessed;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Globals
|
||||||
|
|
||||||
|
read_only global JA_WindowState ja_nil_window_state = { &ja_nil_window_state, &ja_nil_window_state };
|
||||||
|
|
||||||
|
global JA_State* ja_state = 0;
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Top level Functions
|
||||||
|
|
||||||
|
internal void ja_init();
|
||||||
|
internal void ja_frame();
|
||||||
|
internal void ja_shutdown();
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Id Functions
|
||||||
|
|
||||||
|
internal void ja_id_list_push(Arena* arena, JA_IDList* list, JA_ID id);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Window Functions
|
||||||
|
|
||||||
|
internal JA_WindowState* ja_window_state_from_id(JA_ID id);
|
||||||
|
internal JA_WindowState* ja_window_state_from_platform_handle(WM_Window platform_handle);
|
||||||
|
internal void ja_window_request();
|
||||||
|
internal void ja_window_close_request(JA_WindowRequest* request);
|
||||||
|
internal JA_WindowRequest* ja_window_request_from_id(JA_ID id);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include "julietapp_core.c"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "julietapp_core.h"
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// clang-format off
|
||||||
|
// ========================================================================= //
|
||||||
|
// Includes
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
#include "core/core_inc.h"
|
||||||
|
#include "shell/shell_inc.h"
|
||||||
|
#include "window_manager/window_manager_inc.h"
|
||||||
|
#include "render/render_inc.h"
|
||||||
|
#include "julietapp/julietapp_inc.h"
|
||||||
|
|
||||||
|
// C
|
||||||
|
#include "core/core_inc.c"
|
||||||
|
#include "shell/shell_inc.c"
|
||||||
|
#include "window_manager/window_manager_inc.c"
|
||||||
|
#include "render/render_inc.c"
|
||||||
|
#include "julietapp/julietapp_inc.c"
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
internal bool32 frame()
|
||||||
|
{
|
||||||
|
ja_frame();
|
||||||
|
return ja_state->quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void entry_point()
|
||||||
|
{
|
||||||
|
wm_init();
|
||||||
|
r_init();
|
||||||
|
ja_init();
|
||||||
|
|
||||||
|
for (bool32 quit = 0; !quit;)
|
||||||
|
{
|
||||||
|
quit = update();
|
||||||
|
}
|
||||||
|
ja_shutdown();
|
||||||
|
r_shutdown();
|
||||||
|
}
|
||||||
@@ -0,0 +1,392 @@
|
|||||||
|
// TODO : Adapt stuff from D3D12GraphicsDevice.c specially all the shenanigans with dxgi factory and stuff
|
||||||
|
// TODO : Support more kind of format (HDR)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
internal R_D3D12_Window* r_d3d12_window_from_handle(R_Handle handle)
|
||||||
|
{
|
||||||
|
R_D3D12_Window* window = (R_D3D12_Window*)handle.u64[0];
|
||||||
|
if (window == 0)
|
||||||
|
{
|
||||||
|
window = &r_d3d12_nil_window;
|
||||||
|
}
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal R_Handle r_d3d12_handle_from_window(R_D3D12_Window* window)
|
||||||
|
{
|
||||||
|
R_Handle handle = { 0 };
|
||||||
|
handle.u64[0] = (uint64)window;
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Wait Function
|
||||||
|
|
||||||
|
internal void r_d3d12_wait()
|
||||||
|
{
|
||||||
|
r_d3d12_state->fence_value += 1;
|
||||||
|
ID3D12CommandQueue_Signal(r_d3d12_state->direct_command_queue, r_d3d12_state->fence, r_d3d12_state->fence_value);
|
||||||
|
if (ID3D12Fence_GetCompletedValue(r_d3d12_state->fence) < r_d3d12_state->fence_value)
|
||||||
|
{
|
||||||
|
ID3D12Fence_SetEventOnCompletion(r_d3d12_state->fence, r_d3d12_state->fence_value, r_d3d12_state->fence_event);
|
||||||
|
WaitForSingleObject(r_d3d12_state->fence_event, INFINITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// top level layer initialization
|
||||||
|
|
||||||
|
void r_init()
|
||||||
|
{
|
||||||
|
HRESULT error = 0;
|
||||||
|
Arena* arena = arena_alloc();
|
||||||
|
r_d3d12_state = push_array(arena, R_D3D12_State, 1);
|
||||||
|
r_d3d12_state->arena = arena;
|
||||||
|
r_d3d12_state->device_rw_mutex = rw_mutex_alloc();
|
||||||
|
|
||||||
|
// Create base device
|
||||||
|
D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_12_1;
|
||||||
|
|
||||||
|
UINT dxgi_flags = 0;
|
||||||
|
#if BUILD_DEBUG
|
||||||
|
ID3D12Debug1* debug_controller = 0;
|
||||||
|
if (SUCCEEDED(D3D12GetDebugInterface(&IID_ID3D12Debug1, (void**)&debug_controller)))
|
||||||
|
{
|
||||||
|
ID3D12Debug1_EnableDebugLayer(debug_controller);
|
||||||
|
ID3D12Debug1_SetEnableGPUBasedValidation(debug_controller, TRUE);
|
||||||
|
ID3D12Debug1_Release(debug_controller);
|
||||||
|
}
|
||||||
|
dxgi_flags |= DXGI_CREATE_FACTORY_DEBUG;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
error = CreateDXGIFactory2(dxgi_flags, &IID_IDXGIFactory4, (void**)&r_d3d12_state->dxgi_factory);
|
||||||
|
if (FAILED(error))
|
||||||
|
{
|
||||||
|
char buffer[256] = { 0 };
|
||||||
|
juliet_snprintf(buffer, sizeof(buffer), "D3D12 DXGI factory creation failure (%lx). Process is terminating", error);
|
||||||
|
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
|
||||||
|
abort_self(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dxgi setup (device and adapter)
|
||||||
|
IDXGIFactory6* factory6 = 0;
|
||||||
|
error = IDXGIFactory4_QueryInterface(r_d3d12_state->dxgi_factory, &IID_IDXGIFactory6, (void**)&factory6);
|
||||||
|
if (SUCCEEDED(error))
|
||||||
|
{
|
||||||
|
// Prioritize discrete GPU
|
||||||
|
error = IDXGIFactory6_EnumAdapterByGpuPreference(factory6, 0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
|
||||||
|
&IID_IDXGIAdapter1, (void**)&r_d3d12_state->dxgi_adapter);
|
||||||
|
IDXGIFactory6_Release(factory6);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Pray device 0 is the discrete gpu
|
||||||
|
error = IDXGIFactory4_EnumAdapters1(r_d3d12_state->dxgi_factory, 0, &r_d3d12_state->dxgi_adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = D3D12CreateDevice((IUnknown*)r_d3d12_state->dxgi_adapter, feature_level, &IID_ID3D12Device4,
|
||||||
|
(void**)&r_d3d12_state->device);
|
||||||
|
|
||||||
|
// Try warp as hardware is no available
|
||||||
|
if (FAILED(error))
|
||||||
|
{
|
||||||
|
IDXGIAdapter1_Release(r_d3d12_state->dxgi_adapter);
|
||||||
|
error = IDXGIFactory4_EnumWarpAdapter(r_d3d12_state->dxgi_factory, &IID_IDXGIAdapter, (void**)&r_d3d12_state->dxgi_adapter);
|
||||||
|
if (SUCCEEDED(error))
|
||||||
|
{
|
||||||
|
error = D3D12CreateDevice((IUnknown*)r_d3d12_state->dxgi_adapter, feature_level, &IID_ID3D12Device4,
|
||||||
|
(void**)&r_d3d12_state->device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(error))
|
||||||
|
{
|
||||||
|
char buffer[256] = { 0 };
|
||||||
|
juliet_snprintf(buffer, sizeof(buffer), "D3D12 device factory creation failure (%lx). Process is terminating", error);
|
||||||
|
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
|
||||||
|
abort_self(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// break on error
|
||||||
|
#if BUILD_DEBUG
|
||||||
|
ID3D12InfoQueue* info = 0;
|
||||||
|
error = ID3D12Device4_QueryInterface(r_d3d12_state->device, &IID_ID3D12InfoQueue, (void**)&info);
|
||||||
|
if (SUCCEEDED(error))
|
||||||
|
{
|
||||||
|
error = ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
|
||||||
|
error = ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
|
||||||
|
ID3D12InfoQueue_Release(info);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create basic graphics queue
|
||||||
|
D3D12_COMMAND_QUEUE_DESC queue_desc = { 0 };
|
||||||
|
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
|
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||||
|
error = ID3D12Device4_CreateCommandQueue(r_d3d12_state->device, &queue_desc, &IID_ID3D12CommandQueue,
|
||||||
|
(void**)&r_d3d12_state->direct_command_queue);
|
||||||
|
if (FAILED(error))
|
||||||
|
{
|
||||||
|
char buffer[256] = { 0 };
|
||||||
|
juliet_snprintf(buffer, sizeof(buffer), "D3D12 direct command queue creation failure (%lx). Process is terminating", error);
|
||||||
|
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
|
||||||
|
abort_self(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create command allocator and command list
|
||||||
|
for EachIndex(i, 2)
|
||||||
|
{
|
||||||
|
ID3D12Device4_CreateCommandAllocator(r_d3d12_state->device, D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||||
|
&IID_ID3D12CommandAllocator, (void**)&r_d3d12_state->command_allocators[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D12Device4_CreateCommandList1(r_d3d12_state->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_LIST_FLAG_NONE,
|
||||||
|
&IID_ID3D12GraphicsCommandList, (void**)&r_d3d12_state->command_list);
|
||||||
|
|
||||||
|
ID3D12Device4_CreateFence(r_d3d12_state->device, 0, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, (void**)&r_d3d12_state->fence);
|
||||||
|
r_d3d12_state->fence_event = CreateEventW(0, FALSE, FALSE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void r_shutdown()
|
||||||
|
{
|
||||||
|
MutexScopeW(r_d3d12_state->device_rw_mutex)
|
||||||
|
{
|
||||||
|
r_d3d12_wait();
|
||||||
|
|
||||||
|
CloseHandle(r_d3d12_state->fence_event);
|
||||||
|
ID3D12Fence_Release(r_d3d12_state->fence);
|
||||||
|
for EachIndex(i,2)
|
||||||
|
{
|
||||||
|
ID3D12CommandAllocator_Release(r_d3d12_state->command_allocators[i]);
|
||||||
|
}
|
||||||
|
ID3D12CommandList_Release(r_d3d12_state->command_list);
|
||||||
|
ID3D12CommandQueue_Release(r_d3d12_state->direct_command_queue);
|
||||||
|
ID3D12Device4_Release(r_d3d12_state->device);
|
||||||
|
IDXGIAdapter1_Release(r_d3d12_state->dxgi_adapter);
|
||||||
|
IDXGIFactory4_Release(r_d3d12_state->dxgi_factory);
|
||||||
|
}
|
||||||
|
rw_mutex_release(r_d3d12_state->device_rw_mutex);
|
||||||
|
arena_release(r_d3d12_state->arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// window setup/teardown
|
||||||
|
|
||||||
|
R_Handle r_window_equip(WM_Window handle)
|
||||||
|
{
|
||||||
|
R_Handle result = { 0 };
|
||||||
|
|
||||||
|
MutexScopeW(r_d3d12_state->device_rw_mutex)
|
||||||
|
{
|
||||||
|
R_D3D12_Window* window = r_d3d12_state->first_free_window;
|
||||||
|
if (window != 0)
|
||||||
|
{
|
||||||
|
SLL_stack_pop(r_d3d12_state->first_free_window);
|
||||||
|
MemoryZeroStruct(window);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window = push_array(r_d3d12_state->arena, R_D3D12_Window, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND hwnd = { 0 };
|
||||||
|
{
|
||||||
|
W32_WM_Window* w32_layer_window = w32_wm_window_from_handle(handle);
|
||||||
|
hwnd = w32_wm_hwnd_from_window(w32_layer_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create swapchain
|
||||||
|
DXGI_SWAP_CHAIN_DESC1 swapchain_desc = { 0 };
|
||||||
|
swapchain_desc.Width = 0; // Use all window width
|
||||||
|
swapchain_desc.Height = 0; // Use all window height
|
||||||
|
swapchain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
swapchain_desc.Stereo = 0;
|
||||||
|
swapchain_desc.SampleDesc.Count = 1;
|
||||||
|
swapchain_desc.SampleDesc.Quality = 0;
|
||||||
|
swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||||
|
swapchain_desc.BufferCount = 2; // Double buffering
|
||||||
|
swapchain_desc.Scaling = DXGI_SCALING_NONE;
|
||||||
|
swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||||
|
swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
||||||
|
swapchain_desc.Flags = 0;
|
||||||
|
|
||||||
|
DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapchain_fullscreen_desc = { 0 };
|
||||||
|
swapchain_fullscreen_desc.RefreshRate.Numerator = 0;
|
||||||
|
swapchain_fullscreen_desc.RefreshRate.Denominator = 0;
|
||||||
|
swapchain_fullscreen_desc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
||||||
|
swapchain_fullscreen_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||||
|
swapchain_fullscreen_desc.Windowed = TRUE;
|
||||||
|
|
||||||
|
IDXGISwapChain1* swapchain1 = 0;
|
||||||
|
HRESULT error = IDXGIFactory4_CreateSwapChainForHwnd(r_d3d12_state->dxgi_factory,
|
||||||
|
(IUnknown*)r_d3d12_state->direct_command_queue, hwnd,
|
||||||
|
&swapchain_desc, &swapchain_fullscreen_desc, 0, &swapchain1);
|
||||||
|
if (FAILED(error))
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
juliet_snprintf(buffer, sizeof(buffer), "DXGI swap chain creation failure (%lx). Process is terminating.", error);
|
||||||
|
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
|
||||||
|
abort_self(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void**)&window->swapchain);
|
||||||
|
IDXGISwapChain1_Release(swapchain1);
|
||||||
|
|
||||||
|
IDXGIFactory4_MakeWindowAssociation(r_d3d12_state->dxgi_factory, hwnd, DXGI_MWA_NO_ALT_ENTER);
|
||||||
|
|
||||||
|
// Create framebuffer and rtv for swapchain
|
||||||
|
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc = { 0 };
|
||||||
|
rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||||
|
rtv_heap_desc.NumDescriptors = 2;
|
||||||
|
rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||||
|
|
||||||
|
ID3D12Device4_CreateDescriptorHeap(r_d3d12_state->device, &rtv_heap_desc, &IID_ID3D12DescriptorHeap,
|
||||||
|
(void**)&window->rtv_heap);
|
||||||
|
|
||||||
|
UINT rtv_stride = ID3D12Device4_GetDescriptorHandleIncrementSize(r_d3d12_state->device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||||
|
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = { 0 };
|
||||||
|
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(window->rtv_heap, &rtv_handle);
|
||||||
|
|
||||||
|
for (UINT i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
window->rtv_handles[i] = rtv_handle;
|
||||||
|
IDXGISwapChain3_GetBuffer(window->swapchain, i, &IID_ID3D12Resource, (void**)&window->framebuffer[i]);
|
||||||
|
ID3D12Device4_CreateRenderTargetView(r_d3d12_state->device, window->framebuffer[i], 0, window->rtv_handles[i]);
|
||||||
|
rtv_handle.ptr += rtv_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save resolution in case of resize
|
||||||
|
Rect2f client_rect = wm_client_rect_from_window(handle);
|
||||||
|
Vector2i resolution = { (int32)(client_rect.x1 - client_rect.x0), (int32)(client_rect.y1 - client_rect.y0) };
|
||||||
|
window->last_resolution = resolution;
|
||||||
|
|
||||||
|
result = r_d3d12_handle_from_window(window);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r_window_unequip(WM_Window handle, R_Handle handle_equip)
|
||||||
|
{
|
||||||
|
MutexScopeW(r_d3d12_state->device_rw_mutex)
|
||||||
|
{
|
||||||
|
r_d3d12_wait();
|
||||||
|
|
||||||
|
R_D3D12_Window* window = r_d3d12_window_from_handle(handle_equip);
|
||||||
|
if (window != 0 && window != &r_d3d12_nil_window)
|
||||||
|
{
|
||||||
|
for EachIndex(i, 2)
|
||||||
|
{
|
||||||
|
ID3D12Resource_Release(window->framebuffer[i]);
|
||||||
|
}
|
||||||
|
ID3D12DescriptorHeap_Release(window->rtv_heap);
|
||||||
|
IDXGISwapChain1_Release(window->swapchain);
|
||||||
|
SLL_stack_push(r_d3d12_state->first_free_window, window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// frame markers
|
||||||
|
|
||||||
|
void r_begin_frame()
|
||||||
|
{
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
void r_end_frame()
|
||||||
|
{
|
||||||
|
// pouet
|
||||||
|
}
|
||||||
|
|
||||||
|
void r_window_begin_frame(WM_Window window, R_Handle window_equip)
|
||||||
|
{
|
||||||
|
MutexScopeW(r_d3d12_state->device_rw_mutex)
|
||||||
|
{
|
||||||
|
R_D3D12_Window* r_window = r_d3d12_window_from_handle(window_equip);
|
||||||
|
|
||||||
|
// Get resolution
|
||||||
|
Rect2f client_rect = wm_client_rect_from_window(window);
|
||||||
|
Vector2i resolution = { (int32)(client_rect.x1 - client_rect.x0), (int32)(client_rect.y1 - client_rect.y0) };
|
||||||
|
|
||||||
|
// change resolution
|
||||||
|
if (resolution.x > 0 && resolution.y > 0 &&
|
||||||
|
(r_window->last_resolution.x != resolution.x || r_window->last_resolution.y != resolution.y))
|
||||||
|
{
|
||||||
|
r_window->last_resolution = resolution;
|
||||||
|
|
||||||
|
// resize swap chain
|
||||||
|
r_d3d12_wait();
|
||||||
|
|
||||||
|
for EachIndex(i,2)
|
||||||
|
{
|
||||||
|
if (r_window->framebuffer[i] != 0)
|
||||||
|
{
|
||||||
|
ID3D12Resource_Release(r_window->framebuffer[i]);
|
||||||
|
r_window->framebuffer[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IDXGISwapChain3_ResizeBuffers(r_window->swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
|
||||||
|
|
||||||
|
for EachIndex(i,2)
|
||||||
|
{
|
||||||
|
IDXGISwapChain3_GetBuffer(r_window->swapchain, i, &IID_ID3D12Resource, (void**)&r_window->framebuffer[i]);
|
||||||
|
ID3D12Device4_CreateRenderTargetView(r_d3d12_state->device, r_window->framebuffer[i], 0, r_window->rtv_handles[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the command list for that window that frame
|
||||||
|
// TODO : multiple command list as we have multiple windows
|
||||||
|
r_window->framebuffer_idx = IDXGISwapChain3_GetCurrentBackBufferIndex(r_window->swapchain);
|
||||||
|
ID3D12CommandAllocator* allocator = r_d3d12_state->command_allocators[r_window->framebuffer_idx];
|
||||||
|
ID3D12GraphicsCommandList* cmd_list = r_d3d12_state->command_list;
|
||||||
|
|
||||||
|
ID3D12CommandAllocator_Reset(allocator);
|
||||||
|
ID3D12GraphicsCommandList1_Reset(cmd_list, allocator, 0);
|
||||||
|
|
||||||
|
// Barrier to transition from Present (end of frame) to render target
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = { 0 };
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Transition.pResource = r_window->framebuffer[r_window->framebuffer_idx];
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
|
ID3D12GraphicsCommandList_ResourceBarrier(cmd_list, 1, &barrier);
|
||||||
|
|
||||||
|
// HARDCODED
|
||||||
|
// BLUE
|
||||||
|
float32 background[4] = { 0.1f, 0.2f, 0.8f, 1.0f };
|
||||||
|
ID3D12GraphicsCommandList_ClearRenderTargetView(cmd_list, r_window->rtv_handles[r_window->framebuffer_idx],
|
||||||
|
background, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void r_window_end_frame(WM_Window window, R_Handle window_equip)
|
||||||
|
{
|
||||||
|
MutexScopeW(r_d3d12_state->device_rw_mutex)
|
||||||
|
{
|
||||||
|
R_D3D12_Window* r_window = r_d3d12_window_from_handle(window_equip);
|
||||||
|
|
||||||
|
ID3D12GraphicsCommandList* cmd_list = r_d3d12_state->command_list;
|
||||||
|
|
||||||
|
// Transition from render target to present
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = { 0 };
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Transition.pResource = r_window->framebuffer[r_window->framebuffer_idx];
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||||
|
ID3D12GraphicsCommandList_ResourceBarrier(cmd_list, 1, &barrier);
|
||||||
|
|
||||||
|
// Close command list and push it onto the command queue
|
||||||
|
ID3D12GraphicsCommandList_Close(cmd_list);
|
||||||
|
ID3D12CommandQueue_ExecuteCommandLists(r_d3d12_state->direct_command_queue, 1, (ID3D12CommandList**)&cmd_list);
|
||||||
|
|
||||||
|
IDXGISwapChain3_Present(r_window->swapchain, 1, 0);
|
||||||
|
|
||||||
|
// Fence until gpu finishes work
|
||||||
|
r_d3d12_wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
|
#define CINTERFACE
|
||||||
|
#include <d3d12.h>
|
||||||
|
#include <dxgi1_6.h>
|
||||||
|
#undef COBJMACROS
|
||||||
|
#undef CINTERFACE
|
||||||
|
|
||||||
|
#pragma comment(lib, "d3d12")
|
||||||
|
#pragma comment(lib, "dxgi")
|
||||||
|
#pragma comment(lib, "dxguid")
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// D3D12 States Types
|
||||||
|
|
||||||
|
typedef struct R_D3D12_Window R_D3D12_Window;
|
||||||
|
struct R_D3D12_Window
|
||||||
|
{
|
||||||
|
R_D3D12_Window* next;
|
||||||
|
|
||||||
|
// SwapChain and framebuffer
|
||||||
|
IDXGISwapChain3* swapchain;
|
||||||
|
ID3D12Resource* framebuffer[2];
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[2];
|
||||||
|
ID3D12DescriptorHeap* rtv_heap;
|
||||||
|
uint8 framebuffer_idx;
|
||||||
|
|
||||||
|
// last state
|
||||||
|
Vector2i last_resolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct R_D3D12_State R_D3D12_State;
|
||||||
|
struct R_D3D12_State
|
||||||
|
{
|
||||||
|
// states
|
||||||
|
Arena* arena;
|
||||||
|
R_D3D12_Window* first_free_window;
|
||||||
|
RWMutex device_rw_mutex;
|
||||||
|
|
||||||
|
// base d3d12 object
|
||||||
|
ID3D12Device4* device;
|
||||||
|
IDXGIFactory4* dxgi_factory;
|
||||||
|
IDXGIAdapter1* dxgi_adapter;
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
ID3D12CommandQueue* direct_command_queue;
|
||||||
|
ID3D12CommandAllocator* command_allocators[2];
|
||||||
|
ID3D12GraphicsCommandList* command_list;
|
||||||
|
|
||||||
|
// Fence
|
||||||
|
ID3D12Fence* fence;
|
||||||
|
uint64 fence_value;
|
||||||
|
HANDLE fence_event;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Globals
|
||||||
|
|
||||||
|
global R_D3D12_State* r_d3d12_state = 0;
|
||||||
|
global read_only R_D3D12_Window r_d3d12_nil_window = { &r_d3d12_nil_window };
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
internal R_D3D12_Window* r_d3d12_window_from_handle(R_Handle handle);
|
||||||
|
internal R_Handle r_d3d12_handle_from_window(R_D3D12_Window* window);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Wait Function
|
||||||
|
|
||||||
|
internal void r_d3d12_wait();
|
||||||
Whitespace-only changes.
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Handle type
|
||||||
|
|
||||||
|
typedef union R_Handle R_Handle;
|
||||||
|
union R_Handle
|
||||||
|
{
|
||||||
|
uint64 u64[1];
|
||||||
|
uint32 u32[2];
|
||||||
|
uint16 u16[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// top level layer initialization
|
||||||
|
void r_init();
|
||||||
|
void r_shutdown();
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// window setup/teardown
|
||||||
|
|
||||||
|
R_Handle r_window_equip(WM_Window window);
|
||||||
|
void r_window_unequip(WM_Window window, R_Handle window_equip);
|
||||||
|
|
||||||
|
// frame markers
|
||||||
|
|
||||||
|
void r_begin_frame();
|
||||||
|
void r_end_frame();
|
||||||
|
void r_window_begin_frame(WM_Window window, R_Handle window_equip);
|
||||||
|
void r_window_end_frame(WM_Window window, R_Handle window_equip);
|
||||||
@@ -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
|
||||||
Whitespace-only changes.
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Shell operations
|
||||||
|
|
||||||
|
internal void sh_message(bool32 error, String8 title, String8 message);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include "shell.c"
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# include "win32/shell/win32_shell.c"
|
||||||
|
#else
|
||||||
|
# error Shell functions not implemented for this operating system
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# include "win32/shell/win32_shell.h"
|
||||||
|
#else
|
||||||
|
# error Shell functions not implemented for this operating system
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDescription);
|
||||||
|
|
||||||
|
#define W32_KERNEL32_EXT_X_LIST X(SetThreadDescription)
|
||||||
|
|
||||||
|
#define X(x) global W32_##x##_Type* w32_##x##_func;
|
||||||
|
W32_KERNEL32_EXT_X_LIST
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Entity Functions
|
||||||
|
|
||||||
|
internal W32_Entity* w32_entity_alloc(W32_EntityKind kind)
|
||||||
|
{
|
||||||
|
W32_Entity* result = 0;
|
||||||
|
EnterCriticalSection(&w32_state.entity_mutex);
|
||||||
|
{
|
||||||
|
result = w32_state.entity_free;
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
SLL_stack_pop(w32_state.entity_free);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = push_array_no_zero(w32_state.entity_arena, W32_Entity, 1);
|
||||||
|
}
|
||||||
|
MemoryZeroStruct(result);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&w32_state.entity_mutex);
|
||||||
|
result->kind = kind;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void w32_entity_release(W32_Entity* entity)
|
||||||
|
{
|
||||||
|
entity->kind = W32_EntityKind_Null;
|
||||||
|
EnterCriticalSection(&w32_state.entity_mutex);
|
||||||
|
SLL_stack_push(w32_state.entity_free, entity);
|
||||||
|
LeaveCriticalSection(&w32_state.entity_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Time functions
|
||||||
|
|
||||||
|
internal uint64 now_time_us()
|
||||||
|
{
|
||||||
|
uint64 result = 0;
|
||||||
|
LARGE_INTEGER large_int_counter;
|
||||||
|
if (QueryPerformanceCounter(&large_int_counter))
|
||||||
|
{
|
||||||
|
result = (large_int_counter.QuadPart * Million(1)) / w32_state.microsecond_resolution;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void sleep_ms(uint32 ms)
|
||||||
|
{
|
||||||
|
Sleep(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// System
|
||||||
|
|
||||||
|
internal SystemInfo* get_system_info()
|
||||||
|
{
|
||||||
|
return &w32_state.system_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Thread Info
|
||||||
|
|
||||||
|
internal uint32 tid()
|
||||||
|
{
|
||||||
|
DWORD id = GetCurrentThreadId();
|
||||||
|
return (uint32)id;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void set_platform_thread_name(String8 name)
|
||||||
|
{
|
||||||
|
TempArena scratch = scratch_begin(0, 0);
|
||||||
|
|
||||||
|
// Win10 and +
|
||||||
|
if (w32_SetThreadDescription_func)
|
||||||
|
{
|
||||||
|
String16 name16 = str16_from_8(scratch.arena, name);
|
||||||
|
HRESULT hr = w32_SetThreadDescription_func(GetCurrentThread(), (WCHAR*)name16.str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Old way by raising exception
|
||||||
|
{
|
||||||
|
String8 name_copy = str8_copy(scratch.arena, name);
|
||||||
|
#pragma pack(push, 8)
|
||||||
|
typedef struct THREADNAME_INFO THREADNAME_INFO;
|
||||||
|
struct THREADNAME_INFO
|
||||||
|
{
|
||||||
|
uint32 dwType; // Must be 0x1000.
|
||||||
|
char* szName; // Pointer to name (in user addr space).
|
||||||
|
uint32 dwThreadID; // Thread ID (-1=caller thread).
|
||||||
|
uint32 dwFlags; // Reserved for future use, must be zero.
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
THREADNAME_INFO info;
|
||||||
|
info.dwType = 0x1000;
|
||||||
|
info.szName = (char*)name_copy.str;
|
||||||
|
info.dwThreadID = tid();
|
||||||
|
info.dwFlags = 0;
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 6320 6322)
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void*), (const ULONG_PTR*)&info);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#pragma warning(pop)
|
||||||
|
}
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Synchronization primitive functions
|
||||||
|
|
||||||
|
// read write mutexes
|
||||||
|
|
||||||
|
internal RWMutex rw_mutex_alloc()
|
||||||
|
{
|
||||||
|
W32_Entity* entity = w32_entity_alloc(W32_EntityKind_RWMutex);
|
||||||
|
InitializeSRWLock(&entity->rw_mutex);
|
||||||
|
RWMutex result = { IntFromPtr(entity) };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void rw_mutex_release(RWMutex rw_mutex)
|
||||||
|
{
|
||||||
|
W32_Entity* entity = (W32_Entity*)PtrFromInt(rw_mutex.handle[0]);
|
||||||
|
w32_entity_release(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void rw_mutex_take(RWMutex rw_mutex, bool32 write_mode)
|
||||||
|
{
|
||||||
|
W32_Entity* entity = (W32_Entity*)PtrFromInt(rw_mutex.handle[0]);
|
||||||
|
if (write_mode)
|
||||||
|
{
|
||||||
|
AcquireSRWLockExclusive(&entity->rw_mutex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AcquireSRWLockShared(&entity->rw_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void rw_mutex_drop(RWMutex rw_mutex, bool32 write_mode)
|
||||||
|
{
|
||||||
|
W32_Entity* entity = (W32_Entity*)PtrFromInt(rw_mutex.handle[0]);
|
||||||
|
if (write_mode)
|
||||||
|
{
|
||||||
|
ReleaseSRWLockExclusive(&entity->rw_mutex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReleaseSRWLockShared(&entity->rw_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Memory
|
||||||
|
|
||||||
|
internal void* reserve_memory(uint64 size)
|
||||||
|
{
|
||||||
|
void* result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool32 commit_memory(void* ptr, uint64 size)
|
||||||
|
{
|
||||||
|
bool32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void* reserve_memory_large(uint64 size)
|
||||||
|
{
|
||||||
|
// Windows do not allow commiting large pages
|
||||||
|
void* result = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool32 commit_memory_large(void* ptr, uint64 size)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
(void)size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void decommit_memory(void* ptr, uint64 size)
|
||||||
|
{
|
||||||
|
VirtualFree(ptr, size, MEM_DECOMMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void release_memory(void* ptr, uint64 size)
|
||||||
|
{
|
||||||
|
(void)size; // Unused on windows
|
||||||
|
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Aborting
|
||||||
|
|
||||||
|
internal void abort_self(uint64 exit_code)
|
||||||
|
{
|
||||||
|
ExitProcess((int)exit_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Entry points
|
||||||
|
|
||||||
|
internal void w32_entry_point(int argc, WCHAR** wargv)
|
||||||
|
{
|
||||||
|
// Dynamically load some windows function that are not guaranteed in all sdk
|
||||||
|
{
|
||||||
|
#define X(x) w32_##x##_func = (void*)GetProcAddress(module, Stringify(x));
|
||||||
|
HMODULE module;
|
||||||
|
|
||||||
|
module = LoadLibraryA("kernek32.dll");
|
||||||
|
W32_KERNEL32_EXT_X_LIST
|
||||||
|
FreeLibrary(module);
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSTEM_INFO sys_info = { 0 };
|
||||||
|
GetSystemInfo(&sys_info);
|
||||||
|
|
||||||
|
{
|
||||||
|
w32_state.microsecond_resolution = 1;
|
||||||
|
LARGE_INTEGER large_int_resolution;
|
||||||
|
if (QueryPerformanceCounter(&large_int_resolution))
|
||||||
|
{
|
||||||
|
w32_state.microsecond_resolution = large_int_resolution.QuadPart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemInfo* info = &w32_state.system_info;
|
||||||
|
info->page_size = sys_info.dwPageSize;
|
||||||
|
info->large_page_size = GetLargePageMinimum();
|
||||||
|
|
||||||
|
Arena* args_arena = arena_alloc(.reserve_size = MB(1), .commit_size = KB(32));
|
||||||
|
char** argv = push_array(args_arena, char*, argc);
|
||||||
|
for (int i = 0; i < argc; ++i)
|
||||||
|
{
|
||||||
|
String16 arg16 = str16_cstring((uint16*)wargv[i]);
|
||||||
|
String8 arg8 = str8_from_16(args_arena, arg16);
|
||||||
|
argv[i] = (char*)arg8.str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread context
|
||||||
|
TCTX* tctx = tctx_alloc();
|
||||||
|
tctx_select(tctx);
|
||||||
|
|
||||||
|
// setup w32 state
|
||||||
|
Arena* arena = arena_alloc();
|
||||||
|
{
|
||||||
|
w32_state.arena = arena;
|
||||||
|
{
|
||||||
|
SystemInfo* info = &w32_state.system_info;
|
||||||
|
DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
|
||||||
|
uint8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
|
||||||
|
if (GetComputerNameA((char*)buffer, &size))
|
||||||
|
{
|
||||||
|
info->machine_name = str8_copy(arena, str8(buffer, size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup entity storage
|
||||||
|
InitializeCriticalSection(&w32_state.entity_mutex);
|
||||||
|
w32_state.entity_arena = arena_alloc();
|
||||||
|
|
||||||
|
main_thread_core_entry_point(argc, argv);
|
||||||
|
|
||||||
|
tctx_release(tctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
|
||||||
|
{
|
||||||
|
(void)hInstance;
|
||||||
|
(void)hPrevInstance;
|
||||||
|
(void)lpCmdLine;
|
||||||
|
(void)nShowCmd;
|
||||||
|
w32_entry_point(__argc, __wargv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
#pragma comment(lib, "user32")
|
||||||
|
#pragma comment(lib, "shell32")
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Entity Types
|
||||||
|
|
||||||
|
typedef enum W32_EntityKind
|
||||||
|
{
|
||||||
|
W32_EntityKind_Null,
|
||||||
|
W32_EntityKind_RWMutex,
|
||||||
|
} W32_EntityKind;
|
||||||
|
|
||||||
|
typedef struct W32_Entity W32_Entity;
|
||||||
|
struct W32_Entity
|
||||||
|
{
|
||||||
|
W32_Entity* next;
|
||||||
|
W32_EntityKind kind;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
SRWLOCK rw_mutex;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// W32 state types
|
||||||
|
|
||||||
|
typedef struct W32_State W32_State;
|
||||||
|
struct W32_State
|
||||||
|
{
|
||||||
|
Arena* arena;
|
||||||
|
|
||||||
|
// info
|
||||||
|
SystemInfo system_info;
|
||||||
|
uint64 microsecond_resolution;
|
||||||
|
|
||||||
|
// entities
|
||||||
|
CRITICAL_SECTION entity_mutex;
|
||||||
|
Arena* entity_arena;
|
||||||
|
W32_Entity* entity_free;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// W32 globals
|
||||||
|
|
||||||
|
global W32_State w32_state = { 0 };
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Entity Functions
|
||||||
|
|
||||||
|
internal W32_Entity* w32_entity_alloc(W32_EntityKind kind);
|
||||||
|
internal void w32_entity_release(W32_Entity* entity);
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Shell operations
|
||||||
|
|
||||||
|
internal void sh_message(bool32 error, String8 title, String8 message)
|
||||||
|
{
|
||||||
|
TempArena scratch = scratch_begin(0, 0);
|
||||||
|
String16 title16 = str16_from_8(scratch.arena, title);
|
||||||
|
String16 message16 = str16_from_8(scratch.arena, message);
|
||||||
|
MessageBoxW(0, (WCHAR*)message16.str, (WCHAR*)title16.str, MB_OK | (!!error * MB_ICONERROR));
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#pragma once
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,97 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include <dwmapi.h>
|
||||||
|
#include <shellscalingapi.h>
|
||||||
|
#pragma comment(lib, "dwmapi")
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Windows Type
|
||||||
|
|
||||||
|
typedef struct W32_WM_Window W32_WM_Window;
|
||||||
|
struct W32_WM_Window
|
||||||
|
{
|
||||||
|
W32_WM_Window* next;
|
||||||
|
W32_WM_Window* previous;
|
||||||
|
HWND hwnd;
|
||||||
|
HDC hdc;
|
||||||
|
WINDOWPLACEMENT last_window_placement;
|
||||||
|
float32 dpi;
|
||||||
|
bool32 first_paint_done;
|
||||||
|
bool32 maximized;
|
||||||
|
bool32 custom_border;
|
||||||
|
float32 custom_border_title_thickness;
|
||||||
|
float32 custom_border_edge_thickness;
|
||||||
|
bool32 custom_border_composition_enabled;
|
||||||
|
Arena* paint_arena;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Monitor gathering bundle
|
||||||
|
|
||||||
|
typedef struct W32_WM_MonitorGatherNode W32_WM_MonitorGatherNode;
|
||||||
|
struct W32_WM_MonitorGatherNode
|
||||||
|
{
|
||||||
|
W32_WM_MonitorGatherNode* next;
|
||||||
|
WM_Monitor handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct W32_WM_MonitorGatherBundle W32_WM_MonitorGatherBundle;
|
||||||
|
struct W32_WM_MonitorGatherBundle
|
||||||
|
{
|
||||||
|
Arena* arena;
|
||||||
|
W32_WM_MonitorGatherNode* first_monitor;
|
||||||
|
W32_WM_MonitorGatherNode* last_monitor;
|
||||||
|
uint64 monitor_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Windows Global State
|
||||||
|
|
||||||
|
typedef struct W32_WM_State W32_WM_State;
|
||||||
|
struct W32_WM_State
|
||||||
|
{
|
||||||
|
Arena* arena;
|
||||||
|
uint32 gfx_thread_tid;
|
||||||
|
HINSTANCE hIstance;
|
||||||
|
HCURSOR hCursor;
|
||||||
|
WM_SystemInfo gfx_info;
|
||||||
|
W32_WM_Window* first_window;
|
||||||
|
W32_WM_Window* last_window;
|
||||||
|
W32_WM_Window* free_window;
|
||||||
|
WM_Key key_from_vkey_table[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Globals
|
||||||
|
|
||||||
|
global W32_WM_State* w32_wm_state = 0;
|
||||||
|
global WM_EventList w32_wm_event_list = { 0 };
|
||||||
|
global Arena* w32_wm_event_arena = 0;
|
||||||
|
global bool32 w32_wm_resizing = 0;
|
||||||
|
global bool32 w32_wm_new_window_custom_border = 0;
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
internal Rect2f w32_wm_rect2f_from_rect(RECT rect);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Windows
|
||||||
|
|
||||||
|
internal WM_Window w32_wm_handle_from_window(W32_WM_Window* window);
|
||||||
|
internal W32_WM_Window* w32_wm_window_from_handle(WM_Window handle);
|
||||||
|
internal W32_WM_Window* w32_wm_window_from_hwnd(HWND hwnd);
|
||||||
|
internal HWND w32_wm_hwnd_from_window(W32_WM_Window* window);
|
||||||
|
internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd);
|
||||||
|
internal void w32_wm_window_release(W32_WM_Window* window);
|
||||||
|
internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window);
|
||||||
|
internal WM_Key w32_wm_os_key_from_vkey(WPARAM vKey);
|
||||||
|
internal WPARAM w32_wm_vkey_from_os_key(WM_Key key);
|
||||||
|
internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Monitors
|
||||||
|
|
||||||
|
internal BOOL w32_wm_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr);
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// =============================================================================
|
||||||
|
// Handle type helpers
|
||||||
|
|
||||||
|
internal WM_Window wm_window_zero()
|
||||||
|
{
|
||||||
|
WM_Window result = { 0 };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool32 wm_window_match(WM_Window a, WM_Window b)
|
||||||
|
{
|
||||||
|
bool32 result = MemoryMatchStruct(&a, &b);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool32 wm_monitor_match(WM_Monitor a, WM_Monitor b)
|
||||||
|
{
|
||||||
|
bool32 result = MemoryMatchStruct(&a, &b);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Event Functions
|
||||||
|
|
||||||
|
internal void wm_eat_event(WM_EventList* events, WM_Event* event)
|
||||||
|
{
|
||||||
|
DLL_remove(events->first, events->last, event);
|
||||||
|
events->count -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool32 wm_key_press(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key)
|
||||||
|
{
|
||||||
|
bool32 result = 0;
|
||||||
|
for (WM_Event* event = events->first; event != 0; event = event->next)
|
||||||
|
{
|
||||||
|
if ((wm_window_match(event->window, window) || wm_window_match(window, wm_window_zero())) &&
|
||||||
|
event->kind == WM_EventKind_Press && event->key == key && event->modifiers == modifiers)
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
wm_eat_event(events, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool32 wm_key_release(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key)
|
||||||
|
{
|
||||||
|
bool32 result = 0;
|
||||||
|
for (WM_Event* event = events->first; event != 0; event = event->next)
|
||||||
|
{
|
||||||
|
if ((wm_window_match(event->window, window) || wm_window_match(window, wm_window_zero())) &&
|
||||||
|
event->kind == WM_EventKind_Release && event->key == key && event->modifiers == modifiers)
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
wm_eat_event(events, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal WM_Event* wm_event_list_push_new(Arena* arena, WM_EventList* events, WM_EventKind kind)
|
||||||
|
{
|
||||||
|
WM_Event* evt = push_array(arena, WM_Event, 1);
|
||||||
|
DLL_push_back(events->first, events->last, evt);
|
||||||
|
events->count += 1;
|
||||||
|
evt->timestamp_us = now_time_us();
|
||||||
|
evt->kind = kind;
|
||||||
|
return evt;
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// System Types
|
||||||
|
|
||||||
|
typedef struct WM_SystemInfo WM_SystemInfo;
|
||||||
|
struct WM_SystemInfo
|
||||||
|
{
|
||||||
|
float32 double_click_time;
|
||||||
|
float32 caret_blink_time;
|
||||||
|
float32 default_refresh_rate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Window Types
|
||||||
|
|
||||||
|
typedef uint32 WM_WindowFlags;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
WM_WindowFlag_CustomBorder = (1 << 0),
|
||||||
|
WM_WindowFlag_UseDefaultPosition = (1 << 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct WM_Window WM_Window;
|
||||||
|
struct WM_Window
|
||||||
|
{
|
||||||
|
uint64 handle[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Monitor Types
|
||||||
|
|
||||||
|
typedef struct WM_Monitor WM_Monitor;
|
||||||
|
struct WM_Monitor
|
||||||
|
{
|
||||||
|
uint64 handle[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct WM_MonitorArray WM_MonitorArray;
|
||||||
|
struct WM_MonitorArray
|
||||||
|
{
|
||||||
|
WM_Monitor* ptr;
|
||||||
|
uint64 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "window_manager_key.h"
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Curosr Types
|
||||||
|
typedef enum WM_Cursor
|
||||||
|
{
|
||||||
|
WM_Cursor_Pointer,
|
||||||
|
WM_Cursor_COUNT
|
||||||
|
} WM_Cursor;
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Event Types
|
||||||
|
|
||||||
|
typedef enum WM_EventKind
|
||||||
|
{
|
||||||
|
WM_EventKind_Null,
|
||||||
|
WM_EventKind_Press,
|
||||||
|
WM_EventKind_Release,
|
||||||
|
WM_EventKind_MouseMove,
|
||||||
|
WM_EventKind_Text,
|
||||||
|
WM_EventKind_WindowClose,
|
||||||
|
WM_EventKind_COUNT
|
||||||
|
} WM_EventKind;
|
||||||
|
|
||||||
|
typedef uint32 WM_Modifiers;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
WM_Modifier_Ctrl = (1 << 0),
|
||||||
|
WM_Modifier_Shift = (1 << 1),
|
||||||
|
WM_Modifier_Alt = (1 << 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct WM_Event WM_Event;
|
||||||
|
struct WM_Event
|
||||||
|
{
|
||||||
|
WM_Event* next;
|
||||||
|
WM_Event* previous;
|
||||||
|
uint64 timestamp_us;
|
||||||
|
WM_Window window;
|
||||||
|
WM_EventKind kind;
|
||||||
|
WM_Modifiers modifiers;
|
||||||
|
WM_Key key;
|
||||||
|
bool32 is_repeat;
|
||||||
|
bool32 right_sided;
|
||||||
|
uint32 character;
|
||||||
|
uint32 repeat_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct WM_EventList WM_EventList;
|
||||||
|
struct WM_EventList
|
||||||
|
{
|
||||||
|
uint64 count;
|
||||||
|
WM_Event* first;
|
||||||
|
WM_Event* last;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Application defined frame hook
|
||||||
|
|
||||||
|
internal bool32 frame();
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Handle type helpers
|
||||||
|
|
||||||
|
internal WM_Window wm_window_zero();
|
||||||
|
internal bool32 wm_window_match(WM_Window a, WM_Window b);
|
||||||
|
internal bool32 wm_monitor_match(WM_Monitor a, WM_Monitor b);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Event Functions
|
||||||
|
|
||||||
|
internal void wm_eat_event(WM_EventList* events, WM_Event* event);
|
||||||
|
internal bool32 wm_key_press(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key);
|
||||||
|
internal bool32 wm_key_release(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key);
|
||||||
|
internal WM_Event* wm_event_list_push_new(Arena* arena, WM_EventList* events, WM_EventKind kind);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Windows Management Functions
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Main Initialization API
|
||||||
|
|
||||||
|
internal void wm_init();
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Windows
|
||||||
|
|
||||||
|
internal WM_Window wm_widow_open(Rect2f rect, WM_WindowFlags flags, String8 title);
|
||||||
|
internal void wm_window_close(WM_Window handle);
|
||||||
|
internal void wm_window_first_paint(WM_Window window_handle);
|
||||||
|
internal void wm_window_set_monitor(WM_Window window, WM_Monitor monitor);
|
||||||
|
internal Rect2f wm_rect_from_window(WM_Window window_handle);
|
||||||
|
internal Rect2f wm_client_rect_from_window(WM_Window window);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Monitors
|
||||||
|
|
||||||
|
internal WM_MonitorArray wm_push_monitors_array(Arena* arena);
|
||||||
|
internal WM_Monitor wm_primary_monitor();
|
||||||
|
internal WM_Monitor wm_monitor_from_window(WM_Window window);
|
||||||
|
internal String8 wm_name_from_monitor(Arena* arena, WM_Monitor monitor);
|
||||||
|
internal Vector2f wm_dim_from_monitor(WM_Monitor monitor);
|
||||||
|
internal float32 wm_dpi_from_monitor(WM_Monitor monitor);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Events
|
||||||
|
|
||||||
|
internal void wm_send_wakeup_event();
|
||||||
|
internal WM_EventList wm_get_events(Arena* arena, bool32 wait);
|
||||||
|
internal WM_Modifiers wm_get_modifiers();
|
||||||
|
internal bool32 wm_key_is_down(WM_Key key);
|
||||||
|
internal Vector2f wm_mouse_from_window(WM_Window window);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Cursors
|
||||||
|
|
||||||
|
internal void wm_set_cursor(WM_Cursor cursor);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include "window_manager.c"
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# include "win32/window_manager/window_manager.c"
|
||||||
|
#else
|
||||||
|
# error No window manager for this operating system
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "window_manager.h"
|
||||||
|
#include "window_manager_key.h"
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# include "win32/window_manager/window_manager.h"
|
||||||
|
#else
|
||||||
|
# error No Window manager for this operating system
|
||||||
|
#endif
|
||||||
@@ -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