Exit the IDE, make a copy of the ch03 folder and rename it to ch04. Go to the ch04 folder and double-click on the project file to bring up the IDE.
First, copy-paste the following before your render() function:
void init()
{
for (int i = 0; i < WINDOW_WIDTH * WINDOW_HEIGHT; i++)
gFrameBuffer[i] = 0xff000000;
for (int i = 0; i < WINDOW_WIDTH; i++)
{
int p = (int)((sin((i + 3247) * 0.02) * 0.3 +
sin((i + 2347) * 0.04) * 0.1 +
sin((i + 4378) * 0.01) * 0.6) * 100 + (WINDOW_HEIGHT * 2 / 3));
int pos = p * WINDOW_WIDTH + i;
for (int j = p; j < WINDOW_HEIGHT; j++)
{
gFrameBuffer[pos] = 0xff007f00;
pos += WINDOW_WIDTH;
}
}
}
void newsnow()
{
for (int i = 0; i < 8; i++)
gFrameBuffer[rand() % (WINDOW_WIDTH - 2) + 1] = 0xffffffff;
}
void snowfall()
{
for (int j = WINDOW_HEIGHT - 2; j >= 0; j--)
{
int ypos = j * WINDOW_WIDTH;
for (int i = 1; i < WINDOW_WIDTH - 1; i++)
{
if (gFrameBuffer[ypos + i] == 0xffffffff)
{
if (gFrameBuffer[ypos + i + WINDOW_WIDTH] == 0xff000000)
{
gFrameBuffer[ypos + i + WINDOW_WIDTH] = 0xffffffff;
gFrameBuffer[ypos + i] = 0xff000000;
}
}
}
}
}
Before explaining what happens here, let's do a couple more things so you can see what it looks like first.
Replace the render()
function with the following:
void render()
{
newsnow();
snowfall();
}
Finally, go to the main()
function and add a call to init();
right before the main loop starts (before the gDone = 0;
line).
Compile and run.
You should have some white pixels falling down through the black pixels and stacking on the green pixels. It doesn't really look like snow, but we'll get to that in a bit. First, let's see what we have.
In various places, we're adding WINDOW_WIDTH
. This moves one row down, or increases the y coordinate.
The init()
function calculates the ground level using three sin()
functions, much like what we did with the x and y coordinates in the previous chapter. The ground is then filled using vertical bars and mid-green color (0xff007f00 - 7f hex is 127 decimal, which is about half of 256).
We can't assume the framebuffer is clear to begin with, as it just came off raw new[]
. So first, off, we'll fill out the whole buffer with black first with with a for loop. We'd love to use memset()
for this, but since the alpha has to be 255, loop it is.
The init()
function is the only place where we change the whole screen - all of the following operations just change the framebuffer a bit here and there.
The newsnow()
function draws eight white pixels on the top row in random places. Actually, the rand()
function supplied with the standard library is rather bad - if you stare at the "snow" for a while, you may already notice some patterns. C++ comes with better, standard random functions these days, but we'll keep things simple for now.
The snowfall()
function goes through the whole screen bottom-up, left to right. Whenever it finds a white pixel, it checks whether the pixel under it is black, and if so, moves the white dot down.
So what can we do to make the snow a bit snow-ish? Well, first, the snow around here doesn't stack in straight vertical piles, so let's add a couple of checks. You may have wondered why we're leaving the left and rightmost horizontal pixels alone with our snow - here's why. Replace the innermost if
block in the snowfall()
function with the following:
if (gFrameBuffer[ypos + i + WINDOW_WIDTH] == 0xff000000)
{
gFrameBuffer[ypos + i + WINDOW_WIDTH] = 0xffffffff;
gFrameBuffer[ypos + i] = 0xff000000;
}
else
if (gFrameBuffer[ypos + i + WINDOW_WIDTH - 1] == 0xff000000)
{
gFrameBuffer[ypos + i + WINDOW_WIDTH - 1] = 0xffffffff;
gFrameBuffer[ypos + i] = 0xff000000;
}
else
if (gFrameBuffer[ypos + i + WINDOW_WIDTH + 1] == 0xff000000)
{
gFrameBuffer[ypos + i + WINDOW_WIDTH + 1] = 0xffffffff;
gFrameBuffer[ypos + i] = 0xff000000;
}
If we hadn't left the leftmost and rightmost column alone, we would be reading and writing outside the screen now (which, as you'll remember, would be a Bad Thing to do).
Note that the speed of this effect is very dependent on the speed of the machine it's run on, and there's may also be a difference in speed between debug and release builds. Computers being crazy fast these days and screen update likely capped to 60Hz, it will look fine, but this is still something to keep in mind.
Additional things to try:
rand() % 100 + 350
. Can you fix it?WINDOW_WIDTH + 2
and WINDOW_WIDTH - 2
Okay, so we've read and written pixels so far. Combining old and new pixel data is rather important in computer graphics, and we'll be doing just that next...
Next up: 05 - Blending a Bit..
Any comments etc. can be emailed to me.