Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fa75c116e | ||
|
|
2881b2c9d5 | ||
|
|
d79cf42a3d | ||
|
|
17af5348e9 | ||
|
|
dec8cbd059 | ||
|
|
f580776964 | ||
|
|
d2d9981efe | ||
|
|
f6b48a1c11 | ||
|
|
bf13f269fe | ||
|
|
cf86dd10a7 | ||
|
|
5995dd9a47 |
No files matched your search
+3
-6
@@ -49,6 +49,9 @@ IndentWidth: 4
|
||||
InsertNewlineAtEOF: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
Macros:
|
||||
- 'EachIndex(it, count)=(uint64 it = 0; it < (count); ++it)'
|
||||
- 'EachNode(it, Type, first)=(Type* it = first; it != 0; it = it->next)'
|
||||
NamespaceIndentation: All
|
||||
ObjCSpaceAfterProperty: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 100
|
||||
@@ -63,11 +66,5 @@ SortIncludes: CaseInsensitive
|
||||
SpacesInAngles: Never
|
||||
SpacesInContainerLiterals: false
|
||||
Standard: Cpp11
|
||||
StatementMacros:
|
||||
- UPROPERTY
|
||||
- UCLASS
|
||||
- USTRUCT
|
||||
- GENERATED_BODY
|
||||
- UENUM
|
||||
TabWidth: 4
|
||||
...
|
||||
+8
-3
@@ -1,9 +1,14 @@
|
||||
[submodule "External/Imgui"]
|
||||
path = External/Imgui
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
[submodule "Juliet/external/stb"]
|
||||
path = Juliet/external/stb
|
||||
url = https://github.com/nothings/stb.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.
+1
-1
@@ -27,4 +27,4 @@ internal int32 safe_cast_int32(int64 val)
|
||||
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#define STB_SPRINTF_STATIC
|
||||
#include "external/stb/stb_sprintf.h"
|
||||
#include "external/stb_sprintf/stb_sprintf.h"
|
||||
+42
-12
@@ -7,7 +7,7 @@
|
||||
|
||||
#define STB_SPRINTF_DECORATE(name) juliet_##name
|
||||
#define STB_SPRINTF_STATIC
|
||||
#include "external/stb/stb_sprintf.h"
|
||||
#include "external/stb_sprintf/stb_sprintf.h"
|
||||
|
||||
#define internal static
|
||||
#define global static
|
||||
@@ -73,16 +73,25 @@
|
||||
// =============================================================================
|
||||
// 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
|
||||
@@ -119,30 +128,44 @@
|
||||
#define CheckNil(nil, ptr) ((ptr) == 0 || (ptr) == nil)
|
||||
#define SetNil(nil, ptr) ((ptr) = nil)
|
||||
|
||||
// Doubly-linked-lists
|
||||
// clang-format off
|
||||
#define DLL_insert_NPZ(nil, first, last, ptr, node, next, previous) \
|
||||
#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))))
|
||||
// clang-format on
|
||||
#define DLL_push_back_NPZ(nil, first, last, node, next, previous) \
|
||||
DLL_insert_NPZ(nil, first, last, last, node, next, previous)
|
||||
#define DLL_remove_NPZ(nil, first, last, node, next, previous) \
|
||||
#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_node(first, node, next) ((node)->next = (first), (first) = (node))
|
||||
#define SLL_stack_pop_node(first, next) ((first) = (first)->next);
|
||||
#define SLL_stack_push(first, node) SLL_stack_push_node(first, node, next)
|
||||
#define SLL_stack_pop(first) SLL_stack_pop_node(first, next)
|
||||
#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(first, last, node) DLL_push_back_NPZ(0, first, last, node, next, previous)
|
||||
#define DLL_remove(first, last, node) DLL_remove_NPZ(0, first, last, node, next, previous)
|
||||
#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
|
||||
@@ -157,6 +180,13 @@
|
||||
|
||||
#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
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ internal void* arena_push(Arena* arena, uint64 size, uint64 align, bool32 zero)
|
||||
}
|
||||
|
||||
new_block->base_position = current->base_position + current->reserved;
|
||||
SLL_stack_push_node(arena->current, new_block, previous);
|
||||
SLL_stack_push_next(arena->current, new_block, previous);
|
||||
|
||||
current = new_block;
|
||||
pos_pre = AlignPow2(current->position, align);
|
||||
|
||||
@@ -39,6 +39,13 @@
|
||||
# error Compiler not supported.
|
||||
#endif
|
||||
|
||||
// ========================================================================== //
|
||||
// Architecture
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
# define ARCH_64BIT 1
|
||||
#endif
|
||||
|
||||
// ========================================================================== //
|
||||
// Language
|
||||
|
||||
|
||||
@@ -21,5 +21,6 @@ internal uint64 uint64_hash_from_string(String8 string)
|
||||
|
||||
internal uint64 uint64_hash_from_seed_string(uint64 seed, String8 string)
|
||||
{
|
||||
return 0;
|
||||
uint64 result = XXH3_64bits_withSeed(string.str, string.size, seed);
|
||||
return result;
|
||||
}
|
||||
@@ -14,6 +14,17 @@ union Vector2f
|
||||
float32 v[2];
|
||||
};
|
||||
|
||||
typedef union Vector2i Vector2i;
|
||||
union Vector2i
|
||||
{
|
||||
struct
|
||||
{
|
||||
int32 x;
|
||||
int32 y;
|
||||
};
|
||||
int32 v[2];
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// Rect Types
|
||||
|
||||
|
||||
@@ -1,6 +1,57 @@
|
||||
#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
|
||||
#include "core/core_arena.h"
|
||||
|
||||
internal uint64 cstring8_length(uint8* cstring)
|
||||
{
|
||||
uint64 length = 0;
|
||||
@@ -85,7 +136,51 @@ internal String32 str32_cstring(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)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// ========================================================================== //
|
||||
// =============================================================================
|
||||
// String Types
|
||||
|
||||
typedef struct String8 String8;
|
||||
@@ -24,7 +24,18 @@ struct String32
|
||||
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;
|
||||
@@ -34,13 +45,24 @@ struct UnicodeDecode
|
||||
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)
|
||||
@@ -55,13 +77,19 @@ 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);
|
||||
@@ -69,7 +97,7 @@ 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);
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
// =============================================================================
|
||||
// Synchronization primitives types
|
||||
|
||||
typedef struct RWMutex RWMutex;
|
||||
struct RWMutex
|
||||
{
|
||||
uint64 handle[1];
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// Thread Info Helpers
|
||||
internal void set_thread_name(String8 name);
|
||||
@@ -10,3 +19,21 @@ internal void set_thread_namef(char* fmt, ...);
|
||||
|
||||
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
Vendored
-1
Submodule Juliet/external/stb deleted from 2c980bb598.
+1
Submodule Juliet/external/stb_sprintf added at 2ffb3379e8.
Vendored
+1
-1
Submodule Juliet/external/xxHash updated: d9dfb8203c...c87183a77d.
@@ -5,35 +5,61 @@ internal void ja_init()
|
||||
ja_state->arena = arena;
|
||||
|
||||
// Window cache
|
||||
ja_state->window_state_gen_id = 1;
|
||||
{
|
||||
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);
|
||||
|
||||
// if (hello.handle[0] == 0)
|
||||
// {
|
||||
// hello = wm_window_open(rect2fp(50.f, 50.f, 1280.f, 720.f), WM_WindowFlag_UseDefaultPosition,
|
||||
// str8_literal("Hello")); wm_window_first_paint(hello);
|
||||
// }
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Consume events
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -46,20 +72,83 @@ internal void ja_frame()
|
||||
|
||||
// Window management (open/render)
|
||||
{
|
||||
for
|
||||
EachIndex(slot_idx, ja_state->window_state_gen_id)
|
||||
for EachNode(request, JA_WindowRequest, ja_state->window_request_first)
|
||||
{
|
||||
JA_WindowState* ws = ja_window_state_from_id(slot_idx);
|
||||
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()
|
||||
{
|
||||
// wm_window_close(aaa);
|
||||
arena_clear(ja_state->arena);
|
||||
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;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -76,9 +165,139 @@ internal JA_WindowState* ja_window_state_from_id(JA_ID id)
|
||||
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;
|
||||
}
|
||||
@@ -4,18 +4,54 @@
|
||||
// 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;
|
||||
@@ -24,13 +60,23 @@ 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_WindowState* window_state_last_accessed;
|
||||
JA_ID window_state_last_accessed_id;
|
||||
JA_ID window_state_gen_id;
|
||||
JA_WindowState* window_state_last_accessed;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
@@ -47,7 +93,16 @@ 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);
|
||||
@@ -4,12 +4,14 @@
|
||||
|
||||
// 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"
|
||||
@@ -24,6 +26,7 @@ internal bool32 frame()
|
||||
internal void entry_point()
|
||||
{
|
||||
wm_init();
|
||||
r_init();
|
||||
ja_init();
|
||||
|
||||
for (bool32 quit = 0; !quit;)
|
||||
@@ -31,4 +34,5 @@ internal void entry_point()
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1 +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();
|
||||
@@ -1 +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);
|
||||
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
|
||||
@@ -6,6 +6,38 @@ typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDes
|
||||
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
|
||||
|
||||
@@ -85,6 +117,51 @@ internal void set_platform_thread_name(String8 name)
|
||||
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
|
||||
|
||||
@@ -193,6 +270,10 @@ internal void w32_entry_point(int argc, WCHAR** wargv)
|
||||
}
|
||||
}
|
||||
|
||||
// setup entity storage
|
||||
InitializeCriticalSection(&w32_state.entity_mutex);
|
||||
w32_state.entity_arena = arena_alloc();
|
||||
|
||||
main_thread_core_entry_point(argc, argv);
|
||||
|
||||
tctx_release(tctx);
|
||||
|
||||
@@ -7,13 +7,51 @@
|
||||
#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;
|
||||
SystemInfo system_info;
|
||||
|
||||
// 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
|
||||
@@ -93,12 +93,237 @@ internal void w32_wm_window_release(W32_WM_Window* window)
|
||||
|
||||
internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window)
|
||||
{
|
||||
WM_Event* result = 0;
|
||||
WM_Event* result = wm_event_list_push_new(w32_wm_event_arena, &w32_wm_event_list, kind);
|
||||
result->window = w32_wm_handle_from_window(window);
|
||||
result->modifiers = wm_get_modifiers();
|
||||
return result;
|
||||
}
|
||||
|
||||
internal WM_Key w32_wm_os_key_from_vkey(WPARAM vKey)
|
||||
{
|
||||
local_persist bool32 first = 1;
|
||||
local_persist WM_Key key_table[256];
|
||||
if (first)
|
||||
{
|
||||
first = 0;
|
||||
MemoryZeroArray(key_table);
|
||||
|
||||
key_table[(unsigned int)'A'] = WM_Key_A;
|
||||
key_table[(unsigned int)'B'] = WM_Key_B;
|
||||
key_table[(unsigned int)'C'] = WM_Key_C;
|
||||
key_table[(unsigned int)'D'] = WM_Key_D;
|
||||
key_table[(unsigned int)'E'] = WM_Key_E;
|
||||
key_table[(unsigned int)'F'] = WM_Key_F;
|
||||
key_table[(unsigned int)'G'] = WM_Key_G;
|
||||
key_table[(unsigned int)'H'] = WM_Key_H;
|
||||
key_table[(unsigned int)'I'] = WM_Key_I;
|
||||
key_table[(unsigned int)'J'] = WM_Key_J;
|
||||
key_table[(unsigned int)'K'] = WM_Key_K;
|
||||
key_table[(unsigned int)'L'] = WM_Key_L;
|
||||
key_table[(unsigned int)'M'] = WM_Key_M;
|
||||
key_table[(unsigned int)'N'] = WM_Key_N;
|
||||
key_table[(unsigned int)'O'] = WM_Key_O;
|
||||
key_table[(unsigned int)'P'] = WM_Key_P;
|
||||
key_table[(unsigned int)'Q'] = WM_Key_Q;
|
||||
key_table[(unsigned int)'R'] = WM_Key_R;
|
||||
key_table[(unsigned int)'S'] = WM_Key_S;
|
||||
key_table[(unsigned int)'T'] = WM_Key_T;
|
||||
key_table[(unsigned int)'U'] = WM_Key_U;
|
||||
key_table[(unsigned int)'V'] = WM_Key_V;
|
||||
key_table[(unsigned int)'W'] = WM_Key_W;
|
||||
key_table[(unsigned int)'X'] = WM_Key_X;
|
||||
key_table[(unsigned int)'Y'] = WM_Key_Y;
|
||||
key_table[(unsigned int)'Z'] = WM_Key_Z;
|
||||
|
||||
for (uint64 i = '0', j = WM_Key_0; i <= '9'; ++i, ++j)
|
||||
{
|
||||
key_table[i] = (WM_Key)j;
|
||||
}
|
||||
for (uint64 i = VK_NUMPAD0, j = WM_Key_0; i <= VK_NUMPAD9; ++i, ++j)
|
||||
{
|
||||
key_table[i] = (WM_Key)j;
|
||||
}
|
||||
for (uint64 i = VK_F1, j = WM_Key_F1; i <= VK_F24; ++i, ++j)
|
||||
{
|
||||
key_table[i] = (WM_Key)j;
|
||||
}
|
||||
|
||||
key_table[VK_SPACE] = WM_Key_Space;
|
||||
key_table[VK_OEM_3] = WM_Key_Tick;
|
||||
key_table[VK_OEM_MINUS] = WM_Key_Minus;
|
||||
key_table[VK_OEM_PLUS] = WM_Key_Equal;
|
||||
key_table[VK_OEM_4] = WM_Key_LeftBracket;
|
||||
key_table[VK_OEM_6] = WM_Key_RightBracket;
|
||||
key_table[VK_OEM_1] = WM_Key_Semicolon;
|
||||
key_table[VK_OEM_7] = WM_Key_Quote;
|
||||
key_table[VK_OEM_COMMA] = WM_Key_Comma;
|
||||
key_table[VK_OEM_PERIOD] = WM_Key_Period;
|
||||
key_table[VK_OEM_2] = WM_Key_Slash;
|
||||
key_table[VK_OEM_5] = WM_Key_BackSlash;
|
||||
|
||||
key_table[VK_TAB] = WM_Key_Tab;
|
||||
key_table[VK_PAUSE] = WM_Key_Pause;
|
||||
key_table[VK_ESCAPE] = WM_Key_Esc;
|
||||
|
||||
key_table[VK_UP] = WM_Key_Up;
|
||||
key_table[VK_LEFT] = WM_Key_Left;
|
||||
key_table[VK_DOWN] = WM_Key_Down;
|
||||
key_table[VK_RIGHT] = WM_Key_Right;
|
||||
|
||||
key_table[VK_BACK] = WM_Key_Backspace;
|
||||
key_table[VK_RETURN] = WM_Key_Return;
|
||||
|
||||
key_table[VK_DELETE] = WM_Key_Delete;
|
||||
key_table[VK_INSERT] = WM_Key_Insert;
|
||||
key_table[VK_PRIOR] = WM_Key_PageUp;
|
||||
key_table[VK_NEXT] = WM_Key_PageDown;
|
||||
key_table[VK_HOME] = WM_Key_Home;
|
||||
key_table[VK_END] = WM_Key_End;
|
||||
|
||||
key_table[VK_CAPITAL] = WM_Key_CapsLock;
|
||||
key_table[VK_NUMLOCK] = WM_Key_NumLock;
|
||||
key_table[VK_SCROLL] = WM_Key_ScrollLock;
|
||||
key_table[VK_APPS] = WM_Key_Menu;
|
||||
|
||||
key_table[VK_CONTROL] = WM_Key_Ctrl;
|
||||
key_table[VK_LCONTROL] = WM_Key_Ctrl;
|
||||
key_table[VK_RCONTROL] = WM_Key_Ctrl;
|
||||
key_table[VK_SHIFT] = WM_Key_Shift;
|
||||
key_table[VK_LSHIFT] = WM_Key_Shift;
|
||||
key_table[VK_RSHIFT] = WM_Key_Shift;
|
||||
key_table[VK_MENU] = WM_Key_Alt;
|
||||
key_table[VK_LMENU] = WM_Key_Alt;
|
||||
key_table[VK_RMENU] = WM_Key_Alt;
|
||||
|
||||
key_table[VK_DIVIDE] = WM_Key_NumSlash;
|
||||
key_table[VK_MULTIPLY] = WM_Key_NumStar;
|
||||
key_table[VK_SUBTRACT] = WM_Key_NumMinus;
|
||||
key_table[VK_ADD] = WM_Key_NumPlus;
|
||||
key_table[VK_DECIMAL] = WM_Key_NumPeriod;
|
||||
|
||||
for (uint32 i = 0; i < 10; i += 1)
|
||||
{
|
||||
key_table[VK_NUMPAD0 + i] = (WM_Key)((uint64)WM_Key_Num0 + i);
|
||||
}
|
||||
|
||||
for (uint64 i = 0xDF, j = 0; i < 0xFF; i += 1, j += 1)
|
||||
{
|
||||
key_table[i] = (WM_Key)((uint64)WM_Key_Ex0 + j);
|
||||
}
|
||||
}
|
||||
|
||||
WM_Key key = key_table[vKey & bitmask8];
|
||||
return key;
|
||||
}
|
||||
|
||||
internal WPARAM w32_wm_vkey_from_os_key(WM_Key key)
|
||||
{
|
||||
WPARAM result = 0;
|
||||
{
|
||||
local_persist bool32 initialized = 0;
|
||||
local_persist WPARAM vkey_table[WM_Key_COUNT] = { 0 };
|
||||
if (initialized == 0)
|
||||
{
|
||||
initialized = 1;
|
||||
vkey_table[WM_Key_Esc] = VK_ESCAPE;
|
||||
for (WM_Key key = WM_Key_F1; key <= WM_Key_F24; key = (WM_Key)(key + 1))
|
||||
{
|
||||
vkey_table[key] = VK_F1 + (key - WM_Key_F1);
|
||||
}
|
||||
vkey_table[WM_Key_Tick] = VK_OEM_3;
|
||||
for (WM_Key key = WM_Key_0; key <= WM_Key_9; key = (WM_Key)(key + 1))
|
||||
{
|
||||
vkey_table[key] = '0' + (key - WM_Key_0);
|
||||
}
|
||||
vkey_table[WM_Key_Minus] = VK_OEM_MINUS;
|
||||
vkey_table[WM_Key_Equal] = VK_OEM_PLUS;
|
||||
vkey_table[WM_Key_Backspace] = VK_BACK;
|
||||
vkey_table[WM_Key_Tab] = VK_TAB;
|
||||
vkey_table[WM_Key_Q] = 'Q';
|
||||
vkey_table[WM_Key_W] = 'W';
|
||||
vkey_table[WM_Key_E] = 'E';
|
||||
vkey_table[WM_Key_R] = 'R';
|
||||
vkey_table[WM_Key_T] = 'T';
|
||||
vkey_table[WM_Key_Y] = 'Y';
|
||||
vkey_table[WM_Key_U] = 'U';
|
||||
vkey_table[WM_Key_I] = 'I';
|
||||
vkey_table[WM_Key_O] = 'O';
|
||||
vkey_table[WM_Key_P] = 'P';
|
||||
vkey_table[WM_Key_LeftBracket] = VK_OEM_4;
|
||||
vkey_table[WM_Key_RightBracket] = VK_OEM_6;
|
||||
vkey_table[WM_Key_BackSlash] = VK_OEM_5;
|
||||
vkey_table[WM_Key_CapsLock] = VK_CAPITAL;
|
||||
vkey_table[WM_Key_A] = 'A';
|
||||
vkey_table[WM_Key_S] = 'S';
|
||||
vkey_table[WM_Key_D] = 'D';
|
||||
vkey_table[WM_Key_F] = 'F';
|
||||
vkey_table[WM_Key_G] = 'G';
|
||||
vkey_table[WM_Key_H] = 'H';
|
||||
vkey_table[WM_Key_J] = 'J';
|
||||
vkey_table[WM_Key_K] = 'K';
|
||||
vkey_table[WM_Key_L] = 'L';
|
||||
vkey_table[WM_Key_Semicolon] = VK_OEM_1;
|
||||
vkey_table[WM_Key_Quote] = VK_OEM_7;
|
||||
vkey_table[WM_Key_Return] = VK_RETURN;
|
||||
vkey_table[WM_Key_Shift] = VK_SHIFT;
|
||||
vkey_table[WM_Key_Z] = 'Z';
|
||||
vkey_table[WM_Key_X] = 'X';
|
||||
vkey_table[WM_Key_C] = 'C';
|
||||
vkey_table[WM_Key_V] = 'V';
|
||||
vkey_table[WM_Key_B] = 'B';
|
||||
vkey_table[WM_Key_N] = 'N';
|
||||
vkey_table[WM_Key_M] = 'M';
|
||||
vkey_table[WM_Key_Comma] = VK_OEM_COMMA;
|
||||
vkey_table[WM_Key_Period] = VK_OEM_PERIOD;
|
||||
vkey_table[WM_Key_Slash] = VK_OEM_2;
|
||||
vkey_table[WM_Key_Ctrl] = VK_CONTROL;
|
||||
vkey_table[WM_Key_Alt] = VK_MENU;
|
||||
vkey_table[WM_Key_Space] = VK_SPACE;
|
||||
vkey_table[WM_Key_Menu] = VK_APPS;
|
||||
vkey_table[WM_Key_ScrollLock] = VK_SCROLL;
|
||||
vkey_table[WM_Key_Pause] = VK_PAUSE;
|
||||
vkey_table[WM_Key_Insert] = VK_INSERT;
|
||||
vkey_table[WM_Key_Home] = VK_HOME;
|
||||
vkey_table[WM_Key_PageUp] = VK_PRIOR;
|
||||
vkey_table[WM_Key_Delete] = VK_DELETE;
|
||||
vkey_table[WM_Key_End] = VK_END;
|
||||
vkey_table[WM_Key_PageDown] = VK_NEXT;
|
||||
vkey_table[WM_Key_Up] = VK_UP;
|
||||
vkey_table[WM_Key_Left] = VK_LEFT;
|
||||
vkey_table[WM_Key_Down] = VK_DOWN;
|
||||
vkey_table[WM_Key_Right] = VK_RIGHT;
|
||||
for (WM_Key key = WM_Key_Ex0; key <= WM_Key_Ex29; key = (WM_Key)(key + 1))
|
||||
{
|
||||
vkey_table[key] = 0xDF + (key - WM_Key_Ex0);
|
||||
}
|
||||
vkey_table[WM_Key_NumLock] = VK_NUMLOCK;
|
||||
vkey_table[WM_Key_NumSlash] = VK_DIVIDE;
|
||||
vkey_table[WM_Key_NumStar] = VK_MULTIPLY;
|
||||
vkey_table[WM_Key_NumMinus] = VK_SUBTRACT;
|
||||
vkey_table[WM_Key_NumPlus] = VK_ADD;
|
||||
vkey_table[WM_Key_NumPeriod] = VK_DECIMAL;
|
||||
vkey_table[WM_Key_Num0] = VK_NUMPAD0;
|
||||
vkey_table[WM_Key_Num1] = VK_NUMPAD1;
|
||||
vkey_table[WM_Key_Num2] = VK_NUMPAD2;
|
||||
vkey_table[WM_Key_Num3] = VK_NUMPAD3;
|
||||
vkey_table[WM_Key_Num4] = VK_NUMPAD4;
|
||||
vkey_table[WM_Key_Num5] = VK_NUMPAD5;
|
||||
vkey_table[WM_Key_Num6] = VK_NUMPAD6;
|
||||
vkey_table[WM_Key_Num7] = VK_NUMPAD7;
|
||||
vkey_table[WM_Key_Num8] = VK_NUMPAD8;
|
||||
vkey_table[WM_Key_Num9] = VK_NUMPAD9;
|
||||
vkey_table[WM_Key_LeftMouseButton] = VK_LBUTTON;
|
||||
vkey_table[WM_Key_MiddleMouseButton] = VK_MBUTTON;
|
||||
vkey_table[WM_Key_RightMouseButton] = VK_RBUTTON;
|
||||
}
|
||||
result = vkey_table[key];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// w32 windows proc
|
||||
|
||||
internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT result = 0;
|
||||
@@ -152,6 +377,91 @@ internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSKEYUP:
|
||||
{
|
||||
if (wParam != VK_MENU && (wParam < VK_F1 || VK_F24 < wParam || wParam < VK_F4))
|
||||
{
|
||||
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
} // fallthrough;
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP:
|
||||
{
|
||||
bool32 was_down = (lParam & bit31);
|
||||
bool32 is_down = !(lParam & bit32);
|
||||
|
||||
bool32 is_repeat = 0;
|
||||
if (!is_down)
|
||||
{
|
||||
release = 1;
|
||||
}
|
||||
else if (was_down)
|
||||
{
|
||||
release = 1;
|
||||
}
|
||||
|
||||
bool32 right_sided = 0;
|
||||
if ((lParam * bit25) && (wParam == VK_CONTROL || wParam == VK_RCONTROL || wParam == VK_MENU ||
|
||||
wParam == VK_RMENU || wParam == VK_SHIFT || wParam == VK_RSHIFT))
|
||||
{
|
||||
right_sided = 1;
|
||||
}
|
||||
|
||||
WM_Event* event = w32_wm_push_event(release ? WM_EventKind_Release : WM_EventKind_Press, window);
|
||||
event->key = w32_wm_os_key_from_vkey(wParam);
|
||||
event->repeat_count = lParam & bitmask16;
|
||||
event->is_repeat = is_repeat;
|
||||
event->right_sided = right_sided;
|
||||
if (event->key == WM_Key_Alt && event->modifiers & WM_Modifier_Alt)
|
||||
{
|
||||
event->modifiers &= ~WM_Modifier_Alt;
|
||||
}
|
||||
if (event->key == WM_Key_Ctrl && event->modifiers & WM_Modifier_Ctrl)
|
||||
{
|
||||
event->modifiers &= ~WM_Modifier_Ctrl;
|
||||
}
|
||||
if (event->key == WM_Key_Shift && event->modifiers & WM_Modifier_Shift)
|
||||
{
|
||||
event->modifiers &= ~WM_Modifier_Shift;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_SYSCHAR:
|
||||
{
|
||||
WORD vk_code = LOWORD(wParam);
|
||||
if (vk_code == VK_SPACE)
|
||||
{
|
||||
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_CHAR:
|
||||
{
|
||||
uint32 character = wParam;
|
||||
if ((character >= 32 && character != 127) || character == '\r')
|
||||
{
|
||||
WM_Event* event = w32_wm_push_event(WM_EventKind_Text, window);
|
||||
if (lParam & bit29)
|
||||
{
|
||||
event->modifiers |= WM_Modifier_Alt;
|
||||
}
|
||||
if (character == '\r')
|
||||
{
|
||||
character = '\n';
|
||||
}
|
||||
event->character = character;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_SETCURSOR:
|
||||
{
|
||||
Rect2f window_rect = wm_client_rect_from_window(window_handle);
|
||||
@@ -260,6 +570,20 @@ internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa
|
||||
return result;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Monitors
|
||||
|
||||
internal BOOL w32_wm_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr)
|
||||
{
|
||||
W32_WM_MonitorGatherBundle* bundle = (W32_WM_MonitorGatherBundle*)bundle_ptr;
|
||||
WM_Monitor m = { (uint64)monitor };
|
||||
W32_WM_MonitorGatherNode* node = push_array(bundle->arena, W32_WM_MonitorGatherNode, 1);
|
||||
node->handle = m;
|
||||
SLL_queue_push(bundle->first_monitor, bundle->last_monitor, node);
|
||||
bundle->monitor_count += 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal void wm_init()
|
||||
{
|
||||
// Setup based state
|
||||
@@ -508,6 +832,37 @@ internal void wm_window_first_paint(WM_Window window_handle)
|
||||
}
|
||||
}
|
||||
|
||||
internal void wm_window_set_monitor(WM_Window window_handle, WM_Monitor monitor)
|
||||
{
|
||||
W32_WM_Window* window = w32_wm_window_from_handle(window_handle);
|
||||
if (window != 0)
|
||||
{
|
||||
HMONITOR hmonitor = (HMONITOR)monitor.handle[0];
|
||||
MONITORINFOEXW info;
|
||||
info.cbSize = sizeof(MONITORINFOEXW);
|
||||
if (GetMonitorInfoW(hmonitor, (MONITORINFO*)&info))
|
||||
{
|
||||
Rect2f existing_rect = wm_rect_from_window(window_handle);
|
||||
Vector2f window_size = dimension_2f(existing_rect);
|
||||
SetWindowPos(window->hwnd, HWND_TOP, (info.rcWork.left + info.rcWork.right) / 2 - window_size.x / 2,
|
||||
(info.rcWork.top + info.rcWork.bottom) / 2 - window_size.y / 2, window_size.x, window_size.y, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal Rect2f wm_rect_from_window(WM_Window window_handle)
|
||||
{
|
||||
Rect2f r = { 0 };
|
||||
W32_WM_Window* window = w32_wm_window_from_handle(window_handle);
|
||||
if (window != 0)
|
||||
{
|
||||
RECT rect = { 0 };
|
||||
GetWindowRect(w32_wm_hwnd_from_window(window), &rect);
|
||||
r = w32_wm_rect2f_from_rect(rect);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
internal Rect2f wm_client_rect_from_window(WM_Window handle)
|
||||
{
|
||||
Rect2f result = { 0 };
|
||||
@@ -521,6 +876,92 @@ internal Rect2f wm_client_rect_from_window(WM_Window handle)
|
||||
return result;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Monitors
|
||||
|
||||
internal WM_MonitorArray wm_push_monitors_array(Arena* arena)
|
||||
{
|
||||
TempArena scratch = scratch_begin(&arena, 1);
|
||||
|
||||
W32_WM_MonitorGatherBundle bundle = { arena };
|
||||
EnumDisplayMonitors(0, 0, w32_wm_monitor_gather_enum_proc, (LPARAM)&bundle);
|
||||
WM_MonitorArray array = { 0 };
|
||||
array.count = bundle.monitor_count;
|
||||
array.ptr = push_array(arena, WM_Monitor, array.count);
|
||||
{
|
||||
uint64 idx = 0;
|
||||
for EachNode(node, W32_WM_MonitorGatherNode, bundle.first_monitor)
|
||||
{
|
||||
array.ptr[idx] = node->handle;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return array;
|
||||
}
|
||||
|
||||
internal WM_Monitor wm_primary_monitor()
|
||||
{
|
||||
POINT zero_pt = { 0, 0 };
|
||||
HMONITOR monitor = MonitorFromPoint(zero_pt, MONITOR_DEFAULTTOPRIMARY);
|
||||
WM_Monitor result = { (uint64)monitor };
|
||||
return result;
|
||||
}
|
||||
|
||||
internal WM_Monitor wm_monitor_from_window(WM_Window window)
|
||||
{
|
||||
W32_WM_Window* w = w32_wm_window_from_handle(window);
|
||||
WM_Monitor result = { 0 };
|
||||
if (w != 0)
|
||||
{
|
||||
HMONITOR handle = MonitorFromWindow(w->hwnd, MONITOR_DEFAULTTOPRIMARY);
|
||||
result.handle[0] = (uint64)handle;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8 wm_name_from_monitor(Arena* arena, WM_Monitor monitor)
|
||||
{
|
||||
String8 result = { 0 };
|
||||
HMONITOR monitor_handle = (HMONITOR)monitor.handle[0];
|
||||
MONITORINFOEXW info;
|
||||
info.cbSize = sizeof(MONITORINFOEXW);
|
||||
if (GetMonitorInfoW(monitor_handle, (MONITORINFO*)&info))
|
||||
{
|
||||
String16 result16 = str16_cstring((uint16*)info.szDevice);
|
||||
result = str8_from_16(arena, result16);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Vector2f wm_dim_from_monitor(WM_Monitor monitor)
|
||||
{
|
||||
Vector2f result = { 0 };
|
||||
HMONITOR monitor_handle = (HMONITOR)monitor.handle[0];
|
||||
MONITORINFO info;
|
||||
info.cbSize = sizeof(MONITORINFO);
|
||||
if (GetMonitorInfoW(monitor_handle, &info))
|
||||
{
|
||||
result.x = info.rcWork.right - info.rcWork.left;
|
||||
result.y = info.rcWork.bottom - info.rcWork.top;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal float32 wm_dpi_from_monitor(WM_Monitor monitor)
|
||||
{
|
||||
float32 result = 96.f;
|
||||
HMONITOR monitor_handle = (HMONITOR)monitor.handle[0];
|
||||
if (w32_GetDpiForMonitor_func != 0)
|
||||
{
|
||||
UINT dpi_x = 0;
|
||||
UINT dpi_y = 0;
|
||||
HRESULT hr = w32_GetDpiForMonitor_func(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
|
||||
result = (float32)dpi_x;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Events
|
||||
|
||||
@@ -553,21 +994,32 @@ internal WM_EventList wm_get_events(Arena* arena, bool32 wait)
|
||||
internal WM_Modifiers wm_get_modifiers()
|
||||
{
|
||||
WM_Modifiers modifiers = 0;
|
||||
if (GetKeyState(VK_CONTROL) * 0x8000)
|
||||
if (GetKeyState(VK_CONTROL) & 0x8000)
|
||||
{
|
||||
modifiers |= WM_Modifier_Ctrl;
|
||||
}
|
||||
if (GetKeyState(VK_SHIFT) * 0x8000)
|
||||
if (GetKeyState(VK_SHIFT) & 0x8000)
|
||||
{
|
||||
modifiers |= WM_Modifier_Shift;
|
||||
}
|
||||
if (GetKeyState(VK_MENU) * 0x8000)
|
||||
if (GetKeyState(VK_MENU) & 0x8000)
|
||||
{
|
||||
modifiers |= WM_Modifier_Alt;
|
||||
}
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
internal bool32 wm_key_is_down(WM_Key key)
|
||||
{
|
||||
bool32 down = 0;
|
||||
WPARAM vkey = w32_wm_vkey_from_os_key(key);
|
||||
if (GetKeyState(vkey) & 0x8000)
|
||||
{
|
||||
down = 1;
|
||||
}
|
||||
return down;
|
||||
}
|
||||
|
||||
internal Vector2f wm_mouse_from_window(WM_Window handle)
|
||||
{
|
||||
Vector2f result = { 0 };
|
||||
|
||||
@@ -27,6 +27,25 @@ struct W32_WM_Window
|
||||
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
|
||||
|
||||
@@ -66,5 +85,13 @@ internal W32_WM_Window* w32_wm_window_from_handle(WM_Window handle);
|
||||
internal W32_WM_Window* w32_wm_window_from_hwnd(HWND hwnd);
|
||||
internal HWND w32_wm_hwnd_from_window(W32_WM_Window* window);
|
||||
internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd);
|
||||
internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window);
|
||||
internal void w32_wm_window_release(W32_WM_Window* window);
|
||||
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);
|
||||
@@ -1,3 +1,24 @@
|
||||
// =============================================================================
|
||||
// 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
|
||||
|
||||
@@ -7,6 +28,38 @@ internal void wm_eat_event(WM_EventList* events, WM_Event* 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);
|
||||
|
||||
@@ -62,6 +62,7 @@ typedef enum WM_EventKind
|
||||
WM_EventKind_Press,
|
||||
WM_EventKind_Release,
|
||||
WM_EventKind_MouseMove,
|
||||
WM_EventKind_Text,
|
||||
WM_EventKind_WindowClose,
|
||||
WM_EventKind_COUNT
|
||||
} WM_EventKind;
|
||||
@@ -84,6 +85,10 @@ struct WM_Event
|
||||
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;
|
||||
@@ -99,10 +104,19 @@ struct WM_EventList
|
||||
|
||||
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);
|
||||
|
||||
// =============================================================================
|
||||
@@ -119,14 +133,27 @@ internal void wm_init();
|
||||
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);
|
||||
|
||||
// =============================================================================
|
||||
|
||||
Reference in new issue
Block a user