Handmade Hero»Forums»Code
Joseph Abell
4 posts
Working with PNG files
Hi All,

I've been trying to figure out how to load pngs to the engine, rather than relying on my artist to translate the PNG files into BMP files, or doing the translation through GIMP myself. The trouble is that I'm running into a severe lack of clear documentation on what is in the PNG24 file format.

While researching this, I saw that nothings has created a public domain library called stb_image, which I am planning to learn from. I managed to get it working just fine, but then I ran into trouble being able to save the data coming from the library into memory for future use. I'm missing some pretty basic knowledge on how to pack the 8bit channels of colors into a 32bit stream of pixels, and store them into the memory arena. It looks like on day 56, which is where I am at, we have removed all examples of PushArrays, so I'm having trouble seeing what I should be seeing when that gets returned.

So I've come to an impasse, and I cannot figure out what the next step on my quest for PNG file support would be. I can see why we chose to do BMPs if this is the amount of trouble that I'm running into. Can any kind person help me figure out what the file structure is for PNG24, and what basic steps I should take to replicate loading in the BMPs? Thanks in advance!
Asaf Gartner
50 posts
Handmade Network Staff
Working with PNG files
It looks like day 56 is missing some utilities that you might find useful.

Now we have PushSize, which would be a better candidate for allocating memory for a bitmap, but it just calls PushSize_, which already exists on day 56.

We also have the following:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
internal void
ClearBitmap(loaded_bitmap *Bitmap)
{
    if(Bitmap->Memory)
    {
        int32 TotalBitmapSize = Bitmap->Width*Bitmap->Height*BITMAP_BYTES_PER_PIXEL;
        ZeroSize(TotalBitmapSize, Bitmap->Memory);
    }
}

internal loaded_bitmap
MakeEmptyBitmap(memory_arena *Arena, int32 Width, int32 Height, bool32 ClearToZero = true)
{
    loaded_bitmap Result = {};

    Result.AlignPercentage = V2(0.5f, 0.5f);
    Result.WidthOverHeight = SafeRatio1((r32)Width, (r32)Height);

    Result.Width = Width;
    Result.Height = Height;
    Result.Pitch = Result.Width*BITMAP_BYTES_PER_PIXEL;
    int32 TotalBitmapSize = Width*Height*BITMAP_BYTES_PER_PIXEL;
    Result.Memory = PushSize(Arena, TotalBitmapSize, 16);
    if(ClearToZero)
    {
        ClearBitmap(&Result);
    }

    return(Result);
}


There's a good chance that the loaded_bitmap struct changed since day 56, but that's pretty much what you'd want to do to create an empty loaded_bitmap of the correct size.

After that, you just need to copy over the pixel data that you get from stb_image (and possibly rearrange the pixel components).