#import "KERNEL32.core" #import "GDI32.core" #import "USER32.core" #import "WINMM.core" #import "Windows.core" Platform :: struct bitmap: Bitmap window_dc: HDC window: HWND good_scheduling: Bool Bitmap :: struct size: Vec2I data: *U32 hdc: HDC dib: HBITMAP compatible_dc: HDC IsValidBitmap :: (b: *Bitmap): Bool result := b.data != 0 return result CreateBitmap :: (for_dc: HDC, size: Vec2I, bottom_up: Bool = true): Bitmap result: Bitmap = {size = size} if bottom_up == false result.size.y = -result.size.y header_size: U32 = SizeOf(BITMAPINFOHEADER) Assert(header_size == 40) bminfo := BITMAPINFO{ BITMAPINFOHEADER{ biSize = header_size, biWidth = size.x->LONG, biHeight = size.y->LONG, biPlanes = 1, biBitCount = 32, biCompression = BI_RGB, biXPelsPerMeter = 1, biYPelsPerMeter = 1, } } result.dib = CreateDIBSection(for_dc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0) result.hdc = CreateCompatibleDC(for_dc) result.compatible_dc = for_dc return result DestroyBitmap :: (b: *Bitmap) if IsValidBitmap(b) DeleteDC(b.hdc) DeleteObject(b.dib) ZeroMemory(b, SizeOf(Bitmap)) DrawBitmapInCompatibleDC :: (b: *Bitmap) if(IsValidBitmap(b)) SelectObject(b.hdc, b.dib) BitBlt(b.compatible_dc, 0, 0, b.size.x->int, b.size.y->int, b.hdc, 0, 0, SRCCOPY) GetWindowStyle :: (resizable: Bool): DWORD style: DWORD = WS_SYSMENU | WS_OVERLAPPED | WS_CAPTION if resizable ;; style |= WS_MAXIMIZEBOX | WS_THICKFRAME | WS_MINIMIZEBOX return style GetWindowSize :: (window: HWND): Vec2I result: Vec2I window_rect: RECT GetClientRect(window, &window_rect) result.x = (window_rect.right - window_rect.left)->S64 result.y = (window_rect.bottom - window_rect.top)->S64 return result GetWindowPos :: (window: HWND): Vec2I pos: Point ClientToScreen(window, &pos) return {pos.x, pos.y} AdjustWindowRect :: (window: HWND, style: DWORD, rect: *RECT): void FALSE :: 0 if window == 0 dpi := GetDpiForWindow(window) AdjustWindowRectExForDpi(rect, style, FALSE, 0, dpi) else AdjustWindowRectEx(rect, style, FALSE, 0) SetWindowSize :: (window: HWND, style: DWORD, size: Vec2I): void rect := RECT{ 0, 0, size.x->LONG, size.y->LONG } AdjustWindowRect(window, style, &rect) SetWindowPos(window, HWND_TOP, 0, 0, (rect.right - rect.left)->int, (rect.bottom - rect.top)->int, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER) SetWindowPosition :: (window: HWND, style: DWORD, pos: Vec2I): void rect := RECT{ pos.x->LONG, pos.y->LONG, pos.x->LONG, pos.y->LONG } AdjustWindowRect(window, style, &rect) SetWindowPos(window, 0, rect.left, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE) StartMultimedia :: ( x: S64 = 1280, y: S64 = 720, title: String = "Hello people!", window_resizable: Bool = false, target_ms: F64 = 0.0166666 ) Mu.time.delta = target_ms if timeBeginPeriod(1) == TIMERR_NOERROR Mu.os.good_scheduling = true dpi_aware := SetProcessDPIAware() Assert(dpi_aware != 0) Mu.time.start = Time() hInstance := GetModuleHandleA(0) window_name := StringToString16(&Mu.frame_arena, title) w := WNDCLASSW{ lpfnWndProc = WindowProc, hInstance = hInstance, lpszClassName = window_name.str, // style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW, } Assert(RegisterClassW(&w) != 0) style: DWORD = GetWindowStyle(window_resizable) Mu.os.window = CreateWindowExW( dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0, X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = x->int, nHeight = y->int, lpClassName = window_name.str, lpWindowName = window_name.str, dwStyle = style, hInstance = hInstance ) Assert(Mu.os.window != 0) SetWindowSize(Mu.os.window, style, {x,y}) ShowWindow(Mu.os.window, SW_SHOW) size := GetWindowSize(Mu.os.window) Assert(size.x == x && size.y == y) Mu.os.window_dc = GetDC(Mu.os.window) Mu.os.bitmap = CreateBitmap(Mu.os.window_dc, size) Mu.window.resizable = window_resizable Mu.screen = Mu.os.bitmap.data Mu.window.x = size.x Mu.window.y = size.y Mu.window.size = size Mu.window.sizef.x = Mu.window.x->F32 Mu.window.sizef.y = Mu.window.y->F32 UpdateMultimedia :: (): Bool DrawBitmapInCompatibleDC(&Mu.os.bitmap) msg: MSG for PeekMessageW(&msg, Mu.os.window, 0, 0, PM_REMOVE) == 1 TranslateMessage(&msg) DispatchMessageW(&msg) size := GetWindowSize(Mu.os.window) if size.x != Mu.window.x || size.y != Mu.window.y DestroyBitmap(&Mu.os.bitmap) Mu.os.bitmap = CreateBitmap(Mu.os.window_dc, size) Mu.screen = Mu.os.bitmap.data Mu.window.x = size.x Mu.window.y = size.y Mu.window.sizef.x = Mu.window.x->F32 Mu.window.sizef.y = Mu.window.y->F32 Mu.window.size = size Mu.frame_count += 1 frame_time := Time() - Mu.time.frame_start Mu.time.total += frame_time if frame_time < Mu.time.delta if Mu.os.good_scheduling time_to_sleep := (Mu.time.delta - frame_time) * 1000 if time_to_sleep > 0 time_to_sleep_dword := time_to_sleep->DWORD // @check if time_to_sleep_dword truncates down Sleep(time_to_sleep_dword) new_frame_time := Time() for new_frame_time < Mu.time.delta new_frame_time = Time() - Mu.time.frame_start Mu.time.frame_start = Time() return !Mu.quit WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT result: LRESULT if msg == WM_DESTROY // @todo: Add destroy window PostQuitMessage(0) return 0 elif msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN key := MapVKToKey(wparam) Mu.key[key].down = true elif msg == WM_KEYUP || msg == WM_SYSKEYUP key := MapVKToKey(wparam) Mu.key[key].down = false elif msg == WM_LBUTTONDOWN ;; Mu.mouse.left.down = true elif msg == WM_LBUTTONUP ;; Mu.mouse.left.down = false elif msg == WM_RBUTTONDOWN ;; Mu.mouse.right.down = true elif msg == WM_RBUTTONUP ;; Mu.mouse.right.down = false elif msg == WM_MBUTTONDOWN ;; Mu.mouse.middle.down = true elif msg == WM_MBUTTONUP ;; Mu.mouse.middle.down = false elif msg == WM_MOUSEWHEEL if wparam->int > 0 Mu.mouse.wheel = 1 else Mu.mouse.wheel = -1 // Case(WM_CHAR){ // Utf32Result utf32 = Utf16ToUtf32((u16 *)&wparam, 1); // if(!utf32.error){ // int index = OS->input_count; // OS->input_count = ClampTop(OS->input_count + 1, (int)(ArrayCount(OS->input) - 1)); // OS->input[index] = utf32.out_str; // } // }Break; else;; result = DefWindowProcW(hwnd, msg, wparam, lparam) return result /*# mapping = [ ["Up", "VK_UP"], ["Down", "VK_DOWN"], ["Left", "VK_LEFT"], ["Right", "VK_RIGHT"], ["Escape", "VK_ESCAPE"], ["Control", "VK_CONTROL"], ["Backspace", "VK_BACK"], ["Alt", "VK_MENU"], ["Shift", "VK_SHIFT"], ["Tab", "VK_TAB"], ["F1", "VK_F1"], ["F2", "VK_F2"], ["F3", "VK_F3"], ["F4", "VK_F4"], ["F5", "VK_F5"], ["F6", "VK_F6"], ["F7", "VK_F7"], ["F8", "VK_F8"], ["F9", "VK_F9"], ["F10", "VK_F10"], ["F11", "VK_F11"], ["F12", "VK_F12"], ["A", "'A'"], ["B", "'B'"], ["C", "'C'"], ["D", "'D'"], ["E", "'E'"], ["F", "'F'"], ["G", "'G'"], ["H", "'H'"], ["I", "'I'"], ["J", "'J'"], ["K", "'K'"], ["L", "'L'"], ["M", "'M'"], ["N", "'N'"], ["O", "'O'"], ["P", "'P'"], ["Q", "'Q'"], ["R", "'R'"], ["S", "'S'"], ["T", "'T'"], ["U", "'U'"], ["V", "'V'"], ["W", "'W'"], ["X", "'X'"], ["Y", "'Y'"], ["Z", "'Z'"], ["K0", "'0'"], ["K1", "'1'"], ["K2", "'2'"], ["K3", "'3'"], ["K4", "'4'"], ["K5", "'5'"], ["K6", "'6'"], ["K7", "'7'"], ["K8", "'8'"], ["K9", "'9'"], ] print("MapVKToKey :: (vk: WPARAM): Key") el = "" for val,map in mapping: print(f" {el}if vk == {map} ;; return Key.{val}") el = "el" print(" return Key.None") */ MapVKToKey :: (vk: WPARAM): Key if vk == VK_UP ;; return Key.Up elif vk == VK_DOWN ;; return Key.Down elif vk == VK_LEFT ;; return Key.Left elif vk == VK_RIGHT ;; return Key.Right elif vk == VK_ESCAPE ;; return Key.Escape elif vk == VK_CONTROL ;; return Key.Control elif vk == VK_BACK ;; return Key.Backspace elif vk == VK_MENU ;; return Key.Alt elif vk == VK_SHIFT ;; return Key.Shift elif vk == VK_TAB ;; return Key.Tab elif vk == VK_F1 ;; return Key.F1 elif vk == VK_F2 ;; return Key.F2 elif vk == VK_F3 ;; return Key.F3 elif vk == VK_F4 ;; return Key.F4 elif vk == VK_F5 ;; return Key.F5 elif vk == VK_F6 ;; return Key.F6 elif vk == VK_F7 ;; return Key.F7 elif vk == VK_F8 ;; return Key.F8 elif vk == VK_F9 ;; return Key.F9 elif vk == VK_F10 ;; return Key.F10 elif vk == VK_F11 ;; return Key.F11 elif vk == VK_F12 ;; return Key.F12 elif vk == 'A' ;; return Key.A elif vk == 'B' ;; return Key.B elif vk == 'C' ;; return Key.C elif vk == 'D' ;; return Key.D elif vk == 'E' ;; return Key.E elif vk == 'F' ;; return Key.F elif vk == 'G' ;; return Key.G elif vk == 'H' ;; return Key.H elif vk == 'I' ;; return Key.I elif vk == 'J' ;; return Key.J elif vk == 'K' ;; return Key.K elif vk == 'L' ;; return Key.L elif vk == 'M' ;; return Key.M elif vk == 'N' ;; return Key.N elif vk == 'O' ;; return Key.O elif vk == 'P' ;; return Key.P elif vk == 'Q' ;; return Key.Q elif vk == 'R' ;; return Key.R elif vk == 'S' ;; return Key.S elif vk == 'T' ;; return Key.T elif vk == 'U' ;; return Key.U elif vk == 'V' ;; return Key.V elif vk == 'W' ;; return Key.W elif vk == 'X' ;; return Key.X elif vk == 'Y' ;; return Key.Y elif vk == 'Z' ;; return Key.Z elif vk == '0' ;; return Key.K0 elif vk == '1' ;; return Key.K1 elif vk == '2' ;; return Key.K2 elif vk == '3' ;; return Key.K3 elif vk == '4' ;; return Key.K4 elif vk == '5' ;; return Key.K5 elif vk == '6' ;; return Key.K6 elif vk == '7' ;; return Key.K7 elif vk == '8' ;; return Key.K8 elif vk == '9' ;; return Key.K9 return Key.None /*END*/