Moved program icon drawing into handmade layer.

This commit is contained in:
2026-05-29 15:24:46 -07:00
parent 94e20cdff5
commit 1ba8acfe51
5 changed files with 48 additions and 169 deletions
+21 -158
View File
@@ -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;