From cbc0a07a1c189c14df9e6f563a8e381df3423cc7 Mon Sep 17 00:00:00 2001 From: igor Date: Wed, 27 May 2026 18:19:20 -0700 Subject: [PATCH] Some work done to draw program icon dynamically. --- data/program_icon.bmp | Bin 0 -> 40138 bytes sdl_handmade.c | 195 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 175 insertions(+), 20 deletions(-) create mode 100644 data/program_icon.bmp diff --git a/data/program_icon.bmp b/data/program_icon.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e58c43ed8186f1f5e29a6477850a442474915922 GIT binary patch literal 40138 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 PZQ4}Deqn+4sRjNAeHgC| literal 0 HcmV?d00001 diff --git a/sdl_handmade.c b/sdl_handmade.c index a2f7e8f..b49c167 100644 --- a/sdl_handmade.c +++ b/sdl_handmade.c @@ -595,32 +595,175 @@ U64 __rdtsc() * 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. */ -void SDLSetProgramIcon(SDL_Window *Window) -{ -#if 0 - U32 Rmask, Gmask, Bmask, Amask; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - S32 shift_by = (program_icon.bytes_per_pixel == 3) ? 8 : 0; - Rmask = 0xff000000 >> shift_by; - Gmask = 0x00ff0000 >> shift_by; - Bmask = 0x0000ff00 >> shift_by; - Amask = 0x000000ff >> shift_by; -#else - Rmask = 0x000000ff; - Gmask = 0x0000ff00; - Bmask = 0x00ff0000; - Amask = (program_icon.bytes_per_pixel == 3) ? 0 : 0xff000000; -#endif - SDL_Surface * icon = SDL_CreateRGBSurfaceFrom((void *)program_icon.pixel_data, program_icon.width, program_icon.height, - program_icon.bytes_per_pixel * 8, program_icon.bytes_per_pixel * program_icon.width, Rmask, Gmask, Bmask, Amask); +#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 A = (F32)((*Source >> 24) & 0xFF) / 255.0f; + 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); + + // 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++; + 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++; + } + } + +#if 0 + U32 *Beginning = Pixels; + U32 *Ending = Pixels + (Header->Width * Header->Height); + for(S32 Y = 0; Y < Header->Height; Y++) { + for(S32 X = 0; X < Header->Width; X++) { + U32 Temp = *Beginning; + *Beginning = *Ending; + *Ending = Temp; + + Beginning++; + Ending--; + } + } +#endif + } + + return Result; +} + +void SDLSetProgramIcon(SDL_Window *Window, game_offscreen_buffer *ProgramIcon) +{ + U32 Rmask, Gmask, Bmask, Amask; + Rmask = 0x00ff0000; + Gmask = 0x0000ff00; + Bmask = 0x000000ff; + Amask = 0xff000000; + + SDL_Surface *icon = SDL_CreateRGBSurfaceFrom((void *)ProgramIcon->Memory, ProgramIcon->Width, ProgramIcon->Height, ProgramIcon->BytesPerPixel * 8, ProgramIcon->BytesPerPixel * ProgramIcon->Width, Rmask, Gmask, Bmask, Amask); if(icon) { SDL_SetWindowIcon(Window, icon); SDL_FreeSurface(icon); } else { /* TODO: This didn't work . . . SDL_GetError() */ } -#endif } #include "handmade_intrinsics.h" @@ -662,7 +805,19 @@ S32 main(S32 argc, char *argv[]) * its actual size. */ /* SDL_RenderPresent(Renderer) is enough to display the window. */ if(Renderer) { - SDLSetProgramIcon(Window); + thread_context TempContext; // TODO: + memset(&TempContext, 0, sizeof(TempContext)); + + loaded_bitmap ProgramIcon = DEBUGLoadBMPP(&TempContext, DEBUGPlatformReadEntireFile, "data/program_icon.bmp"); + game_offscreen_buffer ProgramIconBuffer; + ProgramIconBuffer.Memory = malloc((ProgramIcon.Width * ProgramIcon.Height) * 4); + ProgramIconBuffer.Width = ProgramIcon.Width; + ProgramIconBuffer.Height = ProgramIcon.Height; + ProgramIconBuffer.BytesPerPixel = 4; + ProgramIconBuffer.Pitch = 4 * ProgramIcon.Width; + + DrawBitmap(&ProgramIconBuffer, &ProgramIcon, 0, 0, 0, 0); + SDLSetProgramIcon(Window, &ProgramIconBuffer); // TODO: Make it a global. SDL_Cursor *PointerCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);