Os monitors query
This commit is contained in:
parent
f2b81a0621
commit
b7921693c4
13 changed files with 241 additions and 24 deletions
|
@ -6,6 +6,6 @@ mkdir build
|
|||
|
||||
pushd build
|
||||
|
||||
clang -g -fuse-ld=lld -o cgame.exe ../build.c -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -ldbghelp -femit-all-decls
|
||||
clang -g -fuse-ld=lld -o cgame.exe ../build.c -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lshcore -lavrt -lksuser -ldbghelp -femit-all-decls
|
||||
|
||||
popd
|
4
build.c
4
build.c
|
@ -33,9 +33,9 @@ typedef struct Context_Extra {
|
|||
//
|
||||
|
||||
// This is a minimal starting point for new projects. Copy & rename to get started
|
||||
// #include "oogabooga/examples/minimal_game_loop.c"
|
||||
#include "oogabooga/examples/minimal_game_loop.c"
|
||||
|
||||
#include "oogabooga/examples/text_rendering.c"
|
||||
// #include "oogabooga/examples/text_rendering.c"
|
||||
// #include "oogabooga/examples/custom_logger.c"
|
||||
// #include "oogabooga/examples/renderer_stress_test.c"
|
||||
// #include "oogabooga/examples/tile_game.c"
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
## v0.01.005
|
||||
|
||||
|
||||
## v0.01.004 - Gamepad input, text wrapping, bug fixes
|
||||
- Input
|
||||
- Added Gamepad support
|
||||
|
|
|
@ -17,7 +17,7 @@ dump_stack_trace();
|
|||
|
||||
#define ASSERT_STR_HELPER(x) #x
|
||||
#define ASSERT_STR(x) ASSERT_STR_HELPER(x)
|
||||
#define assert_line(line, cond, ...) {if(!(cond)) { printf("Assertion failed in file " __FILE__ " on line " ASSERT_STR(line) "\nFailed Condition: " #cond ". Message: " __VA_ARGS__); dump_stack_trace(); crash(); }}
|
||||
#define assert_line(line, cond, ...) {if(!(cond)) { printf("\nAssertion failed in file " __FILE__ " on line " ASSERT_STR(line) "\n\nFailed Condition: " #cond ". Message: " __VA_ARGS__); printf("\n"); dump_stack_trace(); crash(); }}
|
||||
#define assert(cond, ...) {assert_line(__LINE__, cond, __VA_ARGS__)}
|
||||
|
||||
#define DEFER(start, end) for(int _i_ = ((start), 0); _i_ == 0; _i_ += 1, (end))
|
||||
|
|
|
@ -10,12 +10,12 @@ int entry(int argc, char **argv) {
|
|||
|
||||
float64 last_time = os_get_elapsed_seconds();
|
||||
while (!window.should_close) {
|
||||
reset_temporary_storage();
|
||||
|
||||
float64 now = os_get_elapsed_seconds();
|
||||
if ((int)now != (int)last_time) log("%.2f FPS\n%.2fms", 1.0/(now-last_time), (now-last_time)*1000);
|
||||
last_time = now;
|
||||
|
||||
reset_temporary_storage();
|
||||
|
||||
Matrix4 rect_xform = m4_scalar(1.0);
|
||||
rect_xform = m4_rotate_z(rect_xform, (f32)now);
|
||||
rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0));
|
||||
|
|
|
@ -31,7 +31,10 @@ int entry(int argc, char **argv) {
|
|||
Gfx_Font *font = load_font_from_disk(STR("C:/windows/fonts/arial.ttf"), get_heap_allocator());
|
||||
assert(font, "Failed loading arial.ttf, %d", GetLastError());
|
||||
|
||||
render_atlas_if_not_yet_rendered(font, 32, 'A');
|
||||
// This makes sure atlas is rendered for ascii.
|
||||
// You might want to do this if your game lags the first time you render text because it renders
|
||||
// the atlas on the fly.
|
||||
render_atlas_if_not_yet_rendered(font, 32, 'A');
|
||||
|
||||
seed_for_random = rdtsc();
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
Gamepad input:
|
||||
|
||||
(!! Only Xbox gamepads are natively supported. Steam will map playstation controllers to xbox, but you need third party software to map playstation controllers to xbox. See DS4Windows. !!)
|
||||
|
||||
Vector2 input_frame.left_stick
|
||||
Vector2 input_frame.right_stick
|
||||
float32 input_frame.left_trigger
|
||||
|
|
|
@ -619,6 +619,7 @@ void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void* da
|
|||
return 0;
|
||||
}
|
||||
case ALLOCATOR_REALLOCATE: {
|
||||
panic("Temporary allocator cannot 'reallocate'");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -662,4 +663,76 @@ void reset_temporary_storage() {
|
|||
has_warned_temporary_storage_overflow = false;
|
||||
}
|
||||
|
||||
#endif // NOT OOGABOOGA_LINK_EXTERNAL_INSTANCE
|
||||
#endif // NOT OOGABOOGA_LINK_EXTERNAL_INSTANCE
|
||||
|
||||
|
||||
typedef struct Arena {
|
||||
void *start;
|
||||
void *next;
|
||||
u64 size;
|
||||
} Arena;
|
||||
|
||||
void* arena_allocator_proc(u64 size, void *p, Allocator_Message message, void* data) {
|
||||
if (size > 8) size = align_next(size, 8);
|
||||
Arena *arena = (Arena*)data;
|
||||
switch (message) {
|
||||
case ALLOCATOR_ALLOCATE: {
|
||||
void *p = arena->next;
|
||||
|
||||
arena->next = (u8*)arena->next + size;
|
||||
break;
|
||||
}
|
||||
case ALLOCATOR_DEALLOCATE: {
|
||||
return 0;
|
||||
}
|
||||
case ALLOCATOR_REALLOCATE: {
|
||||
panic("Arena allocator cannot 'reallocate'");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocates arena from heap
|
||||
Arena make_arena(u64 size) {
|
||||
size = align_next(size, 8);
|
||||
Arena arena;
|
||||
|
||||
arena.start = alloc(get_heap_allocator(), size);
|
||||
arena.next = arena.start;
|
||||
arena.size = size;
|
||||
|
||||
return arena;
|
||||
}
|
||||
|
||||
// Allocates arena from heap
|
||||
Allocator make_arena_allocator(u64 size) {
|
||||
void *mem = alloc(get_heap_allocator(), size + sizeof(Arena));
|
||||
|
||||
Arena *arena = (Arena*)mem;
|
||||
|
||||
arena->start = (u8*)mem + sizeof(Arena);
|
||||
arena->next = arena->start;
|
||||
arena->size = size;
|
||||
|
||||
Allocator allocator;
|
||||
allocator.data = arena;
|
||||
allocator.proc = arena_allocator_proc;
|
||||
|
||||
return allocator;
|
||||
}
|
||||
Allocator make_arena_allocator_with_memory(u64 size, void *p) {
|
||||
void *mem = alloc(get_heap_allocator(), size + sizeof(Arena));
|
||||
|
||||
Arena *arena = (Arena*)alloc(get_heap_allocator(), sizeof(Arena));
|
||||
|
||||
arena->start = p;
|
||||
arena->next = arena->start;
|
||||
arena->size = size;
|
||||
|
||||
Allocator allocator;
|
||||
allocator.data = arena;
|
||||
allocator.proc = arena_allocator_proc;
|
||||
|
||||
return allocator;
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
|
||||
#define OGB_VERSION_MAJOR 0
|
||||
#define OGB_VERSION_MINOR 1
|
||||
#define OGB_VERSION_PATCH 4
|
||||
#define OGB_VERSION_PATCH 5
|
||||
|
||||
#define OGB_VERSION (OGB_VERSION_MAJOR*1000000+OGB_VERSION_MINOR*1000+OGB_VERSION_PATCH)
|
||||
|
||||
|
@ -391,15 +391,18 @@ void oogabooga_init(u64 program_memory_size) {
|
|||
#else
|
||||
log_info("Headless mode on");
|
||||
#endif
|
||||
log_verbose("CPU has sse1: %cs", features.sse1 ? "true" : "false");
|
||||
log_verbose("CPU has sse2: %cs", features.sse2 ? "true" : "false");
|
||||
log_verbose("CPU has sse3: %cs", features.sse3 ? "true" : "false");
|
||||
log_verbose("CPU has ssse3: %cs", features.ssse3 ? "true" : "false");
|
||||
log_verbose("CPU has sse41: %cs", features.sse41 ? "true" : "false");
|
||||
log_verbose("CPU has sse42: %cs", features.sse42 ? "true" : "false");
|
||||
log_verbose("CPU has avx: %cs", features.avx ? "true" : "false");
|
||||
log_verbose("CPU has avx2: %cs", features.avx2 ? "true" : "false");
|
||||
log_verbose("CPU has sse1: %cs", features.sse1 ? "true" : "false");
|
||||
log_verbose("CPU has sse2: %cs", features.sse2 ? "true" : "false");
|
||||
log_verbose("CPU has sse3: %cs", features.sse3 ? "true" : "false");
|
||||
log_verbose("CPU has ssse3: %cs", features.ssse3 ? "true" : "false");
|
||||
log_verbose("CPU has sse41: %cs", features.sse41 ? "true" : "false");
|
||||
log_verbose("CPU has sse42: %cs", features.sse42 ? "true" : "false");
|
||||
log_verbose("CPU has avx: %cs", features.avx ? "true" : "false");
|
||||
log_verbose("CPU has avx2: %cs", features.avx2 ? "true" : "false");
|
||||
log_verbose("CPU has avx512: %cs", features.avx512 ? "true" : "false");
|
||||
|
||||
Os_Monitor *m = os.primary_monitor;
|
||||
log_verbose("Primary Monitor:\n\t%s\n\t%dhz\n\t%dx%d\n\tdpi: %d", m->name, m->refresh_rate, m->resolution_x, m->resolution_y, m->dpi);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <initguid.h>
|
||||
#include <avrt.h>
|
||||
#include <xinput.h>
|
||||
#include <shellscalingapi.h>
|
||||
|
||||
#define VIRTUAL_MEMORY_BASE ((void*)0x0000690000000000ULL)
|
||||
|
||||
|
@ -163,6 +164,7 @@ void win32_handle_key_repeat(Input_Key_Code code, s64 gamepad_index) {
|
|||
win32_send_key_event(code, win32_key_states[code], gamepad_index);
|
||||
}
|
||||
|
||||
void win32_query_monitors();
|
||||
|
||||
LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wparam, LPARAM lparam) {
|
||||
|
||||
|
@ -265,6 +267,12 @@ LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wpar
|
|||
}
|
||||
break;
|
||||
}
|
||||
case WM_DISPLAYCHANGE: {
|
||||
|
||||
win32_query_monitors();
|
||||
|
||||
goto DEFAULT_HANDLE;
|
||||
}
|
||||
default:
|
||||
|
||||
DEFAULT_HANDLE:
|
||||
|
@ -360,7 +368,6 @@ void os_init(u64 program_memory_capacity) {
|
|||
context.thread_id = GetCurrentThreadId();
|
||||
|
||||
|
||||
|
||||
#if CONFIGURATION == RELEASE
|
||||
// #Configurable #Copypaste
|
||||
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
|
||||
|
@ -379,9 +386,9 @@ void os_init(u64 program_memory_capacity) {
|
|||
os.static_memory_start = 0;
|
||||
os.static_memory_end = 0;
|
||||
|
||||
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
|
||||
|
||||
unsigned char* addr = 0;
|
||||
while (VirtualQuery(addr, &mbi, sizeof(mbi))) {
|
||||
if (mbi.Type == MEM_IMAGE) {
|
||||
|
@ -433,6 +440,57 @@ void os_init(u64 program_memory_capacity) {
|
|||
|
||||
|
||||
|
||||
win32_query_monitors();
|
||||
}
|
||||
|
||||
BOOL win32_query_monitors_callback(HMONITOR monitor_handle, HDC dc, LPRECT rect, LPARAM param) {
|
||||
MONITORINFOEX info = ZERO(MONITORINFOEX);
|
||||
info.cbSize = sizeof(MONITORINFOEX);
|
||||
BOOL ok = GetMonitorInfo(monitor_handle, (MONITORINFO*)&info);
|
||||
assert(ok, "GetMonitorInfo failed");
|
||||
|
||||
string monitor_id;
|
||||
monitor_id.count = strlen(info.szDevice);
|
||||
monitor_id.data = (u8*)info.szDevice;
|
||||
|
||||
u16 *monitor_id_wide = temp_win32_fixed_utf8_to_null_terminated_wide(monitor_id);
|
||||
|
||||
DEVMODEW more_info = ZERO(DEVMODEW);
|
||||
u16 *name_wide = temp_win32_fixed_utf8_to_null_terminated_wide(monitor_id);
|
||||
ok = EnumDisplaySettingsW(name_wide, ENUM_CURRENT_SETTINGS, &more_info);
|
||||
assert(ok, "EnumDisplaySettingsW failed");
|
||||
|
||||
DISPLAY_DEVICEW even_more_info = ZERO(DISPLAY_DEVICEW);
|
||||
even_more_info.cb = sizeof(DISPLAY_DEVICE);
|
||||
bool display_device_found = false;
|
||||
for (DWORD i = 0; EnumDisplayDevicesW(NULL, i, &even_more_info, 0); ++i) {
|
||||
if (wcscmp(even_more_info.DeviceName, monitor_id_wide) == 0) {
|
||||
display_device_found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(display_device_found, "DISPLAY_DEVICE not found");
|
||||
|
||||
Os_Monitor *monitor = (Os_Monitor*)growing_array_add_empty((void**)&os.monitors);
|
||||
memset(monitor, 0, sizeof(Os_Monitor));
|
||||
if (info.dwFlags & MONITORINFOF_PRIMARY) os.primary_monitor = monitor;
|
||||
|
||||
monitor->name = temp_win32_null_terminated_wide_to_fixed_utf8(even_more_info.DeviceString);
|
||||
monitor->refresh_rate = more_info.dmDisplayFrequency;
|
||||
monitor->resolution_x = info.rcMonitor.right - info.rcMonitor.left;
|
||||
monitor->resolution_y = info.rcMonitor.bottom - info.rcMonitor.top;
|
||||
|
||||
GetDpiForMonitor(monitor_handle, MDT_EFFECTIVE_DPI, (UINT*)&monitor->dpi, (UINT*)&monitor->dpi_y);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
void win32_query_monitors() {
|
||||
if (os.monitors) growing_array_clear((void**)&os.monitors);
|
||||
else growing_array_init((void**)&os.monitors, sizeof(Os_Monitor), get_heap_allocator());
|
||||
|
||||
EnumDisplayMonitors(0, 0, win32_query_monitors_callback, 0);
|
||||
|
||||
os.number_of_connected_monitors = growing_array_get_valid_count(os.monitors);
|
||||
}
|
||||
|
||||
void s64_to_null_terminated_string_reverse(char str[], int length)
|
||||
|
@ -1043,6 +1101,8 @@ bool os_do_paths_match(string a, string b) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// #Cleanup
|
||||
// These are not os-specific, why are they here?
|
||||
void fprints(File f, string fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
@ -1059,7 +1119,20 @@ void fprintf(File f, const char* fmt, ...) {
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void os_wait_and_read_stdin(string *result, u64 max_count, Allocator allocator) {
|
||||
char *buffer = talloc(max_count);
|
||||
|
||||
DWORD read;
|
||||
BOOL ok = ReadConsole(GetStdHandle(STD_INPUT_HANDLE), buffer, max_count, &read, 0);
|
||||
|
||||
if (!ok) {
|
||||
*result = string_copy(STR("STDIN is not available"), allocator);
|
||||
} else {
|
||||
*result = alloc_string(allocator, read);
|
||||
memcpy(result->data, buffer, read);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -37,17 +37,31 @@
|
|||
|
||||
typedef int (__cdecl *Crt_Vsnprintf_Proc) (char*, size_t, const char*, va_list);
|
||||
|
||||
typedef struct Os_Info {
|
||||
typedef struct Os_Monitor {
|
||||
u64 refresh_rate;
|
||||
u64 resolution_x;
|
||||
u64 resolution_y;
|
||||
u64 dpi;
|
||||
u64 dpi_y;
|
||||
string name;
|
||||
} Os_Monitor;
|
||||
|
||||
typedef struct Os_Context {
|
||||
u64 page_size;
|
||||
u64 granularity;
|
||||
|
||||
Dynamic_Library_Handle crt;
|
||||
|
||||
Crt_Vsnprintf_Proc crt_vsnprintf;
|
||||
|
||||
u64 number_of_connected_monitors;
|
||||
Os_Monitor *monitors;
|
||||
Os_Monitor *primary_monitor;
|
||||
|
||||
// These are not correct, but they probably do include static memory
|
||||
void *static_memory_start, *static_memory_end;
|
||||
|
||||
} Os_Info;
|
||||
} Os_Context;
|
||||
|
||||
typedef struct Os_Window {
|
||||
|
||||
|
@ -72,11 +86,11 @@ typedef struct Os_Window {
|
|||
|
||||
// #Global
|
||||
ogb_instance Os_Window window;
|
||||
ogb_instance Os_Info os;
|
||||
ogb_instance Os_Context os;
|
||||
|
||||
#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE
|
||||
|
||||
Os_Info os;
|
||||
Os_Context os;
|
||||
Os_Window window;
|
||||
|
||||
#endif // NOT OOGABOOGA_LINK_EXTERNAL_INSTANCE
|
||||
|
@ -378,6 +392,7 @@ void fprint_va_list_buffered(File f, const string fmt, va_list args) {
|
|||
}
|
||||
}
|
||||
|
||||
void os_wait_and_read_stdin(string *result, u64 max_count, Allocator allocator);
|
||||
|
||||
///
|
||||
///
|
||||
|
|
|
@ -173,6 +173,10 @@ string_builder_init(String_Builder *b, Allocator allocator) {
|
|||
string_builder_init_reserve(b, 128, allocator);
|
||||
}
|
||||
void
|
||||
string_builder_deinit(String_Builder *b) {
|
||||
dealloc(b->allocator, b->buffer);
|
||||
}
|
||||
void
|
||||
string_builder_append(String_Builder *b, string s) {
|
||||
assert(b->allocator.proc, "String_Builder is missing allocator");
|
||||
string_builder_reserve(b, b->count+s.count);
|
||||
|
|
|
@ -1,4 +1,33 @@
|
|||
|
||||
/*
|
||||
|
||||
Format a string and print to stdout:
|
||||
print(string fmt, ...)
|
||||
|
||||
Allocate a new string and format into it:
|
||||
sprint(Allocator allocator, string fmt, ...)
|
||||
|
||||
Allocate a new string with the temporary allocator and format into it:
|
||||
tprint(string fmt, ...)
|
||||
|
||||
Example:
|
||||
print("Int: %d, Float: %f, String: %s", my_int, my_float, my_string);
|
||||
|
||||
Format specifiers:
|
||||
%d, %i: Any SIGNED integer
|
||||
%u : Any UNSIGNED integer
|
||||
%f : Float32 or float64
|
||||
%s : string
|
||||
%b : bool
|
||||
%c : Character
|
||||
%v2 : Vector2
|
||||
%v3 : Vector3
|
||||
%v4 : Vector4
|
||||
|
||||
Also includes all of the standard C printf-like format specifiers:
|
||||
https://www.geeksforgeeks.org/format-specifiers-in-c/
|
||||
*/
|
||||
|
||||
ogb_instance void os_write_string_to_stdout(string s);
|
||||
inline int crt_sprintf(char *str, const char *format, ...);
|
||||
int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args);
|
||||
|
@ -69,6 +98,18 @@ u64 format_string_to_buffer(char* buffer, u64 count, const char* fmt, va_list ar
|
|||
len += 1;
|
||||
assert(len < (1024ULL*1024ULL*1024ULL*1ULL), "The argument passed to %%cs is either way too big, missing null-termination or simply not a char*.");
|
||||
}
|
||||
} else if (*p == 'b') {
|
||||
p += 1;
|
||||
int data = va_arg(args, int);
|
||||
bool val = !(data == 0);
|
||||
|
||||
char *result = (val ? "true" : "false");
|
||||
|
||||
if (buffer) {
|
||||
memcpy(bufp, result, strlen(result));
|
||||
}
|
||||
bufp += strlen(result);
|
||||
|
||||
} else if (*p == 'v' && *(p+1) == '2') {
|
||||
p += 2;
|
||||
|
||||
|
@ -131,7 +172,7 @@ u64 format_string_to_buffer(char* buffer, u64 count, const char* fmt, va_list ar
|
|||
case 'n': va_arg(args, int*); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
if (temp_len < 0) {
|
||||
return -1; // Error in formatting
|
||||
}
|
||||
|
|
Reference in a new issue