Skip to content

Instantly share code, notes, and snippets.

@RomanADavis
Created July 27, 2024 02:25
Show Gist options
  • Select an option

  • Save RomanADavis/e6b4c5d2f1d15ffa4249537fc380ab82 to your computer and use it in GitHub Desktop.

Select an option

Save RomanADavis/e6b4c5d2f1d15ffa4249537fc380ab82 to your computer and use it in GitHub Desktop.
Problem getting StretchDIBits to work
#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);
}
#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