Difference between revisions of "Intermediate C++ Game Programming Tutorial 10"
(→Video Timestamp Index) |
m (Text replacement - "http://www.planetchili.net/" to "https://www.planetchili.net/") |
||
(One intermediate revision by one other user not shown) | |||
Line 38: | Line 38: | ||
* Load the DIB Header <code>BITMAPINFOHEADER</code> [https://youtu.be/0z3uCzitO7Y?t=15m08s 15:08] | * Load the DIB Header <code>BITMAPINFOHEADER</code> [https://youtu.be/0z3uCzitO7Y?t=15m08s 15:08] | ||
* Load 8-bit RBG values of the Bitmap File into pixel array of a <code>Surface</code> object [https://youtu.be/0z3uCzitO7Y?t=17m00s 17:00] | * Load 8-bit RBG values of the Bitmap File into pixel array of a <code>Surface</code> object [https://youtu.be/0z3uCzitO7Y?t=17m00s 17:00] | ||
− | * Calculate padding at the end of a bitmap row | + | * Calculate padding at the end of a bitmap row [https://youtu.be/0z3uCzitO7Y?t=18m40s 18:40] |
* Do a test run, loading a Bitmap file and drawing it to the screen [https://youtu.be/0z3uCzitO7Y?t=22m32s 22:32] | * Do a test run, loading a Bitmap file and drawing it to the screen [https://youtu.be/0z3uCzitO7Y?t=22m32s 22:32] | ||
* Test the order of the color channels [https://youtu.be/0z3uCzitO7Y?t=24m46s 24:46] | * Test the order of the color channels [https://youtu.be/0z3uCzitO7Y?t=24m46s 24:46] | ||
Line 48: | Line 48: | ||
== Download Materials == | == Download Materials == | ||
− | * [ | + | * [https://www.planetchili.net/downloads/I10-Images.zip Tutorial and Homework Bitmaps] |
== Homework == | == Homework == |
Latest revision as of 13:26, 5 May 2022
The promised day has come. We're finally going to be loading images from bitmap files into memory and drawing them as sprites on the screen. This is where all that stuff we've been learning--data types, pointers, memory management, file access, etc.--is going to pay off bigtime. Also, get fukt massive PutPixel sprite functions; die in a garbage fire.
Contents
Topics Covered
-
Surface
class for storing image data in memory - Parsing Windows bitmap file headers and loading pixel data
- Calculating padding
- Drawing sprites (pixel blocks) from a
Surface
to the screen
Notes
Channel Byte Order
There is a rather large issue with the order in which the color channels are loaded from the bitmap file, but due to a freak of coincidence, the code works regardless. Still, we must address this buttfuckery.
The way the channels are laid out in the file is (in order of low offset to high offset) |B| |G| |R|. Now the line of code that simultaneously reads the 3 bytes of the 3 color channels, constructs a Color object, and writes it into the Surface is: PutPixel( x,y,Color( file.get(),file.get(),file.get() ) );
. The function prototype of the Color constructor is Color( unsigned char r,unsigned char g,unsigned char b )
, so the order here is RGB, and we would expect that our code would be messed up (the R and B channels would be swapped). But this is not the case. What gives?
Well you might (understandably) assume that our function call to the ctor evaluates the get()
parameter expressions in the following order Color( file.get()first(B),file.get()second(G),file.get()third(R) )
, that is to say, the list of parameter expressions being evaluated in left-to-right order. In actuality, the compiler evaluates them in right-to-left order, i.e. Color( file.get()third(R),file.get()second(G),file.get()first(B) )
, and this is why our code happens to work!
Even stranger is the fact that the C++ standard does not specify the order in which the parameter expressions are evaluated! So it is possible that a different compiler could generate code that gives a different permutation of the color channels. In actuality, we can expect most compilers to do it right-to-left because of the way parameters will be pushed onto the stack (which is mandated), but still, it is terrible practice to rely on this unspecified behavior to always be the way we wish it to be.
The following code fixes this problem. It will be applied (in later downstream commits) to the Sprite repo and the Twin repo on GitHub.
const unsigned char b = file.get();
const unsigned char g = file.get();
const unsigned char r = file.get();
PutPixel( x,y,{ r,g,b } );
Self Assignment
We definitely should be checking for self assignment (mySurf = mySurf;
) in the assignment operator for Surface
. See the Errata of Intermediate 6 for more details.
Video Timestamp Index
- Creating a datatype (
Surface
class) to hold image data 0:13 - Add member function
DrawSprite
toGraphics
class to draw aSurface
object to the screen 5:03 - Test the code with a funky sprite design 7:43
- Load sprites in a
Surface
object from a Bitmap file 9:09 - Exploring the Bitmap Filetype 9:18
- Load the Bitmap file header
BITMAPFILEHEADER
10:54 - Load the DIB Header
BITMAPINFOHEADER
15:08 - Load 8-bit RBG values of the Bitmap File into pixel array of a
Surface
object 17:00 - Calculate padding at the end of a bitmap row 18:40
- Do a test run, loading a Bitmap file and drawing it to the screen 22:32
- Test the order of the color channels 24:46
- Using
assert
, add a test to see if file loading succeeded 25:21 - Homework assignment 27:21
Source Code
Download Materials
Homework
The homework is to improve the bitmap loading routine to support 32-bit RGB format and to support bitmaps with reverse row order.