Tutorial 08 - The Big Calm
This tutorial demonstrates usage of special effects and complex lighting simulation.
Shades of the Sky
To render the sky we use a sprite without texture:
hgeSprite *sky;
sky=new hgeSprite(0, 0, 0, SCREEN_WIDTH, SKY_HEIGHT);
It's top and bottom vertices are tinted into different colors, resulting in smooth transition:
hgeColor colSkyTop;
hgeColor colSkyBtm;
sky->SetColor(colSkyTop.GetHWColor(), 0);
sky->SetColor(colSkyTop.GetHWColor(), 1);
sky->SetColor(colSkyBtm.GetHWColor(), 2);
sky->SetColor(colSkyBtm.GetHWColor(), 3);
sky->Render(0, 0);
The sky colors depend on time of day and are calculated by interpolation
between several constant tints:
hgeColor col1, col2;
col1.SetHWColor(skyTopColors[seq[seq_id]]);
col2.SetHWColor(skyTopColors[seq[seq_id+1]]);
colSkyTop=col2*seq_residue + col1*(1.0f-seq_residue);
col1.SetHWColor(skyBtmColors[seq[seq_id]]);
col2.SetHWColor(skyBtmColors[seq[seq_id+1]]);
colSkyBtm=col2*seq_residue + col1*(1.0f-seq_residue);
The Sea and Waves
The same coloring technique is used for the sea. But this time we use
hgeDistortionMesh class instead
of hgeSprite to allow waves simulation:
hgeDistortionMesh *sea;
sea=new hgeDistortionMesh(SEA_SUBDIVISION, SEA_SUBDIVISION);
sea->SetTextureRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-SKY_HEIGHT);
To create waves we set a displacement and tint for every distortion mesh node
(we skip first and last line for now as we don't want them to move):
for(i=1; i<SEA_SUBDIVISION-1; i++)
{
// these are constants for each vertices line
a=float(i)/(SEA_SUBDIVISION-1);
col1=colSeaTop*(1-a)+colSeaBtm*a;
dwCol1=col1.GetHWColor();
fTime=2.0f*hge->Timer_GetTime();
a*=20;
for(j=0; j<SEA_SUBDIVISION; j++)
{
sea->SetColor(j, i, dwCol1);
dy=a*sinf(seaP[i]+ // precalculated phase shift
(float(j)/(SEA_SUBDIVISION-1)-0.5f)*M_PI*16.0f-fTime);
sea->SetDisplacement(j, i, 0.0f, dy, HGEDISP_NODE);
}
}
Now we set tints for previously skipped first and last lines of distortion mesh nodes:
dwCol1=colSeaTop.GetHWColor();
dwCol2=colSeaBtm.GetHWColor();
for(j=0; j<SEA_SUBDIVISION; j++)
{
sea->SetColor(j, 0, dwCol1);
sea->SetColor(j, SEA_SUBDIVISION-1, dwCol2);
}
The sea is ready now and we render it with just one call:
sea->Render(0, SKY_HEIGHT);
In actual source code a light path from moon and sun is also simulated.
To do this we just add a bit of white tint into distortion mesh nodes
that are currently under the sun/moon.
Celestial Bodies
Stars, moon and sun are just scaled and tinted sprites:
hgeSprite *sun;
hgeSprite *moon;
hgeSprite *star;
sun=new hgeSprite(texObjects,81,0,114,114);
sun->SetHotSpot(57,57);
moon=new hgeSprite(texObjects,0,0,81,81);
moon->SetHotSpot(40,40);
star=new hgeSprite(texObjects,72,81,9,9);
star->SetHotSpot(5,5);
The interesting part about them are halos and reflection
on the sea surface. These are just sprites too:
hgeSprite *glow;
hgeSprite *seaglow;
glow=new hgeSprite(texObjects,128,128,128,128);
glow->SetHotSpot(64,64);
glow->SetBlendMode(BLEND_COLORADD | BLEND_ALPHABLEND);
seaglow=new hgeSprite(texObjects,128,224,128,32);
seaglow->SetHotSpot(64,0);
seaglow->SetBlendMode(BLEND_COLORADD | BLEND_ALPHAADD);
Note that halo sprites use different blending modes to achieve proper coloring.
Also note that both sprites share the same texture region.
The sun and the moon positions, scaling and tints are calculated in
UpdateSimulation function and then they are rendered in RenderSimulation:
glow->SetColor(colSunGlow.GetHWColor());
glow->RenderEx(sunX, sunY, 0.0f, sunGlowS);
sun->SetColor(colSun.GetHWColor());
sun->RenderEx(sunX, sunY, 0.0f, sunS);
glow->SetColor(colMoonGlow.GetHWColor());
glow->RenderEx(moonX, moonY, 0.0f, moonGlowS);
moon->SetColor(colMoon.GetHWColor());
moon->RenderEx(moonX, moonY, 0.0f, moonS);
The same for sea reflection:
seaglow->SetColor(colSeaGlow.GetHWColor());
seaglow->RenderEx(seaGlowX, SKY_HEIGHT,
0.0f, seaGlowSX, seaGlowSY);
Note that sea reflection sprite is scaled non proportionally.
Performance
Despite visual complexity this tutorial runs at rather high FPS. This is
possible because when rendering sprites via Direct3D the bottleneck
is texture bandwidth. And this tutorial renders just several sprites from
one small texture. Large screen areas are filled with flat color.
The complete source code with detailed comments for this tutorial you may find in the folder
tutorials\tutorial08. The required media files you'll find in the folder tutorials\precompiled.
Use keys 1 to 9 to change simulation speed, 0 for real time and ESC to exit.
|