Created
July 27, 2024 02:25
-
-
Save RomanADavis/e6b4c5d2f1d15ffa4249537fc380ab82 to your computer and use it in GitHub Desktop.
Problem getting StretchDIBits to work
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "windows_definitions.h" | |
| #define false (BOOL)0 | |
| #define true (BOOL)1 | |
| #define persist static | |
| #define global static | |
| #define private static | |
| #define not ! | |
| #define and && | |
| #define is == | |
| #define or || | |
| #define unless(statement) if(not(statement)) | |
| #define until(statement) while(not(statement)) | |
| #define LOGFAIL(format, ...) printf(format, ##__VA_ARGS__); exit(EXIT_FAILURE) | |
| #define LOGPASS(format, ...) printf(format, ##__VA_ARGS__) | |
| global BOOL running = true; | |
| global BitmapInfo bitmapInfo; | |
| global void *bitmapMemory; | |
| BitmapInfo BitmapInfo_new(WindowHandler windowHandler){ | |
| RECT clientRect; | |
| GetClientRect(windowHandler, &clientRect); | |
| LONG width = clientRect.right - clientRect.left; | |
| LONG height = clientRect.bottom - clientRect.top; | |
| BitmapInfo bitmapInfo = {0}; | |
| bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo.bmiHeader); | |
| bitmapInfo.bmiHeader.biWidth = width; | |
| bitmapInfo.bmiHeader.biHeight = height; | |
| bitmapInfo.bmiHeader.biPlanes = 1; // can only be 0 or 1; Meaningless? | |
| bitmapInfo.bmiHeader.biBitCount = 32; // 32-bit color | |
| bitmapInfo.bmiHeader.biCompression = BI_RGB; // No compression for more speed | |
| bitmapInfo.bmiHeader.biSize = 0; // For compression: unused here. | |
| bitmapInfo.bmiHeader.biSizeImage = width * height * 4; | |
| bitmapInfo.bmiHeader.biXPelsPerMeter = 0; // For printing: unused here | |
| bitmapInfo.bmiHeader.biYPelsPerMeter = 0; // For printing: unused here | |
| bitmapInfo.bmiHeader.biClrUsed = 0; // For color tables: unused here | |
| bitmapInfo.bmiHeader.biClrImportant = 0; // For index pallets: unused here | |
| return bitmapInfo; | |
| } | |
| void Bitmap_resize(WindowHandler windowHandler){ | |
| RECT clientRect; | |
| GetClientRect(windowHandler, &clientRect); | |
| LONG width = clientRect.right - clientRect.left; | |
| LONG height = clientRect.bottom - clientRect.top; | |
| bitmapInfo = BitmapInfo_new(windowHandler); | |
| HANDLE sectionHandle = NULL; | |
| DWORD offset = 0; | |
| if(bitmapMemory){ | |
| BOOL success = VirtualFree(bitmapMemory, RELEASE_ALL, MEM_RELEASE); | |
| unless(success){ | |
| LOGFAIL("VirtualFree failed in Bitmap_resize with error code %d\n", success); | |
| } | |
| } | |
| int bytesPerPixel = 4; | |
| int bitmapMemorySize = bytesPerPixel * (width * height); | |
| bitmapMemory = VirtualAlloc(ANY_VIRTUAL_MEMORY_LOCATION, bitmapMemorySize, | |
| MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | |
| unless(bitmapMemory){ | |
| LOGFAIL("Virtual Alloc failed in Bitmap_resize with error code %lu\n", GetLastError()); | |
| } | |
| } | |
| void Window_paint(WindowHandler *windowHandler){ | |
| PAINTSTRUCT paint; | |
| DeviceContextHandler deviceContext = BeginPaint(*windowHandler, &paint); | |
| int x = paint.rcPaint.left; | |
| int width = paint.rcPaint.right - x; | |
| int y = paint.rcPaint.top; | |
| int height = paint.rcPaint.bottom - y; | |
| int copied = StretchDIBits(deviceContext, | |
| 0, 0, width, height, | |
| 0, 0, width, height, | |
| bitmapMemory, | |
| &bitmapInfo, | |
| DIB_RGB_COLORS, SRCCOPY); | |
| unless(copied){ | |
| LOGFAIL("StretchDIBits failed in Window_paint with error code %lu, width: %d height: %d, biSize %d", | |
| GetLastError(), width, height, bitmapInfo.bmiHeader.biSizeImage); | |
| } | |
| EndPaint(*windowHandler, &paint); | |
| } | |
| LRESULT CALLBACK Window_callback(WindowHandler windowHandler, unsigned int message, | |
| WideParameter wideParameter, LongPointerParameter longPointerParameter){ | |
| LRESULT result = 0; | |
| switch(message){ | |
| case WM_SIZE:{ | |
| RECT clientRect; | |
| GetClientRect(windowHandler, &clientRect); | |
| LONG clientRectWidth = clientRect.right - clientRect.left; | |
| LONG clientRectHeight = clientRect.bottom - clientRect.top; | |
| printf("Size message sent. Width: %ld Height: %ld \n", | |
| clientRectWidth, clientRectHeight); | |
| Bitmap_resize(windowHandler); | |
| }break; | |
| case WM_DESTROY:{ | |
| printf("Quit message sent.\n"); | |
| running = false; | |
| }break; | |
| case WM_CLOSE:{ | |
| printf("Close message sent.\n"); | |
| running = false; | |
| }break; | |
| case WM_ACTIVATEAPP:{ | |
| printf("Activate app message sent.\n"); | |
| }break; | |
| case WM_PAINT: { | |
| printf("Paint message sent.\n"); | |
| Window_paint(&windowHandler); | |
| }break; | |
| default:{ | |
| result = DefaultWindowProcedure(windowHandler, message, wideParameter, longPointerParameter); | |
| }break; | |
| } | |
| // This is supposed to return a pointer, but at a different level than NULL; I don't really get it. | |
| return result; | |
| } | |
| WindowClass WindowClass_new(InstanceHandler *instance, | |
| WindowProcedure windowProcedure, | |
| LongPointerConstString className){ | |
| WindowClass windowClass = {0}; | |
| // CS_OWNDC: Has it's own device context; CS_HREDRAW and CS_VREDRAW just redraw | |
| // the window on resize Vertically and Horizontally | |
| windowClass.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW ; | |
| windowClass.lpfnWndProc = windowProcedure; // WindowProc: pointer function for the window | |
| // windowClass.cbClsExtra = 0; | |
| // windowClass.cbWndExtra = 0; | |
| windowClass.hInstance = *instance; | |
| // HICON hIcon; | |
| // HCURSOR hCursor; | |
| // HBRUSH hbrBackground; | |
| // LPCSTR lpszMenuName; | |
| windowClass.lpszClassName = className; | |
| unless(RegisterClass(&windowClass)){ | |
| LOGFAIL("Failed to register Window Class with style: %d, class name: %s\n", | |
| windowClass.style, windowClass.lpszClassName); | |
| } | |
| LOGPASS("Successfully registered WindowClass with style: %d, class name: %s\n", | |
| windowClass.style, windowClass.lpszClassName); | |
| return windowClass; | |
| } | |
| WindowHandler WindowHandler_new(WindowClass *windowClass, LongPointerConstString windowName){ | |
| DWORD extendedWindowSyle = 0; | |
| DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE; | |
| int windowCoordinateX = CW_USEDEFAULT; | |
| int windowCoordinateY = CW_USEDEFAULT; | |
| int windowWidth = CW_USEDEFAULT; | |
| int windowHeight = CW_USEDEFAULT; | |
| WindowHandler parentWindow = NULL; | |
| MenuHandler menuHandler = NULL; | |
| LongPointerParameter *windowCreateCallback = NULL; | |
| WindowHandler windowHandler = CreateWindowEx( extendedWindowSyle, | |
| windowClass->lpszClassName, | |
| windowName, | |
| windowStyle, | |
| windowCoordinateX, | |
| windowCoordinateY, | |
| windowWidth, | |
| windowHeight, | |
| parentWindow, | |
| menuHandler, | |
| windowClass->hInstance, | |
| windowCreateCallback); | |
| unless(windowHandler){ LOGFAIL("Failed to create windowHandler.\n");} | |
| LOGPASS("Successfully created windowHandler.\n"); | |
| return windowHandler; | |
| } | |
| int CALLBACK WinMain(InstanceHandler instance, InstanceHandler previous, | |
| LongStringPointer arguments, int windowDisplayMode){ | |
| printf("Successfully started WinMain.\n"); | |
| WindowClass windowClass = WindowClass_new(&instance, Window_callback, "HandmadeWindowClass"); | |
| LongPointerConstString windowName = "Handmade Hero"; | |
| WindowHandler windowHandler = WindowHandler_new(&windowClass, windowName); | |
| bitmapInfo = BitmapInfo_new(windowHandler); | |
| WindowMessage message; | |
| while(running){ | |
| BOOL messageResult = GetMessage(&message, windowHandler, NO_MINIMUM_MESSAGE, NO_MAXIMUM_MESSAGE); | |
| if(messageResult > 0){ | |
| TranslateMessage(&message); | |
| DispatchMessage(&message); | |
| }else{ | |
| break; | |
| } | |
| } | |
| return 0; | |
| } | |
| int main(void){ | |
| // Calling it this way means we link through the console, which allows us to | |
| // printf debug. | |
| // Added bonus: You can kill the window from the terminal! | |
| WinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOW); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <windows.h> | |
| #define NO_MAXIMUM_MESSAGE 0 | |
| #define NO_MINIMUM_MESSAGE 0 | |
| #define ANY_VIRTUAL_MEMORY_LOCATION 0 | |
| #define RELEASE_ALL 0 | |
| #define DefaultWindowProcedure(window, message, wideParameter, longParameter) DefWindowProc(window, message, wideParameter, longParameter) | |
| typedef HINSTANCE InstanceHandler; | |
| typedef LPSTR LongStringPointer; | |
| typedef LPCSTR LongPointerConstString; | |
| typedef WNDCLASS WindowClass; | |
| typedef HWND WindowHandler; | |
| typedef WPARAM WideParameter; | |
| typedef LPARAM LongPointerParameter; | |
| typedef WNDPROC WindowProcedure; | |
| typedef LPCSTR LongPointerConstString; | |
| typedef HMENU MenuHandler; | |
| typedef MSG WindowMessage; | |
| typedef HDC DeviceContextHandler; | |
| typedef BITMAPINFO BitmapInfo; | |
| typedef HBITMAP BitmapHandle; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment