Mouse pointers & text rendering bug
This commit is contained in:
parent
db7159a306
commit
234e3ed440
12 changed files with 329 additions and 45 deletions
15
TODO
15
TODO
|
@ -12,15 +12,13 @@
|
|||
- Optimize
|
||||
- Spam simd
|
||||
- Concurrent jobs for players?
|
||||
- Mega buffer for contiguous intermediate buffers
|
||||
We definitely also want a limit to how much memory we want allocated to intermediate buffers.
|
||||
- Pool of intermediate buffers (2^)
|
||||
- Bugs:
|
||||
- Small fadeout on pause is slightly noisy
|
||||
- Setting time stamp/progression causes noise (need fade transition like on pause/play)
|
||||
- End of clip also causes noise if audio clip does not end smoothly
|
||||
- Setting audio source to a format which differs from audio output format in both channels and bit_width at the same time will produce pure loud noise.
|
||||
- 24-Bit audio conversion doesn't really work
|
||||
- Converting 24-bit audio files doesn't really work
|
||||
|
||||
- General bugs & issues
|
||||
- Release freeze in run_tests
|
||||
|
@ -30,6 +28,10 @@
|
|||
|
||||
- Renderer
|
||||
- API to pass constant values to shader (codegen #define's)
|
||||
- Draw_Frame instances
|
||||
- Or draw to a custom Quad_Buffer, then draw quad buffers ?
|
||||
- draw_deferred ?
|
||||
- Draw_Frame Render_Image
|
||||
|
||||
- Fonts
|
||||
- Atlases are way too big, render atlases with size depending on font_height (say, 128 codepoints per atlas)
|
||||
|
@ -38,9 +40,16 @@
|
|||
- Window::bool is_minimized
|
||||
- don't set window.width & window.height to 0
|
||||
- Sockets recv, send
|
||||
- Mouse pointer
|
||||
- Hide mouse pointer
|
||||
|
||||
|
||||
- Arenas
|
||||
|
||||
- Examples/Guides:
|
||||
- Scaling text for pixel perfect rendering
|
||||
- Z sorting
|
||||
- Scissor boxing
|
||||
|
||||
- Needs testing:
|
||||
- Audio format channel conversions
|
||||
|
|
|
@ -6,6 +6,6 @@ mkdir build
|
|||
|
||||
pushd build
|
||||
|
||||
clang -g -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 -lavrt -lksuser -ldbghelp -femit-all-decls
|
||||
|
||||
popd
|
4
build.c
4
build.c
|
@ -37,11 +37,11 @@ typedef struct Context_Extra {
|
|||
|
||||
// #include "oogabooga/examples/text_rendering.c"
|
||||
// #include "oogabooga/examples/custom_logger.c"
|
||||
// #include "oogabooga/examples/renderer_stress_test.c"
|
||||
#include "oogabooga/examples/renderer_stress_test.c"
|
||||
// #include "oogabooga/examples/tile_game.c"
|
||||
// #include "oogabooga/examples/audio_test.c"
|
||||
// #include "oogabooga/examples/custom_shader.c"
|
||||
#include "oogabooga/examples/growing_array_example.c"
|
||||
// #include "oogabooga/examples/growing_array_example.c"
|
||||
|
||||
// This is where you swap in your own project!
|
||||
// #include "entry_yourepicgamename.c"
|
||||
|
|
|
@ -1,4 +1,18 @@
|
|||
|
||||
## v0.01.003 -
|
||||
- Os layer
|
||||
- Implemented setting of mouse pointers, either to system standard pointers or a custom image
|
||||
- Ignore SETCURSOR events unless window resize
|
||||
- Store SYSTEM_INFO in init
|
||||
- os_get_number_of_logical_processors()
|
||||
|
||||
- Renderer
|
||||
- Fix bad uv sampling bug when uneven window dimensions
|
||||
|
||||
- Misc
|
||||
-
|
||||
|
||||
|
||||
## v0.01.002 - Flexible build options, Hotloading, growing array
|
||||
- Build system
|
||||
- We can now compile with:
|
||||
|
|
|
@ -28,9 +28,10 @@ typedef struct Cpu_Capabilities {
|
|||
#if COMPILER_MVSC
|
||||
#define inline __forceinline
|
||||
#define alignat(x) __declspec(align(x))
|
||||
#define noreturn __declspec(noreturn)
|
||||
#define COMPILER_HAS_MEMCPY_INTRINSICS 1
|
||||
inline void
|
||||
crash() {
|
||||
crash() noreturn {
|
||||
__debugbreak();
|
||||
volatile int *a = 0;
|
||||
*a = 5;
|
||||
|
@ -113,10 +114,11 @@ typedef struct Cpu_Capabilities {
|
|||
|
||||
#elif COMPILER_GCC || COMPILER_CLANG
|
||||
#define inline __attribute__((always_inline)) inline
|
||||
#define alignat(x) __attribute__((aligned(x)))
|
||||
#define alignat(x) __attribute__((aligned(x)))
|
||||
#define noreturn __attribute__((noreturn))
|
||||
#define COMPILER_HAS_MEMCPY_INTRINSICS 1
|
||||
|
||||
inline void __attribute__((noreturn))
|
||||
inline void noreturn
|
||||
crash() {
|
||||
__builtin_trap();
|
||||
volatile int *a = 0;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
Draw_Quad *draw_quad_projected(Draw_Quad quad, Matrix4 world_to_clip);
|
||||
Draw_Quad *draw_quad(Draw_Quad quad);
|
||||
Draw_Quad *draw_quad_xform(Draw_Quad quad, Matrix4 xform);
|
||||
bool draw_text_callback(Gfx_Glyph glyph, Gfx_Font_Atlas *atlas, float glyph_x, float glyph_y, void *ud);
|
||||
void draw_text_xform(Gfx_Font *font, string text, u32 raster_height, Matrix4 xform, Vector2 scale, Vector4 color);
|
||||
void draw_text(Gfx_Font *font, string text, u32 raster_height, Vector2 position, Vector2 scale, Vector4 color);
|
||||
Gfx_Text_Metrics draw_text_and_measure(Gfx_Font *font, string text, u32 raster_height, Vector2 position, Vector2 scale, Vector4 color);
|
||||
|
|
|
@ -15,6 +15,11 @@ int entry(int argc, char **argv) {
|
|||
Gfx_Image *hammer_image = load_image_from_disk(STR("oogabooga/examples/hammer.png"), get_heap_allocator());
|
||||
assert(hammer_image, "Failed loading hammer.png");
|
||||
|
||||
Custom_Mouse_Pointer hammer_pointer
|
||||
= os_make_custom_mouse_pointer_from_file(STR("oogabooga/examples/hammer.png"), 16, 16, get_heap_allocator());
|
||||
assert(hammer_pointer != 0, "Could not load hammer pointer");
|
||||
|
||||
|
||||
void *my_data = alloc(get_heap_allocator(), 32*32*4);
|
||||
memset(my_data, 0xffffffff, 32*32*4);
|
||||
Gfx_Image *my_image = make_image(32, 32, 4, my_data, get_heap_allocator());
|
||||
|
@ -54,7 +59,7 @@ int entry(int argc, char **argv) {
|
|||
if (is_key_just_released(KEY_ESCAPE)) {
|
||||
window.should_close = true;
|
||||
}
|
||||
|
||||
os_set_mouse_pointer_custom(hammer_pointer);
|
||||
if (is_key_just_pressed(KEY_ARROW_LEFT)) {
|
||||
window.x -= 10;
|
||||
}
|
||||
|
|
|
@ -244,8 +244,8 @@ void font_atlas_init(Gfx_Font_Atlas *atlas, Gfx_Font_Variation *variation, u32 f
|
|||
glyph->advance = (float)advance*variation->scale;
|
||||
//glyph->xoffset += (float)left_side_bearing*variation->scale;
|
||||
|
||||
glyph->uv.x1 = (float)cursor_x/(float)FONT_ATLAS_WIDTH;
|
||||
glyph->uv.y1 = (float)cursor_y/(float)FONT_ATLAS_HEIGHT;
|
||||
glyph->uv.x1 = ((float)cursor_x)/(float)FONT_ATLAS_WIDTH;
|
||||
glyph->uv.y1 = ((float)cursor_y)/(float)FONT_ATLAS_HEIGHT;
|
||||
glyph->uv.x2 = ((float)cursor_x+glyph->width)/(float)FONT_ATLAS_WIDTH;
|
||||
glyph->uv.y2 = ((float)cursor_y+glyph->height)/(float)FONT_ATLAS_HEIGHT;
|
||||
|
||||
|
|
|
@ -674,8 +674,21 @@ void d3d11_process_draw_frame() {
|
|||
}
|
||||
|
||||
if (q->type == QUAD_TYPE_TEXT) {
|
||||
|
||||
// This is meant to fix the annoying artifacts that shows up when sampling text from an atlas
|
||||
// presumably for floating point precision issues or something.
|
||||
|
||||
// #Incomplete
|
||||
// If we want to animate text with small movements then it will look wonky.
|
||||
// This should be optional probably.
|
||||
// Also, we might want to do this on non-text if rendering with linear filtering
|
||||
// from a large texture atlas.
|
||||
|
||||
float pixel_width = 2.0/(float)window.width;
|
||||
float pixel_height = 2.0/(float)window.height;
|
||||
|
||||
bool xeven = window.width % 2 == 0;
|
||||
bool yeven = window.height % 2 == 0;
|
||||
|
||||
q->bottom_left.x = round(q->bottom_left.x / pixel_width) * pixel_width;
|
||||
q->bottom_left.y = round(q->bottom_left.y / pixel_height) * pixel_height;
|
||||
|
@ -703,10 +716,50 @@ void d3d11_process_draw_frame() {
|
|||
TR->position = v4(q->top_right.x, q->top_right.y, 0, 1);
|
||||
BR->position = v4(q->bottom_right.x, q->bottom_right.y, 0, 1);
|
||||
|
||||
BL->uv = v2(q->uv.x1, q->uv.y1);
|
||||
TL->uv = v2(q->uv.x1, q->uv.y2);
|
||||
TR->uv = v2(q->uv.x2, q->uv.y2);
|
||||
BR->uv = v2(q->uv.x2, q->uv.y1);
|
||||
|
||||
if (q->image) {
|
||||
|
||||
BL->uv = v2(q->uv.x1, q->uv.y1);
|
||||
TL->uv = v2(q->uv.x1, q->uv.y2);
|
||||
TR->uv = v2(q->uv.x2, q->uv.y2);
|
||||
BR->uv = v2(q->uv.x2, q->uv.y1);
|
||||
// #Hack #Bug #Cleanup
|
||||
// When a window dimension is uneven it slightly under/oversamples on an axis by a
|
||||
// seemingly arbitrary amount. The 0.25 is a magic value I got from trial and error.
|
||||
// (It undersamples by a fourth of the atlas texture?)
|
||||
// Anything > 0.25 < will slightly over/undersample on my machine.
|
||||
// I have no idea about #Portability here.
|
||||
// - Charlie M 26th July 2024
|
||||
if (window.width % 2 != 0) {
|
||||
BL->uv.x += (2.0/(float)q->image->width)*0.25;
|
||||
TL->uv.x += (2.0/(float)q->image->width)*0.25;
|
||||
TR->uv.x += (2.0/(float)q->image->width)*0.25;
|
||||
BR->uv.x += (2.0/(float)q->image->width)*0.25;
|
||||
}
|
||||
if (window.height % 2 != 0) {
|
||||
BL->uv.y -= (2.0/(float)q->image->height)*0.25;
|
||||
TL->uv.y -= (2.0/(float)q->image->height)*0.25;
|
||||
TR->uv.y -= (2.0/(float)q->image->height)*0.25;
|
||||
BR->uv.y -= (2.0/(float)q->image->height)*0.25;
|
||||
}
|
||||
|
||||
u8 sampler = -1;
|
||||
if (q->image_min_filter == GFX_FILTER_MODE_NEAREST
|
||||
&& q->image_mag_filter == GFX_FILTER_MODE_NEAREST)
|
||||
sampler = 0;
|
||||
if (q->image_min_filter == GFX_FILTER_MODE_LINEAR
|
||||
&& q->image_mag_filter == GFX_FILTER_MODE_LINEAR)
|
||||
sampler = 1;
|
||||
if (q->image_min_filter == GFX_FILTER_MODE_LINEAR
|
||||
&& q->image_mag_filter == GFX_FILTER_MODE_NEAREST)
|
||||
sampler = 2;
|
||||
if (q->image_min_filter == GFX_FILTER_MODE_NEAREST
|
||||
&& q->image_mag_filter == GFX_FILTER_MODE_LINEAR)
|
||||
sampler = 3;
|
||||
BL->sampler=TL->sampler=TR->sampler=BR->sampler = (u8)sampler;
|
||||
|
||||
}
|
||||
BL->texture_index=TL->texture_index=TR->texture_index=BR->texture_index = texture_index;
|
||||
|
||||
BL->self_uv = v2(0, 0);
|
||||
TL->self_uv = v2(0, 1);
|
||||
|
@ -721,7 +774,6 @@ void d3d11_process_draw_frame() {
|
|||
|
||||
BL->color = TL->color = TR->color = BR->color = q->color;
|
||||
|
||||
BL->texture_index=TL->texture_index=TR->texture_index=BR->texture_index = texture_index;
|
||||
BL->type=TL->type=TR->type=BR->type = (u8)q->type;
|
||||
|
||||
float t = q->scissor.y1;
|
||||
|
@ -734,23 +786,6 @@ void d3d11_process_draw_frame() {
|
|||
BL->has_scissor=TL->has_scissor=TR->has_scissor=BR->has_scissor = q->has_scissor;
|
||||
BL->scissor=TL->scissor=TR->scissor=BR->scissor = q->scissor;
|
||||
|
||||
u8 sampler = -1;
|
||||
if (q->image_min_filter == GFX_FILTER_MODE_NEAREST
|
||||
&& q->image_mag_filter == GFX_FILTER_MODE_NEAREST)
|
||||
sampler = 0;
|
||||
if (q->image_min_filter == GFX_FILTER_MODE_LINEAR
|
||||
&& q->image_mag_filter == GFX_FILTER_MODE_LINEAR)
|
||||
sampler = 1;
|
||||
if (q->image_min_filter == GFX_FILTER_MODE_LINEAR
|
||||
&& q->image_mag_filter == GFX_FILTER_MODE_NEAREST)
|
||||
sampler = 2;
|
||||
if (q->image_min_filter == GFX_FILTER_MODE_NEAREST
|
||||
&& q->image_mag_filter == GFX_FILTER_MODE_LINEAR)
|
||||
sampler = 3;
|
||||
|
||||
BL->type=TL->type=TR->type=BR->type = (u8)q->type;
|
||||
BL->sampler=TL->sampler=TR->sampler=BR->sampler = (u8)sampler;
|
||||
|
||||
*BL2 = *BL;
|
||||
*TR2 = *TR;
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
|
||||
#define OGB_VERSION_MAJOR 0
|
||||
#define OGB_VERSION_MINOR 1
|
||||
#define OGB_VERSION_PATCH 2
|
||||
#define OGB_VERSION_PATCH 3
|
||||
|
||||
#define OGB_VERSION (OGB_VERSION_MAJOR*1000000+OGB_VERSION_MINOR*1000+OGB_VERSION_PATCH)
|
||||
|
||||
|
@ -228,6 +228,7 @@ typedef u8 bool;
|
|||
|
||||
#ifdef _WIN32
|
||||
#define COBJMACROS
|
||||
#undef noreturn
|
||||
#include <Windows.h>
|
||||
#if CONFIGURATION == DEBUG
|
||||
#include <dbghelp.h>
|
||||
|
|
|
@ -41,6 +41,12 @@ void win32_check_hr_impl(HRESULT hr, u32 line, const char* file_name) {
|
|||
}
|
||||
}
|
||||
|
||||
// #Global
|
||||
bool win32_want_override_mouse_pointer = false;
|
||||
HCURSOR win32_shadowed_mouse_pointer = 0;
|
||||
bool win32_did_override_user_mouse_pointer = false;
|
||||
SYSTEM_INFO win32_system_info;
|
||||
|
||||
#ifndef OOGABOOGA_HEADLESS
|
||||
|
||||
// Persistent
|
||||
|
@ -86,6 +92,8 @@ void win32_handle_key_repeat(Input_Key_Code code) {
|
|||
|
||||
win32_send_key_event(code, win32_key_states[code]);
|
||||
}
|
||||
|
||||
|
||||
LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wparam, LPARAM lparam) {
|
||||
|
||||
if (window._initialized) {
|
||||
|
@ -161,6 +169,32 @@ LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wpar
|
|||
|
||||
goto DEFAULT_HANDLE;
|
||||
}
|
||||
case WM_SETCURSOR: {
|
||||
|
||||
WORD hit_test = LOWORD(lparam);
|
||||
WORD mouse_message = HIWORD(lparam);
|
||||
|
||||
if (hit_test == HTLEFT || hit_test == HTRIGHT || hit_test == HTTOP ||
|
||||
hit_test == HTBOTTOM || hit_test == HTTOPLEFT || hit_test == HTTOPRIGHT ||
|
||||
hit_test == HTBOTTOMLEFT || hit_test == HTBOTTOMRIGHT) {
|
||||
|
||||
// We are hovering the borders, let windows decide the pointer
|
||||
win32_want_override_mouse_pointer = true;
|
||||
|
||||
goto DEFAULT_HANDLE;
|
||||
} else {
|
||||
if (win32_want_override_mouse_pointer) {
|
||||
win32_want_override_mouse_pointer = false;
|
||||
if (win32_did_override_user_mouse_pointer) {
|
||||
win32_did_override_user_mouse_pointer = false;
|
||||
SetCursor(win32_shadowed_mouse_pointer);
|
||||
} else {
|
||||
goto DEFAULT_HANDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
DEFAULT_HANDLE:
|
||||
|
@ -255,10 +289,11 @@ void os_init(u64 program_memory_size) {
|
|||
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
os.granularity = cast(u64)si.dwAllocationGranularity;
|
||||
os.page_size = cast(u64)si.dwPageSize;
|
||||
os_set_mouse_pointer_standard(MOUSE_POINTER_DEFAULT);
|
||||
|
||||
GetSystemInfo(&win32_system_info);
|
||||
os.granularity = cast(u64)win32_system_info.dwAllocationGranularity;
|
||||
os.page_size = cast(u64)win32_system_info.dwPageSize;
|
||||
|
||||
os.static_memory_start = 0;
|
||||
os.static_memory_end = 0;
|
||||
|
@ -1031,18 +1066,25 @@ void fprintf(File f, const char* fmt, ...) {
|
|||
|
||||
///
|
||||
///
|
||||
// Memory
|
||||
// Queries
|
||||
///
|
||||
|
||||
void* os_get_stack_base() {
|
||||
void*
|
||||
os_get_stack_base() {
|
||||
NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
|
||||
return tib->StackBase;
|
||||
}
|
||||
void* os_get_stack_limit() {
|
||||
void*
|
||||
os_get_stack_limit() {
|
||||
NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
|
||||
return tib->StackLimit;
|
||||
}
|
||||
|
||||
u64
|
||||
os_get_number_of_logical_processors() {
|
||||
return (u64)win32_system_info.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
// Debug
|
||||
|
@ -1144,8 +1186,140 @@ os_get_stack_trace(u64 *trace_count, Allocator allocator) {
|
|||
#endif // NOT DEBUG
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
// Mouse pointer
|
||||
|
||||
#ifndef OOGABOOGA_HEADLESS
|
||||
LPCSTR
|
||||
win32_mouse_pointer_kind_to_win32(Mouse_Pointer_Kind k) {
|
||||
switch (k) {
|
||||
case MOUSE_POINTER_DEFAULT: return IDC_ARROW;
|
||||
case MOUSE_POINTER_TEXT_SELECT: return IDC_IBEAM;
|
||||
case MOUSE_POINTER_BUSY: return IDC_WAIT;
|
||||
case MOUSE_POINTER_BUSY_BACKGROUND: return IDC_APPSTARTING;
|
||||
case MOUSE_POINTER_CROSS: return IDC_CROSS;
|
||||
case MOUSE_POINTER_ARROW_N: return IDC_UPARROW;
|
||||
case MOUSE_POINTER_ARROWS_NW_SE: return IDC_SIZENWSE;
|
||||
case MOUSE_POINTER_ARROWS_NE_SW: return IDC_SIZENESW;
|
||||
case MOUSE_POINTER_ARROWS_HORIZONTAL: return IDC_SIZEWE;
|
||||
case MOUSE_POINTER_ARROWS_VERTICAL: return IDC_SIZENS;
|
||||
case MOUSE_POINTER_ARROWS_ALL: return IDC_SIZEALL;
|
||||
case MOUSE_POINTER_NO: return IDC_NO;
|
||||
case MOUSE_POINTER_POINT: return IDC_HAND;
|
||||
default: break;
|
||||
}
|
||||
panic("Unhandled Mouse_Pointer_Kind");
|
||||
}
|
||||
|
||||
void ogb_instance
|
||||
os_set_mouse_pointer_standard(Mouse_Pointer_Kind kind) {
|
||||
thread_local local_persist HCURSOR loaded_pointers[MOUSE_POINTER_MAX] = {0};
|
||||
|
||||
if (loaded_pointers[kind] == 0) {
|
||||
loaded_pointers[kind] = LoadCursor(0, win32_mouse_pointer_kind_to_win32(kind));
|
||||
}
|
||||
|
||||
if (win32_want_override_mouse_pointer) {
|
||||
win32_shadowed_mouse_pointer = loaded_pointers[kind];
|
||||
win32_did_override_user_mouse_pointer = true;
|
||||
} else {
|
||||
SetCursor(loaded_pointers[kind]);
|
||||
}
|
||||
}
|
||||
void ogb_instance
|
||||
os_set_mouse_pointer_custom(Custom_Mouse_Pointer p) {
|
||||
if (win32_want_override_mouse_pointer) {
|
||||
win32_shadowed_mouse_pointer = (HCURSOR)p;
|
||||
win32_did_override_user_mouse_pointer = true;
|
||||
} else {
|
||||
SetCursor((HCURSOR)p);
|
||||
}
|
||||
}
|
||||
|
||||
// Expects 32-bit rgba
|
||||
Custom_Mouse_Pointer ogb_instance
|
||||
os_make_custom_mouse_pointer(void *image, int width, int height, int hotspot_x, int hotspot_y) {
|
||||
HICON icon = NULL;
|
||||
HBITMAP bitmap = NULL;
|
||||
ICONINFO icon_info = { 0 };
|
||||
|
||||
BITMAPINFO bmi = { 0 };
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = width;
|
||||
bmi.bmiHeader.biHeight = height;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
BYTE* bits = NULL;
|
||||
HDC hdc = GetDC(NULL);
|
||||
bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
|
||||
ReleaseDC(NULL, hdc);
|
||||
if (!bitmap) {
|
||||
assert(false, "Failed to create DIB section");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(bits, image, width * height * 4);
|
||||
|
||||
icon_info.fIcon = FALSE; // Cursor, not icon
|
||||
icon_info.xHotspot = hotspot_x;
|
||||
icon_info.yHotspot = height-hotspot_y;
|
||||
icon_info.hbmMask = bitmap;
|
||||
icon_info.hbmColor = bitmap;
|
||||
|
||||
icon = CreateIconIndirect(&icon_info);
|
||||
if (!icon) {
|
||||
assert(false, "Failed to create icon from bitmap");
|
||||
DeleteObject(bitmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DeleteObject(bitmap);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
Custom_Mouse_Pointer ogb_instance
|
||||
os_make_custom_mouse_pointer_from_file(string path, int hotspot_x, int hotspot_y, Allocator allocator) {
|
||||
int width, height, channels;
|
||||
stbi_set_flip_vertically_on_load(1);
|
||||
third_party_allocator = allocator;
|
||||
|
||||
string png;
|
||||
bool ok = os_read_entire_file(path, &png, allocator);
|
||||
|
||||
if (!ok) return 0;
|
||||
|
||||
unsigned char* stb_data = stbi_load_from_memory(
|
||||
png.data,
|
||||
png.count,
|
||||
&width,
|
||||
&height,
|
||||
&channels,
|
||||
STBI_rgb_alpha
|
||||
);
|
||||
|
||||
if (!stb_data) {
|
||||
dealloc_string(allocator, png);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Custom_Mouse_Pointer p = os_make_custom_mouse_pointer(stb_data, width, height, hotspot_x, hotspot_y);
|
||||
|
||||
dealloc_string(allocator, png);
|
||||
stbi_image_free(stb_data);
|
||||
third_party_allocator = ZERO(Allocator);
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef OOGABOOGA_HEADLESS // No audio in headless
|
||||
|
||||
// Actually fuck you bill gates
|
||||
const GUID CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e}};
|
||||
|
|
|
@ -200,6 +200,7 @@ typedef enum Os_Io_Open_Flags {
|
|||
// To append, pass WRITE flag without CREATE flag
|
||||
} Os_Io_Open_Flags;
|
||||
|
||||
// Returns OS_INVALID_FILE on fail
|
||||
File ogb_instance
|
||||
os_file_open_s(string path, Os_Io_Open_Flags flags);
|
||||
|
||||
|
@ -376,13 +377,16 @@ void fprint_va_list_buffered(File f, const string fmt, va_list args) {
|
|||
|
||||
///
|
||||
///
|
||||
// Memory
|
||||
// Queries
|
||||
///
|
||||
ogb_instance void*
|
||||
os_get_stack_base();
|
||||
ogb_instance void*
|
||||
os_get_stack_limit();
|
||||
|
||||
ogb_instance u64
|
||||
os_get_number_of_logical_processors();
|
||||
|
||||
|
||||
///
|
||||
///
|
||||
|
@ -401,6 +405,47 @@ void dump_stack_trace() {
|
|||
}
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
// Mouse pointer
|
||||
|
||||
typedef enum Mouse_Pointer_Kind {
|
||||
MOUSE_POINTER_DEFAULT = 0, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_arrow.png
|
||||
MOUSE_POINTER_TEXT_SELECT = 10, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_ibeam.png
|
||||
MOUSE_POINTER_BUSY = 20, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_wait.png
|
||||
MOUSE_POINTER_BUSY_BACKGROUND = 30, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_appstarting.png
|
||||
MOUSE_POINTER_CROSS = 40, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_cross.png
|
||||
MOUSE_POINTER_ARROW_N = 50, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_uparrow.png
|
||||
MOUSE_POINTER_ARROWS_NW_SE = 60, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizenwse.png
|
||||
MOUSE_POINTER_ARROWS_NE_SW = 70, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizenesw.png
|
||||
MOUSE_POINTER_ARROWS_HORIZONTAL = 80, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizewe.png
|
||||
MOUSE_POINTER_ARROWS_VERTICAL = 90, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizens.png
|
||||
MOUSE_POINTER_ARROWS_ALL = 100, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizeall.png
|
||||
MOUSE_POINTER_NO = 110, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_no.png
|
||||
MOUSE_POINTER_POINT = 120, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_hand.png
|
||||
|
||||
MOUSE_POINTER_MAX,
|
||||
} Mouse_Pointer_Kind;
|
||||
|
||||
typedef void* Custom_Mouse_Pointer;
|
||||
|
||||
void ogb_instance
|
||||
os_set_mouse_pointer_standard(Mouse_Pointer_Kind kind);
|
||||
void ogb_instance
|
||||
os_set_mouse_pointer_custom(Custom_Mouse_Pointer p);
|
||||
|
||||
// Expects 32-bit rgba
|
||||
// Returns 0 on fail
|
||||
Custom_Mouse_Pointer ogb_instance
|
||||
os_make_custom_mouse_pointer(void *image, int width, int height, int hotspot_x, int hotspot_y);
|
||||
|
||||
// Returns 0 on fail
|
||||
// Will free everything that's allocated, passing temp allocator should be fine as long as the image is small
|
||||
Custom_Mouse_Pointer ogb_instance
|
||||
os_make_custom_mouse_pointer_from_file(string path, int hotspot_x, int hotspot_y, Allocator allocator);
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
void ogb_instance
|
||||
os_init(u64 program_memory_size);
|
||||
|
||||
|
|
Reference in a new issue