Os monitors query

This commit is contained in:
Charlie Malmqvist 2024-08-21 20:17:05 +02:00
parent f2b81a0621
commit b7921693c4
13 changed files with 241 additions and 24 deletions

View file

@ -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

View file

@ -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"

View file

@ -1,3 +1,6 @@
## v0.01.005
## v0.01.004 - Gamepad input, text wrapping, bug fixes
- Input
- Added Gamepad support

View file

@ -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))

View file

@ -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));

View file

@ -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();

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);
///
///

View file

@ -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);

View file

@ -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
}