Handmade Hero»Episode Guide
Parsing PNG Headers
?
?

Keyboard Navigation

Global Keys

[, < / ], > Jump to previous / next episode
W, K, P / S, J, N Jump to previous / next marker
t / T Toggle theatre / SUPERtheatre mode
V Revert filter to original state Y Select link (requires manual Ctrl-c)

Menu toggling

q Quotes r References f Filter y Link c Credits

In-Menu Movement

a
w
s
d
h j k l


Quotes and References Menus

Enter Jump to timecode

Quotes, References and Credits Menus

o Open URL (in new tab)

Filter Menu

x, Space Toggle category and focus next
X, ShiftSpace Toggle category and focus previous
v Invert topics / media as per focus

Filter and Link Menus

z Toggle filter / linking mode

Credits Menu

Enter Open URL (in new tab)
0:00Recap and set the stage for the day
🗩
0:00Recap and set the stage for the day
🗩
0:00Recap and set the stage for the day
🗩
0:16Run the game to show the current camera and lighting situation, and consider our next steps
🏃
0:16Run the game to show the current camera and lighting situation, and consider our next steps
🏃
0:16Run the game to show the current camera and lighting situation, and consider our next steps
🏃
2:22Determine to support hot-loadable art assets in a readily usable format by Anna, i.e. PNG
🏃
2:22Determine to support hot-loadable art assets in a readily usable format by Anna, i.e. PNG
🏃
2:22Determine to support hot-loadable art assets in a readily usable format by Anna, i.e. PNG
🏃
4:53Consider our current BMP-loading code, with a view to implementing minimal PNG-loading
📖
4:53Consider our current BMP-loading code, with a view to implementing minimal PNG-loading
📖
4:53Consider our current BMP-loading code, with a view to implementing minimal PNG-loading
📖
9:24Install GIMP1
🗹
9:24Install GIMP1
🗹
9:24Install GIMP1
🗹
11:43Bring up the PNG specification2,3
📖
11:43Bring up the PNG specification2,3
📖
11:43Bring up the PNG specification2,3
📖
12:56Create a piece of structured art as a 1024×1024 8bpp RGBA PNG called gimp_test.png
🎨
12:56Create a piece of structured art as a 1024×1024 8bpp RGBA PNG called gimp_test.png
🎨
12:56Create a piece of structured art as a 1024×1024 8bpp RGBA PNG called gimp_test.png
🎨
19:33Embark on a PNG parser, creating handmade_png.cpp
19:33Embark on a PNG parser, creating handmade_png.cpp
19:33Embark on a PNG parser, creating handmade_png.cpp
21:59Run it to see our printf
🏃
21:59Run it to see our printf
🏃
21:59Run it to see our printf
🏃
22:09Grab ReadEntireFile() from test_asset_builder.cpp
22:09Grab ReadEntireFile() from test_asset_builder.cpp
22:09Grab ReadEntireFile() from test_asset_builder.cpp
23:18Run it to see it in action
🏃
23:18Run it to see it in action
🏃
23:18Run it to see it in action
🏃
23:34Introduce ParsePNG(), noting that it is not meant to be fault tolerant
23:34Introduce ParsePNG(), noting that it is not meant to be fault tolerant
23:34Introduce ParsePNG(), noting that it is not meant to be fault tolerant
25:44Setup the handmade_png.cpp project in MSVC
🗹
25:44Setup the handmade_png.cpp project in MSVC
🗹
25:44Setup the handmade_png.cpp project in MSVC
🗹
27:02Step through ReadEntireFile() and inspect its Result
🏃
27:02Step through ReadEntireFile() and inspect its Result
🏃
27:02Step through ReadEntireFile() and inspect its Result
🏃
27:45Create handmade_png.h
27:45Create handmade_png.h
27:45Create handmade_png.h
28:33Consult the PNG spec4 with an explanation of the RIFF generic file container format
📖
28:33Consult the PNG spec4 with an explanation of the RIFF generic file container format
📖
28:33Consult the PNG spec4 with an explanation of the RIFF generic file container format
📖
31:42Introduce png_header, png_chunk_header and png_chunk_footer structs, using #pragma pack5
31:42Introduce png_header, png_chunk_header and png_chunk_footer structs, using #pragma pack5
31:42Introduce png_header, png_chunk_header and png_chunk_footer structs, using #pragma pack5
35:54Begin to implement ParsePNG(), introducing ConsumeSize() to extract desired data from our file contents
35:54Begin to implement ParsePNG(), introducing ConsumeSize() to extract desired data from our file contents
35:54Begin to implement ParsePNG(), introducing ConsumeSize() to extract desired data from our file contents
43:49Run it and hit a file underflow error
🏃
43:49Run it and hit a file underflow error
🏃
43:49Run it and hit a file underflow error
🏃
44:25Step through ParsePNG() to realise that the ContentsSize doesn't decrease
🏃
44:25Step through ParsePNG() to realise that the ContentsSize doesn't decrease
🏃
44:25Step through ParsePNG() to realise that the ContentsSize doesn't decrease
🏃
44:43Fix ConsumeSize() to decrement the ContentsSize
44:43Fix ConsumeSize() to decrement the ContentsSize
44:43Fix ConsumeSize() to decrement the ContentsSize
45:03Step through ParsePNG()
🏃
45:03Step through ParsePNG()
🏃
45:03Step through ParsePNG()
🏃
46:23Consult the PNG spec for information on the Length field6
📖
46:23Consult the PNG spec for information on the Length field6
📖
46:23Consult the PNG spec for information on the Length field6
📖
47:07Change Type in png_chunk_header to be an array of four chars
47:07Change Type in png_chunk_header to be an array of four chars
47:07Change Type in png_chunk_header to be an array of four chars
47:30Step in to ParsePNG() to see our Type more easily
🏃
47:30Step in to ParsePNG() to see our Type more easily
🏃
47:30Step in to ParsePNG() to see our Type more easily
🏃
48:09Consult the PNG spec about for information on the Length field7
📖
48:09Consult the PNG spec about for information on the Length field7
📖
48:09Consult the PNG spec about for information on the Length field7
📖
50:20Inspect the FileContents as raw memory to determine that PNG may be big-endian
🏃
50:20Inspect the FileContents as raw memory to determine that PNG may be big-endian
🏃
50:20Inspect the FileContents as raw memory to determine that PNG may be big-endian
🏃
51:32Consult the PNG spec8 to see that it is indeed big-endianα
51:32Consult the PNG spec8 to see that it is indeed big-endianα
51:32Consult the PNG spec8 to see that it is indeed big-endianα
52:41Introduce EndianSwap()
52:41Introduce EndianSwap()
52:41Introduce EndianSwap()
1:01:35Add a test value and assertion in EndianSwap()
1:01:35Add a test value and assertion in EndianSwap()
1:01:35Add a test value and assertion in EndianSwap()
1:02:05Step in to EndianSwap() to see what it produces
🏃
1:02:05Step in to EndianSwap() to see what it produces
🏃
1:02:05Step in to EndianSwap() to see what it produces
🏃
1:02:37Step in to ParsePNG() to inspect our endian-swapped PNG data
🏃
1:02:37Step in to ParsePNG() to inspect our endian-swapped PNG data
🏃
1:02:37Step in to ParsePNG() to inspect our endian-swapped PNG data
🏃
1:03:41Enable ParsePNG() to print out the chunk types
1:03:41Enable ParsePNG() to print out the chunk types
1:03:41Enable ParsePNG() to print out the chunk types
1:04:34Run it to see our chunks
🏃
1:04:34Run it to see our chunks
🏃
1:04:34Run it to see our chunks
🏃
1:04:49Start to enable ParsePNG() to not bother parsing certain chunk types, introducing FOURCC() to turn a string into a 32-bit identifier
1:04:49Start to enable ParsePNG() to not bother parsing certain chunk types, introducing FOURCC() to turn a string into a 32-bit identifier
1:04:49Start to enable ParsePNG() to not bother parsing certain chunk types, introducing FOURCC() to turn a string into a 32-bit identifier
1:08:26Run it to see that our FOURCC() works
🏃
1:08:26Run it to see that our FOURCC() works
🏃
1:08:26Run it to see that our FOURCC() works
🏃
1:09:00Check the web9 to show other FOURCC() approaches
📖
1:09:00Check the web9 to show other FOURCC() approaches
📖
1:09:00Check the web9 to show other FOURCC() approaches
📖
1:09:46Try to make FOURCC() straight up cast the string to a u32 pointer
1:09:46Try to make FOURCC() straight up cast the string to a u32 pointer
1:09:46Try to make FOURCC() straight up cast the string to a u32 pointer
1:10:21Run it to see that this works
🏃
1:10:21Run it to see that this works
🏃
1:10:21Run it to see that this works
🏃
1:10:33Enable ParsePNG() to switch on our chunk types for conditional parsing
1:10:33Enable ParsePNG() to switch on our chunk types for conditional parsing
1:10:33Enable ParsePNG() to switch on our chunk types for conditional parsing
1:11:13Hit a compile error and revert FOURCC() to our bit-shifting approach
1:11:13Hit a compile error and revert FOURCC() to our bit-shifting approach
1:11:13Hit a compile error and revert FOURCC() to our bit-shifting approach
1:11:50Trim down ParsePNG() to only handle IHDR and IDAT, introducing png_ihdr struct10
1:11:50Trim down ParsePNG() to only handle IHDR and IDAT, introducing png_ihdr struct10
1:11:50Trim down ParsePNG() to only handle IHDR and IDAT, introducing png_ihdr struct10
1:21:30Run it to see our IHDR data
🏃
1:21:30Run it to see our IHDR data
🏃
1:21:30Run it to see our IHDR data
🏃
1:22:32Condense ParsePNG() down to only support 8bpp RBGA, deflate / inflate, and the International Standard-defined adaptive filtering and not interlaced PNGs11
1:22:32Condense ParsePNG() down to only support 8bpp RBGA, deflate / inflate, and the International Standard-defined adaptive filtering and not interlaced PNGs11
1:22:32Condense ParsePNG() down to only support 8bpp RBGA, deflate / inflate, and the International Standard-defined adaptive filtering and not interlaced PNGs11
1:25:59Jump into the IDAT chunk12
📖
1:25:59Jump into the IDAT chunk12
📖
1:25:59Jump into the IDAT chunk12
📖
1:30:03Consult the DEFLATE spec13
📖
1:30:03Consult the DEFLATE spec13
📖
1:30:03Consult the DEFLATE spec13
📖
1:31:56Huffman Tree
🖌
1:31:56Huffman Tree
🖌
1:31:56Huffman Tree
🖌
1:37:04Consult DEFLATE's use of Huffman coding14 with a note that Huffman excels with integral numbers of bits
📖
1:37:04Consult DEFLATE's use of Huffman coding14 with a note that Huffman excels with integral numbers of bits
📖
1:37:04Consult DEFLATE's use of Huffman coding14 with a note that Huffman excels with integral numbers of bits
📖
1:40:43“I'm gonna have to take a mulligan on that one.”β
📖
1:40:43“I'm gonna have to take a mulligan on that one.”β
📖
1:40:43“I'm gonna have to take a mulligan on that one.”β
📖
1:40:50Continue to consult the DEFLATE spec15
📖
1:40:50Continue to consult the DEFLATE spec15
📖
1:40:50Continue to consult the DEFLATE spec15
📖
1:50:41Setup ParsePNG() to decompress our images, introducing AllocatePixels()16
1:50:41Setup ParsePNG() to decompress our images, introducing AllocatePixels()16
1:50:41Setup ParsePNG() to decompress our images, introducing AllocatePixels()16
1:57:50Introduce png_idat_header and png_idat_footer for ParsePNG() to parse out of our file17
1:57:50Introduce png_idat_header and png_idat_footer for ParsePNG() to parse out of our file17
1:57:50Introduce png_idat_header and png_idat_footer for ParsePNG() to parse out of our file17
2:05:03Run it to see our IDAT chunk data18
🏃
2:05:03Run it to see our IDAT chunk data18
🏃
2:05:03Run it to see our IDAT chunk data18
🏃
2:06:44Q&A
🗩
2:06:44Q&A
🗩
2:06:44Q&A
🗩
2:07:28x13pixels Q: Instead of using the FOURCC() macro why not just use a single-quoted literal? For example, if ((ChunkHeader->TypeU32) == 'IHDR') {}
🗪
2:07:28x13pixels Q: Instead of using the FOURCC() macro why not just use a single-quoted literal? For example, if ((ChunkHeader->TypeU32) == 'IHDR') {}
🗪
2:07:28x13pixels Q: Instead of using the FOURCC() macro why not just use a single-quoted literal? For example, if ((ChunkHeader->TypeU32) == 'IHDR') {}
🗪
2:07:55bigmofo1 Q: What is wrong about using ImageMagick from the build system to convert all the images?
🗪
2:07:55bigmofo1 Q: What is wrong about using ImageMagick from the build system to convert all the images?
🗪
2:07:55bigmofo1 Q: What is wrong about using ImageMagick from the build system to convert all the images?
🗪
2:08:22x13pixels Q: Don't think so. I used it 20 years ago at least
🗪
2:08:22x13pixels Q: Don't think so. I used it 20 years ago at least
🗪
2:08:22x13pixels Q: Don't think so. I used it 20 years ago at least
🗪
2:09:14mtc743 handmade_hero Q: What math subject do I need to know to follow along? Should I learn linear algebra?
🗪
2:09:14mtc743 handmade_hero Q: What math subject do I need to know to follow along? Should I learn linear algebra?
🗪
2:09:14mtc743 handmade_hero Q: What math subject do I need to know to follow along? Should I learn linear algebra?
🗪
2:09:56ozkayace Q: Just little bit brainstorming, can somehow Zipf's law be used for benefit on Huffman?
🗪
2:09:56ozkayace Q: Just little bit brainstorming, can somehow Zipf's law be used for benefit on Huffman?
🗪
2:09:56ozkayace Q: Just little bit brainstorming, can somehow Zipf's law be used for benefit on Huffman?
🗪
2:10:11saidwho12 handmade_hero It would work if you bswap the type
🗪
2:10:11saidwho12 handmade_hero It would work if you bswap the type
🗪
2:10:11saidwho12 handmade_hero It would work if you bswap the type
🗪
2:10:21Change ParsePNG() to EndianSwap() the chunk type, and replace FOURCC() with direct equality checks on 'IHDR' and 'IDAT'
2:10:21Change ParsePNG() to EndianSwap() the chunk type, and replace FOURCC() with direct equality checks on 'IHDR' and 'IDAT'
2:10:21Change ParsePNG() to EndianSwap() the chunk type, and replace FOURCC() with direct equality checks on 'IHDR' and 'IDAT'
2:11:07ozkayace Q: Zipf's law19
🗪
2:11:07ozkayace Q: Zipf's law19
🗪
2:11:07ozkayace Q: Zipf's law19
🗪
2:13:28dudeinbasement1 Q: How could someone abuse the PNG loader? You brought up malformed code
🗪
2:13:28dudeinbasement1 Q: How could someone abuse the PNG loader? You brought up malformed code
🗪
2:13:28dudeinbasement1 Q: How could someone abuse the PNG loader? You brought up malformed code
🗪
2:14:28tybereon handmade_hero The png_idat_footer should be 4 bytes. I think you just have it as a single u8 right now
🗪
2:14:28tybereon handmade_hero The png_idat_footer should be 4 bytes. I think you just have it as a single u8 right now
🗪
2:14:28tybereon handmade_hero The png_idat_footer should be 4 bytes. I think you just have it as a single u8 right now
🗪
2:14:35Fix png_idat_footer
2:14:35Fix png_idat_footer
2:14:35Fix png_idat_footer
2:14:40mihaicris Q: Why are there several IDAT chunks and not one single one?
🗪
2:14:40mihaicris Q: Why are there several IDAT chunks and not one single one?
🗪
2:14:40mihaicris Q: Why are there several IDAT chunks and not one single one?
🗪
2:15:33vtlmks handmade_hero Not using _bswap() intrinsic instead?20
🗪
2:15:33vtlmks handmade_hero Not using _bswap() intrinsic instead?20
🗪
2:15:33vtlmks handmade_hero Not using _bswap() intrinsic instead?20
🗪
2:17:00Try to change EndianSwap() to use the _bswap intrinsic21
2:17:00Try to change EndianSwap() to use the _bswap intrinsic21
2:17:00Try to change EndianSwap() to use the _bswap intrinsic21
2:18:32Try to find the definition of _bswap
🏃
2:18:32Try to find the definition of _bswap
🏃
2:18:32Try to find the definition of _bswap
🏃
2:20:23Make EndianSwap() use the _byteswap_ulong intrinsic
2:20:23Make EndianSwap() use the _byteswap_ulong intrinsic
2:20:23Make EndianSwap() use the _byteswap_ulong intrinsic
2:21:00Step in to EndianSwap() and check out the asm
🏃
2:21:00Step in to EndianSwap() and check out the asm
🏃
2:21:00Step in to EndianSwap() and check out the asm
🏃
2:21:34Make EndianSwap() use our original approach, and compile in -O2
2:21:34Make EndianSwap() use our original approach, and compile in -O2
2:21:34Make EndianSwap() use our original approach, and compile in -O2
2:21:53Step in to EndianSwap() to see that the compiler output a bswap anyway
🏃
2:21:53Step in to EndianSwap() to see that the compiler output a bswap anyway
🏃
2:21:53Step in to EndianSwap() to see that the compiler output a bswap anyway
🏃
2:22:46bigmofo1 Q: Is the PNG loader to support allow live art iteration on stream? Art stream soon?
🗪
2:22:46bigmofo1 Q: Is the PNG loader to support allow live art iteration on stream? Art stream soon?
🗪
2:22:46bigmofo1 Q: Is the PNG loader to support allow live art iteration on stream? Art stream soon?
🗪
2:23:01pmttavara Q: Sorry if I missed it, but was there any reason the chunk types have the weird mixed case, like tEXt and pHYs etc?22
🗪
2:23:01pmttavara Q: Sorry if I missed it, but was there any reason the chunk types have the weird mixed case, like tEXt and pHYs etc?22
🗪
2:23:01pmttavara Q: Sorry if I missed it, but was there any reason the chunk types have the weird mixed case, like tEXt and pHYs etc?22
🗪
2:24:12saidwho12 Q: What's the 32-bit crc for?
🗪
2:24:12saidwho12 Q: What's the 32-bit crc for?
🗪
2:24:12saidwho12 Q: What's the 32-bit crc for?
🗪
2:25:02We're all done
🗩
2:25:02We're all done
🗩
2:25:02We're all done
🗩