diff --git a/data/program_icon.bmp b/data/program_icon.bmp index e58c43e..1cb8123 100644 Binary files a/data/program_icon.bmp and b/data/program_icon.bmp differ 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;