Compare commits

...
29 changed files with 6029 additions and 66 deletions

No files matched your search

+3 -6
View File
@@ -49,6 +49,9 @@ 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
@@ -63,11 +66,5 @@ 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
... ...
+1 -1
View File
@@ -27,4 +27,4 @@ internal int32 safe_cast_int32(int64 val)
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#define STB_SPRINTF_STATIC #define STB_SPRINTF_STATIC
#include "external/stb/stb_sprintf.h" #include "external/stb_sprintf/stb_sprintf.h"
+42 -12
View File
@@ -7,7 +7,7 @@
#define STB_SPRINTF_DECORATE(name) juliet_##name #define STB_SPRINTF_DECORATE(name) juliet_##name
#define STB_SPRINTF_STATIC #define STB_SPRINTF_STATIC
#include "external/stb/stb_sprintf.h" #include "external/stb_sprintf/stb_sprintf.h"
#define internal static #define internal static
#define global static #define global static
@@ -73,16 +73,25 @@
// ============================================================================= // =============================================================================
// For loop helpers // 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 EachIndex(it, count) (uint64 it = 0; it < (count); ++it)
#define EachNode(it, Type, first) (Type* it = first; it != 0; it = it->next)
// ============================================================================= // =============================================================================
// Memory Helpers // Memory Helpers
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size)) #define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
#define MemorySet(dst, src, size) memset((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 MemoryZero(ptr, size) memset((ptr), 0, (size))
#define MemoryZeroStruct(s) MemoryZero((s), sizeof(*(s))) #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 // Asserts
@@ -119,30 +128,44 @@
#define CheckNil(nil, ptr) ((ptr) == 0 || (ptr) == nil) #define CheckNil(nil, ptr) ((ptr) == 0 || (ptr) == nil)
#define SetNil(nil, ptr) ((ptr) = nil) #define SetNil(nil, ptr) ((ptr) = nil)
// Doubly-linked-lists
// clang-format off // 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, 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)) \ : 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)) \ : ((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))), \ : (((CheckNil(nil, ptr) && CheckNil(nil, (ptr)->next)) ? (0) : ((ptr)->next->previous = (node))), \
((node)->next = (ptr)->next), ((ptr)->next = (node)), ((node)->previous = (ptr)))) ((node)->next = (ptr)->next), ((ptr)->next = (node)), ((node)->previous = (ptr))))
// clang-format on #define DLL_push_back_next_prev_zero(nil, first, last, node, next, previous) \
#define DLL_push_back_NPZ(nil, first, last, node, next, previous) \ DLL_insert_next_prev_zero(nil, first, last, last, node, next, previous)
DLL_insert_NPZ(nil, first, last, last, node, next, previous) #define DLL_remove_next_prev_zero(nil, first, last, node, next, previous) \
#define DLL_remove_NPZ(nil, first, last, node, next, previous) \
(((node) == (first) ? (first) = (node)->next : (0)), ((node) == (last) ? (last) = (last)->previous : (0)), \ (((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)->previous) ? (0) : ((node)->previous->next = (node)->next)), \
(CheckNil(nil, (node)->next) ? (0) : ((node)->next->previous = (node)->previous))) (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) // Single (link & head) lists (= stacks)
#define SLL_stack_push_node(first, node, next) ((node)->next = (first), (first) = (node)) #define SLL_stack_push_next(first, node, next) ((node)->next = (first), (first) = (node))
#define SLL_stack_pop_node(first, next) ((first) = (first)->next); #define SLL_stack_pop_next(first, next) ((first) = (first)->next);
#define SLL_stack_push(first, node) SLL_stack_push_node(first, node, next)
#define SLL_stack_pop(first) SLL_stack_pop_node(first, next)
// Double linked list helpers // Double linked list helpers
#define DLL_push_back(first, last, node) DLL_push_back_NPZ(0, first, last, node, next, previous) #define DLL_push_back_next_prev(first, last, node, next, previous) \
#define DLL_remove(first, last, node) DLL_remove_NPZ(0, 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 // Helpers
@@ -157,6 +180,13 @@
#define ArrayCount(arr) (sizeof(arr) / sizeof((arr)[0])) #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 // Core Types
+1 -1
View File
@@ -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; 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; current = new_block;
pos_pre = AlignPow2(current->position, align); pos_pre = AlignPow2(current->position, align);
+7
View File
@@ -39,6 +39,13 @@
# error Compiler not supported. # error Compiler not supported.
#endif #endif
// ========================================================================== //
// Architecture
#if defined(ARCH_X64)
# define ARCH_64BIT 1
#endif
// ========================================================================== // // ========================================================================== //
// Language // Language
+2 -1
View File
@@ -21,5 +21,6 @@ internal uint64 uint64_hash_from_string(String8 string)
internal uint64 uint64_hash_from_seed_string(uint64 seed, 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;
} }
+11
View File
@@ -14,6 +14,17 @@ union Vector2f
float32 v[2]; float32 v[2];
}; };
typedef union Vector2i Vector2i;
union Vector2i
{
struct
{
int32 x;
int32 y;
};
int32 v[2];
};
// ============================================================================= // =============================================================================
// Rect Types // Rect Types
+97 -2
View File
@@ -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 // String Length
#include "core/core_arena.h"
internal uint64 cstring8_length(uint8* cstring) internal uint64 cstring8_length(uint8* cstring)
{ {
uint64 length = 0; uint64 length = 0;
@@ -85,7 +136,51 @@ internal String32 str32_cstring(uint32* cstring)
return result; 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 // String Formatting & Copying
internal String8 str8_copy(Arena* arena, String8 in) internal String8 str8_copy(Arena* arena, String8 in)
+35 -7
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
// ========================================================================== // // =============================================================================
// String Types // String Types
typedef struct String8 String8; typedef struct String8 String8;
@@ -24,7 +24,18 @@ struct String32
uint64 size; uint64 size;
}; };
// ========================================================================== // // =============================================================================
// String Matching Types
typedef uint32 StringMatchFlags;
enum
{
StringMatchFlag_CaseInsensitive = (1 << 0),
StringMatchFlag_RightSideSloppy = (1 << 1),
StringMatchFlag_SlashInsensitive = (1 << 2),
};
// =============================================================================
// Unicode decoding Types // Unicode decoding Types
typedef struct UnicodeDecode UnicodeDecode; typedef struct UnicodeDecode UnicodeDecode;
@@ -34,13 +45,24 @@ struct UnicodeDecode
uint32 codepoint; 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 // String Length
internal uint64 cstring8_length(uint8* cstring); internal uint64 cstring8_length(uint8* cstring);
internal uint64 cstring16_length(uint16* cstring); internal uint64 cstring16_length(uint16* cstring);
internal uint64 cstring32_length(uint32* cstring); internal uint64 cstring32_length(uint32* cstring);
// ========================================================================== // // =============================================================================
// String Constructor // String Constructor
#define str8_literal(S) str8((uint8*)(S), sizeof(S) - 1) #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 String16 str16_cstring(uint16* cstring);
internal String32 str32_cstring(uint32* 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 // String Formatting & Copying
internal String8 str8_copy(Arena* arena, String8 in); internal String8 str8_copy(Arena* arena, String8 in);
internal String8 str8fv(Arena* arena, char* fmt, va_list args); internal String8 str8fv(Arena* arena, char* fmt, va_list args);
// ========================================================================== // // =============================================================================
// Unicode String Encode/Decode // Unicode String Encode/Decode
internal UnicodeDecode utf8_decode(uint8* str, uint64 max); 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 utf8_encode(uint8* str, uint32 codepoint);
internal uint32 utf16_encode(uint16* str, uint32 codepoint); internal uint32 utf16_encode(uint16* str, uint32 codepoint);
// ========================================================================== // // =============================================================================
// Unicode String Conversions // Unicode String Conversions
internal String8 str8_from_16(Arena* arena, String16 in); internal String8 str8_from_16(Arena* arena, String16 in);
+27
View File
@@ -1,5 +1,14 @@
#pragma once #pragma once
// =============================================================================
// Synchronization primitives types
typedef struct RWMutex RWMutex;
struct RWMutex
{
uint64 handle[1];
};
// ============================================================================= // =============================================================================
// Thread Info Helpers // Thread Info Helpers
internal void set_thread_name(String8 name); internal void set_thread_name(String8 name);
@@ -10,3 +19,21 @@ internal void set_thread_namef(char* fmt, ...);
internal uint32 tid(); internal uint32 tid();
internal void set_platform_thread_name(String8 name); internal void set_platform_thread_name(String8 name);
// =============================================================================
// Synchronization primitive functions
// Read Write Mutexes functions
internal RWMutex rw_mutex_alloc();
internal void rw_mutex_release(RWMutex mutex);
internal void rw_mutex_take(RWMutex mutex, bool32 write_mode);
internal void rw_mutex_drop(RWMutex mutex, bool32 write_mode);
#define rw_mutex_take_r(m) rw_mutex_take((m), (0))
#define rw_mutex_take_w(m) rw_mutex_take((m), (1))
#define rw_mutex_drop_r(m) rw_mutex_drop((m), (0))
#define rw_mutex_drop_w(m) rw_mutex_drop((m), (1))
// Scope macros
#define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex))
#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex))
+4285
View File
File diff suppressed because it is too large. Load diff
+240 -21
View File
@@ -5,36 +5,62 @@ internal void ja_init()
ja_state->arena = arena; ja_state->arena = arena;
// Window cache // Window cache
ja_state->window_state_gen_id = 1; {
ja_state->first_window_state = ja_state->last_window_state = &ja_nil_window_state; 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() internal void ja_frame()
{ {
TempArena scratch = scratch_begin(0, 0); TempArena scratch = scratch_begin(0, 0);
ja_state->frame_depth += 1;
// ========================================================================= // =========================================================================
// Events from os // Events from os
WM_EventList events = { 0 }; WM_EventList events = { 0 };
bool32 wait = 0; if (ja_state->frame_depth == 1)
events = wm_get_events(scratch.arena, wait); {
bool32 wait = 0;
// if (hello.handle[0] == 0) events = wm_get_events(scratch.arena, wait);
// { }
// 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 // 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) for (WM_Event *event = events.first, *next = 0; event != 0; event = next)
{ {
bool32 take = 0; JA_WindowState* ws = ja_window_state_from_platform_handle(event->window);
bool32 take = 0;
if (event->kind == WM_EventKind_WindowClose) if (event->kind == WM_EventKind_WindowClose)
{ {
ja_state->quit = 1; if (ws != 0)
take = 1; {
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) if (take)
@@ -46,20 +72,83 @@ internal void ja_frame()
// Window management (open/render) // Window management (open/render)
{ {
for for EachNode(request, JA_WindowRequest, ja_state->window_request_first)
EachIndex(slot_idx, ja_state->window_state_gen_id) {
{ JA_WindowState* ws = ja_window_state_from_id(request->id);
JA_WindowState* ws = ja_window_state_from_id(slot_idx);
} // 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); scratch_end(scratch);
} }
internal void ja_shutdown() internal void ja_shutdown()
{ {
// wm_window_close(aaa); arena_release(ja_state->arena);
arena_clear(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;
} }
// ============================================================================= // =============================================================================
@@ -75,10 +164,140 @@ internal JA_WindowState* ja_window_state_from_id(JA_ID id)
} }
else else
{ {
uint64 hash = uint64_hash_from_string(str8_struct(&id)); 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 // 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; 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;
}
+62 -7
View File
@@ -4,18 +4,54 @@
// Core Types // Core Types
typedef uint64 JA_ID; 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 // 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; typedef struct JA_WindowState JA_WindowState;
struct JA_WindowState struct JA_WindowState
{ {
// links and metadata
JA_WindowState* order_next; JA_WindowState* order_next;
JA_WindowState* order_previous; JA_WindowState* order_previous;
JA_WindowState* hash_next; JA_WindowState* hash_next;
JA_WindowState* hash_previous; JA_WindowState* hash_previous;
JA_ID id; JA_ID id;
WM_Window plat_handle; 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; typedef struct JA_State JA_State;
@@ -24,13 +60,23 @@ struct JA_State
// Base // Base
Arena* arena; Arena* arena;
bool32 quit; 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 // Windows
JA_WindowState* first_window_state; JA_WindowState* free_window_state;
JA_WindowState* last_window_state; uint64 window_state_slots_count;
JA_WindowState* window_state_last_accessed; JA_WindowStateSlot* window_state_slots;
JA_ID window_state_last_accessed_id; JA_WindowState* first_window_state;
JA_ID window_state_gen_id; JA_WindowState* last_window_state;
JA_ID window_state_last_accessed_id;
JA_WindowState* window_state_last_accessed;
}; };
// ============================================================================= // =============================================================================
@@ -47,7 +93,16 @@ internal void ja_init();
internal void ja_frame(); internal void ja_frame();
internal void ja_shutdown(); internal void ja_shutdown();
// =============================================================================
// Id Functions
internal void ja_id_list_push(Arena* arena, JA_IDList* list, JA_ID id);
// ============================================================================= // =============================================================================
// Window Functions // Window Functions
internal JA_WindowState* ja_window_state_from_id(JA_ID id); 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
View File
@@ -4,12 +4,14 @@
// Headers // Headers
#include "core/core_inc.h" #include "core/core_inc.h"
#include "shell/shell_inc.h"
#include "window_manager/window_manager_inc.h" #include "window_manager/window_manager_inc.h"
#include "render/render_inc.h" #include "render/render_inc.h"
#include "julietapp/julietapp_inc.h" #include "julietapp/julietapp_inc.h"
// C // C
#include "core/core_inc.c" #include "core/core_inc.c"
#include "shell/shell_inc.c"
#include "window_manager/window_manager_inc.c" #include "window_manager/window_manager_inc.c"
#include "render/render_inc.c" #include "render/render_inc.c"
#include "julietapp/julietapp_inc.c" #include "julietapp/julietapp_inc.c"
@@ -24,6 +26,7 @@ internal bool32 frame()
internal void entry_point() internal void entry_point()
{ {
wm_init(); wm_init();
r_init();
ja_init(); ja_init();
for (bool32 quit = 0; !quit;) for (bool32 quit = 0; !quit;)
@@ -31,4 +34,5 @@ internal void entry_point()
quit = update(); quit = update();
} }
ja_shutdown(); ja_shutdown();
r_shutdown();
} }
+392
View File
@@ -0,0 +1,392 @@
// TODO : Adapt stuff from D3D12GraphicsDevice.c specially all the shenanigans with dxgi factory and stuff
// TODO : Support more kind of format (HDR)
// =============================================================================
// Helpers
internal R_D3D12_Window* r_d3d12_window_from_handle(R_Handle handle)
{
R_D3D12_Window* window = (R_D3D12_Window*)handle.u64[0];
if (window == 0)
{
window = &r_d3d12_nil_window;
}
return window;
}
internal R_Handle r_d3d12_handle_from_window(R_D3D12_Window* window)
{
R_Handle handle = { 0 };
handle.u64[0] = (uint64)window;
return handle;
}
// =============================================================================
// Wait Function
internal void r_d3d12_wait()
{
r_d3d12_state->fence_value += 1;
ID3D12CommandQueue_Signal(r_d3d12_state->direct_command_queue, r_d3d12_state->fence, r_d3d12_state->fence_value);
if (ID3D12Fence_GetCompletedValue(r_d3d12_state->fence) < r_d3d12_state->fence_value)
{
ID3D12Fence_SetEventOnCompletion(r_d3d12_state->fence, r_d3d12_state->fence_value, r_d3d12_state->fence_event);
WaitForSingleObject(r_d3d12_state->fence_event, INFINITE);
}
}
// =============================================================================
// top level layer initialization
void r_init()
{
HRESULT error = 0;
Arena* arena = arena_alloc();
r_d3d12_state = push_array(arena, R_D3D12_State, 1);
r_d3d12_state->arena = arena;
r_d3d12_state->device_rw_mutex = rw_mutex_alloc();
// Create base device
D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_12_1;
UINT dxgi_flags = 0;
#if BUILD_DEBUG
ID3D12Debug1* debug_controller = 0;
if (SUCCEEDED(D3D12GetDebugInterface(&IID_ID3D12Debug1, (void**)&debug_controller)))
{
ID3D12Debug1_EnableDebugLayer(debug_controller);
ID3D12Debug1_SetEnableGPUBasedValidation(debug_controller, TRUE);
ID3D12Debug1_Release(debug_controller);
}
dxgi_flags |= DXGI_CREATE_FACTORY_DEBUG;
#endif
error = CreateDXGIFactory2(dxgi_flags, &IID_IDXGIFactory4, (void**)&r_d3d12_state->dxgi_factory);
if (FAILED(error))
{
char buffer[256] = { 0 };
juliet_snprintf(buffer, sizeof(buffer), "D3D12 DXGI factory creation failure (%lx). Process is terminating", error);
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
abort_self(1);
}
// dxgi setup (device and adapter)
IDXGIFactory6* factory6 = 0;
error = IDXGIFactory4_QueryInterface(r_d3d12_state->dxgi_factory, &IID_IDXGIFactory6, (void**)&factory6);
if (SUCCEEDED(error))
{
// Prioritize discrete GPU
error = IDXGIFactory6_EnumAdapterByGpuPreference(factory6, 0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
&IID_IDXGIAdapter1, (void**)&r_d3d12_state->dxgi_adapter);
IDXGIFactory6_Release(factory6);
}
else
{
// Pray device 0 is the discrete gpu
error = IDXGIFactory4_EnumAdapters1(r_d3d12_state->dxgi_factory, 0, &r_d3d12_state->dxgi_adapter);
}
error = D3D12CreateDevice((IUnknown*)r_d3d12_state->dxgi_adapter, feature_level, &IID_ID3D12Device4,
(void**)&r_d3d12_state->device);
// Try warp as hardware is no available
if (FAILED(error))
{
IDXGIAdapter1_Release(r_d3d12_state->dxgi_adapter);
error = IDXGIFactory4_EnumWarpAdapter(r_d3d12_state->dxgi_factory, &IID_IDXGIAdapter, (void**)&r_d3d12_state->dxgi_adapter);
if (SUCCEEDED(error))
{
error = D3D12CreateDevice((IUnknown*)r_d3d12_state->dxgi_adapter, feature_level, &IID_ID3D12Device4,
(void**)&r_d3d12_state->device);
}
}
if (FAILED(error))
{
char buffer[256] = { 0 };
juliet_snprintf(buffer, sizeof(buffer), "D3D12 device factory creation failure (%lx). Process is terminating", error);
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
abort_self(1);
}
// break on error
#if BUILD_DEBUG
ID3D12InfoQueue* info = 0;
error = ID3D12Device4_QueryInterface(r_d3d12_state->device, &IID_ID3D12InfoQueue, (void**)&info);
if (SUCCEEDED(error))
{
error = ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
error = ID3D12InfoQueue_SetBreakOnSeverity(info, D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
ID3D12InfoQueue_Release(info);
}
#endif
// Create basic graphics queue
D3D12_COMMAND_QUEUE_DESC queue_desc = { 0 };
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
error = ID3D12Device4_CreateCommandQueue(r_d3d12_state->device, &queue_desc, &IID_ID3D12CommandQueue,
(void**)&r_d3d12_state->direct_command_queue);
if (FAILED(error))
{
char buffer[256] = { 0 };
juliet_snprintf(buffer, sizeof(buffer), "D3D12 direct command queue creation failure (%lx). Process is terminating", error);
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
abort_self(1);
}
// Create command allocator and command list
for EachIndex(i, 2)
{
ID3D12Device4_CreateCommandAllocator(r_d3d12_state->device, D3D12_COMMAND_LIST_TYPE_DIRECT,
&IID_ID3D12CommandAllocator, (void**)&r_d3d12_state->command_allocators[i]);
}
ID3D12Device4_CreateCommandList1(r_d3d12_state->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_LIST_FLAG_NONE,
&IID_ID3D12GraphicsCommandList, (void**)&r_d3d12_state->command_list);
ID3D12Device4_CreateFence(r_d3d12_state->device, 0, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, (void**)&r_d3d12_state->fence);
r_d3d12_state->fence_event = CreateEventW(0, FALSE, FALSE, 0);
}
void r_shutdown()
{
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
r_d3d12_wait();
CloseHandle(r_d3d12_state->fence_event);
ID3D12Fence_Release(r_d3d12_state->fence);
for EachIndex(i,2)
{
ID3D12CommandAllocator_Release(r_d3d12_state->command_allocators[i]);
}
ID3D12CommandList_Release(r_d3d12_state->command_list);
ID3D12CommandQueue_Release(r_d3d12_state->direct_command_queue);
ID3D12Device4_Release(r_d3d12_state->device);
IDXGIAdapter1_Release(r_d3d12_state->dxgi_adapter);
IDXGIFactory4_Release(r_d3d12_state->dxgi_factory);
}
rw_mutex_release(r_d3d12_state->device_rw_mutex);
arena_release(r_d3d12_state->arena);
}
// =============================================================================
// window setup/teardown
R_Handle r_window_equip(WM_Window handle)
{
R_Handle result = { 0 };
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
R_D3D12_Window* window = r_d3d12_state->first_free_window;
if (window != 0)
{
SLL_stack_pop(r_d3d12_state->first_free_window);
MemoryZeroStruct(window);
}
else
{
window = push_array(r_d3d12_state->arena, R_D3D12_Window, 1);
}
HWND hwnd = { 0 };
{
W32_WM_Window* w32_layer_window = w32_wm_window_from_handle(handle);
hwnd = w32_wm_hwnd_from_window(w32_layer_window);
}
// Create swapchain
DXGI_SWAP_CHAIN_DESC1 swapchain_desc = { 0 };
swapchain_desc.Width = 0; // Use all window width
swapchain_desc.Height = 0; // Use all window height
swapchain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapchain_desc.Stereo = 0;
swapchain_desc.SampleDesc.Count = 1;
swapchain_desc.SampleDesc.Quality = 0;
swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapchain_desc.BufferCount = 2; // Double buffering
swapchain_desc.Scaling = DXGI_SCALING_NONE;
swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapchain_desc.Flags = 0;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapchain_fullscreen_desc = { 0 };
swapchain_fullscreen_desc.RefreshRate.Numerator = 0;
swapchain_fullscreen_desc.RefreshRate.Denominator = 0;
swapchain_fullscreen_desc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapchain_fullscreen_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapchain_fullscreen_desc.Windowed = TRUE;
IDXGISwapChain1* swapchain1 = 0;
HRESULT error = IDXGIFactory4_CreateSwapChainForHwnd(r_d3d12_state->dxgi_factory,
(IUnknown*)r_d3d12_state->direct_command_queue, hwnd,
&swapchain_desc, &swapchain_fullscreen_desc, 0, &swapchain1);
if (FAILED(error))
{
char buffer[256];
juliet_snprintf(buffer, sizeof(buffer), "DXGI swap chain creation failure (%lx). Process is terminating.", error);
sh_message(1, str8_literal("Fatal Error"), str8_cstring(buffer));
abort_self(1);
}
IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void**)&window->swapchain);
IDXGISwapChain1_Release(swapchain1);
IDXGIFactory4_MakeWindowAssociation(r_d3d12_state->dxgi_factory, hwnd, DXGI_MWA_NO_ALT_ENTER);
// Create framebuffer and rtv for swapchain
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc = { 0 };
rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtv_heap_desc.NumDescriptors = 2;
rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ID3D12Device4_CreateDescriptorHeap(r_d3d12_state->device, &rtv_heap_desc, &IID_ID3D12DescriptorHeap,
(void**)&window->rtv_heap);
UINT rtv_stride = ID3D12Device4_GetDescriptorHandleIncrementSize(r_d3d12_state->device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = { 0 };
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(window->rtv_heap, &rtv_handle);
for (UINT i = 0; i < 2; ++i)
{
window->rtv_handles[i] = rtv_handle;
IDXGISwapChain3_GetBuffer(window->swapchain, i, &IID_ID3D12Resource, (void**)&window->framebuffer[i]);
ID3D12Device4_CreateRenderTargetView(r_d3d12_state->device, window->framebuffer[i], 0, window->rtv_handles[i]);
rtv_handle.ptr += rtv_stride;
}
// Save resolution in case of resize
Rect2f client_rect = wm_client_rect_from_window(handle);
Vector2i resolution = { (int32)(client_rect.x1 - client_rect.x0), (int32)(client_rect.y1 - client_rect.y0) };
window->last_resolution = resolution;
result = r_d3d12_handle_from_window(window);
}
return result;
}
void r_window_unequip(WM_Window handle, R_Handle handle_equip)
{
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
r_d3d12_wait();
R_D3D12_Window* window = r_d3d12_window_from_handle(handle_equip);
if (window != 0 && window != &r_d3d12_nil_window)
{
for EachIndex(i, 2)
{
ID3D12Resource_Release(window->framebuffer[i]);
}
ID3D12DescriptorHeap_Release(window->rtv_heap);
IDXGISwapChain1_Release(window->swapchain);
SLL_stack_push(r_d3d12_state->first_free_window, window);
}
}
}
// frame markers
void r_begin_frame()
{
// No-op
}
void r_end_frame()
{
// pouet
}
void r_window_begin_frame(WM_Window window, R_Handle window_equip)
{
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
R_D3D12_Window* r_window = r_d3d12_window_from_handle(window_equip);
// Get resolution
Rect2f client_rect = wm_client_rect_from_window(window);
Vector2i resolution = { (int32)(client_rect.x1 - client_rect.x0), (int32)(client_rect.y1 - client_rect.y0) };
// change resolution
if (resolution.x > 0 && resolution.y > 0 &&
(r_window->last_resolution.x != resolution.x || r_window->last_resolution.y != resolution.y))
{
r_window->last_resolution = resolution;
// resize swap chain
r_d3d12_wait();
for EachIndex(i,2)
{
if (r_window->framebuffer[i] != 0)
{
ID3D12Resource_Release(r_window->framebuffer[i]);
r_window->framebuffer[i] = 0;
}
}
IDXGISwapChain3_ResizeBuffers(r_window->swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
for EachIndex(i,2)
{
IDXGISwapChain3_GetBuffer(r_window->swapchain, i, &IID_ID3D12Resource, (void**)&r_window->framebuffer[i]);
ID3D12Device4_CreateRenderTargetView(r_d3d12_state->device, r_window->framebuffer[i], 0, r_window->rtv_handles[i]);
}
}
// Open the command list for that window that frame
// TODO : multiple command list as we have multiple windows
r_window->framebuffer_idx = IDXGISwapChain3_GetCurrentBackBufferIndex(r_window->swapchain);
ID3D12CommandAllocator* allocator = r_d3d12_state->command_allocators[r_window->framebuffer_idx];
ID3D12GraphicsCommandList* cmd_list = r_d3d12_state->command_list;
ID3D12CommandAllocator_Reset(allocator);
ID3D12GraphicsCommandList1_Reset(cmd_list, allocator, 0);
// Barrier to transition from Present (end of frame) to render target
D3D12_RESOURCE_BARRIER barrier = { 0 };
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = r_window->framebuffer[r_window->framebuffer_idx];
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
ID3D12GraphicsCommandList_ResourceBarrier(cmd_list, 1, &barrier);
// HARDCODED
// BLUE
float32 background[4] = { 0.1f, 0.2f, 0.8f, 1.0f };
ID3D12GraphicsCommandList_ClearRenderTargetView(cmd_list, r_window->rtv_handles[r_window->framebuffer_idx],
background, 0, 0);
}
}
void r_window_end_frame(WM_Window window, R_Handle window_equip)
{
MutexScopeW(r_d3d12_state->device_rw_mutex)
{
R_D3D12_Window* r_window = r_d3d12_window_from_handle(window_equip);
ID3D12GraphicsCommandList* cmd_list = r_d3d12_state->command_list;
// Transition from render target to present
D3D12_RESOURCE_BARRIER barrier = { 0 };
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = r_window->framebuffer[r_window->framebuffer_idx];
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
ID3D12GraphicsCommandList_ResourceBarrier(cmd_list, 1, &barrier);
// Close command list and push it onto the command queue
ID3D12GraphicsCommandList_Close(cmd_list);
ID3D12CommandQueue_ExecuteCommandLists(r_d3d12_state->direct_command_queue, 1, (ID3D12CommandList**)&cmd_list);
IDXGISwapChain3_Present(r_window->swapchain, 1, 0);
// Fence until gpu finishes work
r_d3d12_wait();
}
}
+71
View File
@@ -1 +1,72 @@
#pragma once #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();
+29
View File
@@ -1 +1,30 @@
#pragma once #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);
View File
Whitespace-only changes.
+6
View File
@@ -0,0 +1,6 @@
#pragma once
// =============================================================================
// Shell operations
internal void sh_message(bool32 error, String8 title, String8 message);
+7
View File
@@ -0,0 +1,7 @@
#include "shell.c"
#if OS_WINDOWS
# include "win32/shell/win32_shell.c"
#else
# error Shell functions not implemented for this operating system
#endif
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "shell.h"
#if OS_WINDOWS
# include "win32/shell/win32_shell.h"
#else
# error Shell functions not implemented for this operating system
#endif
+81
View File
@@ -6,6 +6,38 @@ typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDes
W32_KERNEL32_EXT_X_LIST W32_KERNEL32_EXT_X_LIST
#undef X #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 // Time functions
@@ -85,6 +117,51 @@ internal void set_platform_thread_name(String8 name)
scratch_end(scratch); 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 // 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); main_thread_core_entry_point(argc, argv);
tctx_release(tctx); tctx_release(tctx);
+41 -3
View File
@@ -7,13 +7,51 @@
#pragma comment(lib, "shell32") #pragma comment(lib, "shell32")
// clang-format on // 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; typedef struct W32_State W32_State;
struct W32_State struct W32_State
{ {
Arena* arena; Arena* arena;
SystemInfo system_info;
uint64 microsecond_resolution; // 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 }; global W32_State w32_state = { 0 };
// =============================================================================
// Entity Functions
internal W32_Entity* w32_entity_alloc(W32_EntityKind kind);
internal void w32_entity_release(W32_Entity* entity);
+11
View File
@@ -0,0 +1,11 @@
// =============================================================================
// Shell operations
internal void sh_message(bool32 error, String8 title, String8 message)
{
TempArena scratch = scratch_begin(0, 0);
String16 title16 = str16_from_8(scratch.arena, title);
String16 message16 = str16_from_8(scratch.arena, message);
MessageBoxW(0, (WCHAR*)message16.str, (WCHAR*)title16.str, MB_OK | (!!error * MB_ICONERROR));
scratch_end(scratch);
}
+1
View File
@@ -0,0 +1 @@
#pragma once
+456 -4
View File
@@ -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) 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->window = w32_wm_handle_from_window(window);
result->modifiers = wm_get_modifiers(); result->modifiers = wm_get_modifiers();
return result; 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) internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
LRESULT result = 0; LRESULT result = 0;
@@ -152,6 +377,91 @@ internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa
break; 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: case WM_SETCURSOR:
{ {
Rect2f window_rect = wm_client_rect_from_window(window_handle); 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; 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() internal void wm_init()
{ {
// Setup based state // 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) internal Rect2f wm_client_rect_from_window(WM_Window handle)
{ {
Rect2f result = { 0 }; Rect2f result = { 0 };
@@ -521,6 +876,92 @@ internal Rect2f wm_client_rect_from_window(WM_Window handle)
return result; 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 // Events
@@ -553,21 +994,32 @@ internal WM_EventList wm_get_events(Arena* arena, bool32 wait)
internal WM_Modifiers wm_get_modifiers() internal WM_Modifiers wm_get_modifiers()
{ {
WM_Modifiers modifiers = 0; WM_Modifiers modifiers = 0;
if (GetKeyState(VK_CONTROL) * 0x8000) if (GetKeyState(VK_CONTROL) & 0x8000)
{ {
modifiers |= WM_Modifier_Ctrl; modifiers |= WM_Modifier_Ctrl;
} }
if (GetKeyState(VK_SHIFT) * 0x8000) if (GetKeyState(VK_SHIFT) & 0x8000)
{ {
modifiers |= WM_Modifier_Shift; modifiers |= WM_Modifier_Shift;
} }
if (GetKeyState(VK_MENU) * 0x8000) if (GetKeyState(VK_MENU) & 0x8000)
{ {
modifiers |= WM_Modifier_Alt; modifiers |= WM_Modifier_Alt;
} }
return modifiers; 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) internal Vector2f wm_mouse_from_window(WM_Window handle)
{ {
Vector2f result = { 0 }; Vector2f result = { 0 };
+28 -1
View File
@@ -27,6 +27,25 @@ struct W32_WM_Window
Arena* paint_arena; 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 // 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 W32_WM_Window* w32_wm_window_from_hwnd(HWND hwnd);
internal HWND w32_wm_hwnd_from_window(W32_WM_Window* window); internal HWND w32_wm_hwnd_from_window(W32_WM_Window* window);
internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd); 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 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);
+53
View File
@@ -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 // Event Functions
@@ -7,6 +28,38 @@ internal void wm_eat_event(WM_EventList* events, WM_Event* event)
events->count -= 1; 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) 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); WM_Event* evt = push_array(arena, WM_Event, 1);
+27
View File
@@ -62,6 +62,7 @@ typedef enum WM_EventKind
WM_EventKind_Press, WM_EventKind_Press,
WM_EventKind_Release, WM_EventKind_Release,
WM_EventKind_MouseMove, WM_EventKind_MouseMove,
WM_EventKind_Text,
WM_EventKind_WindowClose, WM_EventKind_WindowClose,
WM_EventKind_COUNT WM_EventKind_COUNT
} WM_EventKind; } WM_EventKind;
@@ -84,6 +85,10 @@ struct WM_Event
WM_EventKind kind; WM_EventKind kind;
WM_Modifiers modifiers; WM_Modifiers modifiers;
WM_Key key; WM_Key key;
bool32 is_repeat;
bool32 right_sided;
uint32 character;
uint32 repeat_count;
}; };
typedef struct WM_EventList WM_EventList; typedef struct WM_EventList WM_EventList;
@@ -99,10 +104,19 @@ struct WM_EventList
internal bool32 frame(); 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 // Event Functions
internal void wm_eat_event(WM_EventList* events, WM_Event* event); 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); 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 WM_Window wm_widow_open(Rect2f rect, WM_WindowFlags flags, String8 title);
internal void wm_window_close(WM_Window handle); internal void wm_window_close(WM_Window handle);
internal void wm_window_first_paint(WM_Window 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); 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 // Events
internal void wm_send_wakeup_event(); internal void wm_send_wakeup_event();
internal WM_EventList wm_get_events(Arena* arena, bool32 wait); internal WM_EventList wm_get_events(Arena* arena, bool32 wait);
internal WM_Modifiers wm_get_modifiers(); internal WM_Modifiers wm_get_modifiers();
internal bool32 wm_key_is_down(WM_Key key);
internal Vector2f wm_mouse_from_window(WM_Window window); internal Vector2f wm_mouse_from_window(WM_Window window);
// ============================================================================= // =============================================================================