From 1ba8acfe5197179b8ab0c9888c1f17532ea0ca7e Mon Sep 17 00:00:00 2001 From: igor Date: Fri, 29 May 2026 15:24:46 -0700 Subject: [PATCH] Moved program icon drawing into handmade layer. --- data/program_icon.bmp | Bin 40138 -> 262282 bytes handmade.c | 19 ++++- handmade.h | 16 ++-- sdl_handmade.c | 179 +++++------------------------------------- sdl_handmade.h | 3 +- 5 files changed, 48 insertions(+), 169 deletions(-) diff --git a/data/program_icon.bmp b/data/program_icon.bmp index e58c43ed8186f1f5e29a6477850a442474915922..1cb812327bca1baa9b4d9e420feb2e5a4cc38153 100644 GIT binary patch literal 262282 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 literal 40138 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 PZQ4}Deqn+4sRjNAeHgC| diff --git a/handmade.c b/handmade.c index 976fa1a..813c641 100644 --- a/handmade.c +++ b/handmade.c @@ -123,7 +123,7 @@ static void DrawBitmap(game_offscreen_buffer *Buffer, loaded_bitmap *Bitmap, F32 U32 *Dest = (U32 *)DestRow; U32 *Source = SourceRow; for(S32 X = MinX; X < MaxX; X++) { - F32 A = (F32)((*Source >> 24) & 0xFF) / 255.0f; + F32 SA = (F32)((*Source >> 24) & 0xFF); F32 SR = (F32)((*Source >> 16) & 0xFF); F32 SG = (F32)((*Source >> 8) & 0xFF); F32 SB = (F32)((*Source >> 0) & 0xFF); @@ -132,12 +132,14 @@ static void DrawBitmap(game_offscreen_buffer *Buffer, loaded_bitmap *Bitmap, F32 F32 DG = (F32)((*Dest >> 8) & 0xFF); F32 DB = (F32)((*Dest >> 0) & 0xFF); + F32 A = SA / 255.0f; + // TODO: This should be replaced by premultiplied alpha. F32 R = (1.0f-A)*DR + A*SR; F32 G = (1.0f-A)*DG + A*SG; F32 B = (1.0f-A)*DB + A*SB; - *Dest = (((U32)RoundF32toS32(R) << 16) | ((U32)RoundF32toS32(G) << 8) | ((U32)RoundF32toS32(B) << 0)); + *Dest = (((U32)RoundF32toS32(SA) << 24) | ((U32)RoundF32toS32(R) << 16) | ((U32)RoundF32toS32(G) << 8) | ((U32)RoundF32toS32(B) << 0)); Dest++; Source++; @@ -234,7 +236,18 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, game_input *In GameState = (game_state *)Memory->PermanentStorage; if(!Memory->IsInitialized) { - GameState->Backdrop = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_background.bmp"); + GameState->ProgramIcon.Width = 256; + GameState->ProgramIcon.Height = 256; + GameState->ProgramIcon.BytesPerPixel = 4; + GameState->ProgramIcon.Pitch = GameState->ProgramIcon.BytesPerPixel * GameState->ProgramIcon.Width; + GameState->ProgramIcon.Memory = malloc(GameState->ProgramIcon.BytesPerPixel * GameState->ProgramIcon.Width * GameState->ProgramIcon.Height); + memset(GameState->ProgramIcon.Memory, 0, GameState->ProgramIcon.BytesPerPixel * GameState->ProgramIcon.Width * GameState->ProgramIcon.Height); + + GameState->ProgramIconBMP = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/program_icon.bmp"); + DrawBitmap(&GameState->ProgramIcon, &GameState->ProgramIconBMP, 0.0f, 0.0f, 0, 0); + Memory->SetProgramIcon(&GameState->ProgramIcon); + + GameState->Backdrop = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_background.bmp"); hero_bitmaps *Bitmap; diff --git a/handmade.h b/handmade.h index 8259f45..ff08613 100644 --- a/handmade.h +++ b/handmade.h @@ -3,7 +3,6 @@ #include "core.h" #include "handmade_tile.h" - /* --------------------------------------------------------------------- */ /* NOTE: Servcies that the platform layer provides to the game. */ /* --------------------------------------------------------------------- */ @@ -23,13 +22,15 @@ B32 DEBUGPlatformWriteEntireFile(thread_context *Thread, const char *Filename, U void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory); #endif +typedef struct game_offscreen_buffer game_offscreen_buffer; +void SetProgramIcon(game_offscreen_buffer *ProgramIcon); + /* --------------------------------------------------------------------- */ /* NOTE: Servcies that the game provides to the platform layer. */ /* --------------------------------------------------------------------- */ typedef struct game_offscreen_buffer { - /* Pixels are always 32-bit and have the bytes in BGRX - * (little-endian). */ + /* Pixels are always 32-bit and have the bytes in BGRX (little-endian). */ void *Memory; S32 Width; S32 Height; @@ -112,6 +113,7 @@ typedef struct game_memory { debug_read_file_result (*DEBUGPlatformReadEntireFile)(thread_context *Thread,const char *); B32 (*DEBUGPlatformWriteEntireFile)(thread_context *Thread, const char *, U32, void *); void (*DEBUGPlatformFreeFileMemory)(thread_context *Thread, void *); + void (*SetProgramIcon)(game_offscreen_buffer *ProgramIcon); #endif } game_memory; @@ -123,9 +125,7 @@ typedef struct game_memory { #if OS_WINDOWS __declspec(dllexport) #endif -void UpdateAndRender(thread_context *Thread, game_memory *Memory, - game_input *Input, game_offscreen_buffer *Buffer, - game_sound_output_buffer *SoundBuffer); +void UpdateAndRender(thread_context *Thread, game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer); /* * @@ -177,6 +177,9 @@ typedef struct hero_bitmaps { } hero_bitmaps; typedef struct game_state { + game_offscreen_buffer ProgramIcon; + loaded_bitmap ProgramIconBMP; + memory_arena WorldArena; world *World; @@ -184,6 +187,7 @@ typedef struct game_state { tile_map_position PlayerP; v2 dPlayerP; // velocity + loaded_bitmap Backdrop; U32 FacingDirection; diff --git a/sdl_handmade.c b/sdl_handmade.c index aba61cb..d9fea10 100644 --- a/sdl_handmade.c +++ b/sdl_handmade.c @@ -56,6 +56,8 @@ SDL_GameController *ControllerHandles[MAX_CONTROLLERS]; static offscreen_buffer GlobalBackbuffer; +SDL_Window *LastWindow; + static B32 IsFullscreen; static sdl_window_size WindowSize; static sdl_window_position WindowPosition; @@ -138,6 +140,20 @@ void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory) free(Memory); // TODO: Should we accept debug_read_file_result instead of just memory. } +void SetProgramIcon(game_offscreen_buffer *ProgramIcon) +{ + SDL_Window *Window = LastWindow; + + SDL_Surface *Icon = SDL_CreateRGBSurfaceWithFormatFrom((void *)ProgramIcon->Memory, ProgramIcon->Width, ProgramIcon->Height, ProgramIcon->BytesPerPixel * 8, ProgramIcon->BytesPerPixel * ProgramIcon->Width, SDL_PIXELFORMAT_ARGB8888); + if(!Icon) { + /* TODO: This didn't work . . . SDL_GetError() */ + return ; + } + + SDL_SetWindowIcon(Window, Icon); + SDL_FreeSurface(Icon); +} + static sdl_border_size SDLGetWindowBorderSizes(SDL_Window *Window) { sdl_border_size Result; @@ -620,163 +636,6 @@ U64 __rdtsc() } #endif -/* TODO: In the future, this should just accept either a bitmap or image - * path. This is to be determined. One cool feature this might - * support is displaying certain information in the program icon by - * drawing into a bitmap. */ - -#include "handmade_intrinsics.h" - -static void DrawBitmap(game_offscreen_buffer *Buffer, loaded_bitmap *Bitmap, F32 RelX, F32 RelY, S32 AlignX, S32 AlignY) -{ - RelX -= (F32)AlignX; - RelY -= (F32)AlignY; - - S32 MinX = RoundF32toS32(RelX); - S32 MinY = RoundF32toS32(RelY); - S32 MaxX = RoundF32toS32(RelX + (F32)Bitmap->Width); - S32 MaxY = RoundF32toS32(RelY + (F32)Bitmap->Height); - - S32 Width = Buffer->Width; - S32 Height = Buffer->Height; - - S32 SourceOffsetX = 0; - if(MinX < 0) { - SourceOffsetX = -MinX; - MinX = 0; - } - - S32 SourceOffsetY = 0; - if(MinY < 0) { - SourceOffsetY = -MinY; - MinY = 0; - } - - if(MaxX > Width) - MaxX = Width; - if(MaxY > Height) - MaxY = Height; - - U32 *SourceRow = Bitmap->Pixels + Bitmap->Width*(Bitmap->Height - 1); - SourceRow += -Bitmap->Width*SourceOffsetY + SourceOffsetX; - U8 *DestRow = ((U8 *)Buffer->Memory + MinX*Buffer->BytesPerPixel + MinY*Buffer->Pitch); - for(S32 Y = MinY; Y < MaxY; Y++) { - U32 *Dest = (U32 *)DestRow; - U32 *Source = SourceRow; - for(S32 X = MinX; X < MaxX; X++) { - F32 SA = (F32)((*Source >> 24) & 0xFF); - F32 SR = (F32)((*Source >> 16) & 0xFF); - F32 SG = (F32)((*Source >> 8) & 0xFF); - F32 SB = (F32)((*Source >> 0) & 0xFF); - - F32 DR = (F32)((*Dest >> 16) & 0xFF); - F32 DG = (F32)((*Dest >> 8) & 0xFF); - F32 DB = (F32)((*Dest >> 0) & 0xFF); - - F32 A = SA / 255.0f; - - // TODO: This should be replaced by premultiplied alpha. - F32 R = (1.0f-A)*DR + A*SR; - F32 G = (1.0f-A)*DG + A*SG; - F32 B = (1.0f-A)*DB + A*SB; - - *Dest = (((U32)RoundF32toS32(SA) << 24) | ((U32)RoundF32toS32(R) << 16) | ((U32)RoundF32toS32(G) << 8) | ((U32)RoundF32toS32(B) << 0)); - - Dest++; - Source++; - } - DestRow += Buffer->Pitch; - SourceRow -= Bitmap->Width; - } -} - -#pragma pack(push, 1) -typedef struct bitmap_header { - U16 FileType; - U32 FileSize; - U16 Reserved1; - U16 Reserved2; - U32 BitmapOffset; - U32 Size; - S32 Width; - S32 Height; - U16 Planes; - U16 BitsPerPixel; - U32 Compression; - U32 SizeOfBitmap; - S32 HorzResolution; - S32 VertResolution; - U32 ColorsUsed; - U32 ColorsImportant; - - U32 RedMask; - U32 GreenMask; - U32 BlueMask; -} bitmap_header; -#pragma pack(pop) - -static loaded_bitmap DEBUGLoadBMPP(thread_context *Thread, debug_read_file_result (*DEBUGPlatformReadEntireFile)(thread_context *Thread, const char *), char *FileName) -{ - loaded_bitmap Result; - memset(&Result, 0, sizeof(Result)); - - debug_read_file_result ReadResult = DEBUGPlatformReadEntireFile(Thread, FileName); - if(ReadResult.ContentsSize > 0) { - bitmap_header *Header = (bitmap_header *)ReadResult.Contents; - - U32 *Pixels = (U32 *)((U8 *)ReadResult.Contents + Header->BitmapOffset); - Result.Pixels = Pixels; - Result.Width = Header->Width; - Result.Height = Header->Height; - - ASSERT(Header->Compression == 3); - - // NOTE: The byte order in memory is determined by the Header. - - U32 RedMask = Header->RedMask; - U32 GreenMask = Header->GreenMask; - U32 BlueMask = Header->BlueMask; - U32 AlphaMask = ~(RedMask | GreenMask | BlueMask); - - bit_scan_result RedShift = FindLeastSignificantSetBit(RedMask); - bit_scan_result GreenShift = FindLeastSignificantSetBit(GreenMask); - bit_scan_result BlueShift = FindLeastSignificantSetBit(BlueMask); - bit_scan_result AlphaShift = FindLeastSignificantSetBit(AlphaMask); - - ASSERT(RedShift.Found); - ASSERT(GreenShift.Found); - ASSERT(BlueShift.Found); - ASSERT(AlphaShift.Found); - - U32 *SourceDest = Pixels; - for(S32 Y = 0; Y < Header->Height; Y++) { - for(S32 X = 0; X < Header->Width; X++) { - U32 C = *SourceDest; - - *SourceDest = ((((C >> AlphaShift.Index) & 0xFF) << 24) | - (((C >> RedShift.Index ) & 0xFF) << 16) | - (((C >> GreenShift.Index) & 0xFF) << 8) | - (((C >> BlueShift.Index ) & 0xFF) << 0)); - SourceDest++; - } - } - } - - return Result; -} - -void SDLSetProgramIcon(SDL_Window *Window, game_offscreen_buffer *ProgramIcon) -{ - SDL_Surface *icon = SDL_CreateRGBSurfaceWithFormatFrom((void *)ProgramIcon->Memory, ProgramIcon->Width, ProgramIcon->Height, ProgramIcon->BytesPerPixel * 8, ProgramIcon->BytesPerPixel * ProgramIcon->Width, SDL_PIXELFORMAT_ARGB8888); - if(icon) { - SDL_SetWindowIcon(Window, icon); - SDL_FreeSurface(icon); - } else { - /* TODO: This didn't work . . . SDL_GetError() */ - } -} - -#include "handmade_intrinsics.h" S32 main(S32 argc, char *argv[]) { sdl_state SDLState; @@ -799,8 +658,9 @@ S32 main(S32 argc, char *argv[]) * the window once everything is ready. */ // TODO: SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, in non-debug build SDL_Window *Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, RESOLUTION_WIDTH+20, RESOLUTION_HEIGHT+20, SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE/* | SDL_WINDOW_ALWAYS_ON_TOP*/); - if(Window) { + LastWindow = Window; + SDL_DisplayMode display_mode; SDL_GetCurrentDisplayMode(0, &display_mode); // Various display information. @@ -822,6 +682,7 @@ S32 main(S32 argc, char *argv[]) // This way, we can use all the drawing functions of handmade. // https://learn.microsoft.com/en-us/windows/apps/design/iconography/app-icon-construction // Probably, the icon size should be 256x256, so windows scales it properly. This buffer should be allocated into the arena. +#if 0 loaded_bitmap ProgramIcon = DEBUGLoadBMPP(&TempContext, DEBUGPlatformReadEntireFile, "data/program_icon.bmp"); game_offscreen_buffer ProgramIconBuffer; ProgramIconBuffer.Memory = malloc((ProgramIcon.Width * ProgramIcon.Height) * 4); @@ -833,6 +694,7 @@ S32 main(S32 argc, char *argv[]) DrawBitmap(&ProgramIconBuffer, &ProgramIcon, 0, 0, 0, 0); SDLSetProgramIcon(Window, &ProgramIconBuffer); +#endif // TODO: Make it a global. SDL_Cursor *PointerCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); @@ -880,6 +742,7 @@ S32 main(S32 argc, char *argv[]) GameMemory.PermanentStorageSize = MB(64); GameMemory.TransientStorageSize = GB(1); GameMemory.DEBUGPlatformReadEntireFile = &DEBUGPlatformReadEntireFile; + GameMemory.SetProgramIcon = &SetProgramIcon; //GameMemory.DEBUGPlatformWriteEntireFile = &DEBUGPlatformWriteEntireFile; GameMemory.DEBUGPlatformFreeFileMemory = &DEBUGPlatformFreeFileMemory; diff --git a/sdl_handmade.h b/sdl_handmade.h index 32f359b..3fea49c 100644 --- a/sdl_handmade.h +++ b/sdl_handmade.h @@ -24,8 +24,7 @@ typedef struct sdl_window_position { } sdl_window_position; typedef struct offscreen_buffer { - /* Pixels are always 32-bit and have the bytes in BGRX - * (little-endian). */ + /* Pixels are always 32-bit and have the bytes in BGRX (little-endian). */ SDL_Texture *Texture; void *Memory; S32 Width;