Tutorial 14: Terrain Mini-Maps

Mini-maps are small 2D maps in the user interface that help the user locate their current position on the terrain. Most commonly they will be the color map that is used for the terrain with additional markings for points of interest and such. Sometimes they are also artist created to give a different look to the map that fits with the rest of the user interface. I personally like to combine the color map with a light map to give it a 3D top down perspective.

For example I run the RAW viewing program that I wrote which takes the RAW height map and the color map as input. The program then produces the fully rendered map:

It also writes out the maps it produces in bitmap format so I can access them after running the program:

So I take the fully rendered bitmap and use Gimp to shrink it from 1025x1025 down to 150x150. I then put a 2 pixel white border around it creating a 154x154 mini-map with a 150x150 map section:

Finally I take that mini-map and use the BitmapClass to render it in 2D in my terrain's user interface. I also use a 3x3 green pixel which I put on top of the mini-map in accordance with the camera's position on the terrain. Each frame I update the mini-map with the new position of the camera to keep the green pixel updated on the mini-map. This way when I move around so does the green dot on the mini-map.

Framework

The frame work has been updated to include the MiniMapClass, the BitmapClass, and the TextureShaderClass.

The BitmapClass and the TextureShaderClass are the same as the OpenGL 4.0 tutorial series, so we won't cover those again. We will begin the code section by examining the MiniMapClass:


Minimapclass.h

The MiniMapClass contains two textures. One is for the mini-map itself, the other is for the green location marker. The class basically renders those two bitmaps to the screen in 2D and also keeps an update position of where the camera is on the terrain so that the green position indicator can be updated each frame.

////////////////////////////////////////////////////////////////////////////////
// Filename: minimapclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _MINIMAPCLASS_H_
#define _MINIMAPCLASS_H_


///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "bitmapclass.h"
#include "shadermanagerclass.h"


////////////////////////////////////////////////////////////////////////////////
// Class name: MiniMapClass
////////////////////////////////////////////////////////////////////////////////
class MiniMapClass
{
public:
    MiniMapClass();
    MiniMapClass(const MiniMapClass&);
    ~MiniMapClass();

    bool Initialize(OpenGLClass*, int, int, float, float);
    void Shutdown();
    bool Render(OpenGLClass*, ShaderManagerClass*, float*, float*, float*);

    void PositionUpdate(float, float);

private:
    int m_mapLocationX, m_mapLocationY, m_pointLocationX, m_pointLocationY;
    float m_mapSizeX, m_mapSizeY, m_terrainWidth, m_terrainHeight;
    BitmapClass *m_MiniMapBitmap, *m_PointBitmap;
};

#endif

Minimapclass.cpp

////////////////////////////////////////////////////////////////////////////////
// Filename: minimapclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "minimapclass.h"

The two bitmaps are initialized to null in the class constructor.

MiniMapClass::MiniMapClass()
{
    m_MiniMapBitmap = 0;
    m_PointBitmap = 0;
}


MiniMapClass::MiniMapClass(const MiniMapClass& other)
{
}


MiniMapClass::~MiniMapClass()
{
}


bool MiniMapClass::Initialize(OpenGLClass* OpenGL, int screenWidth, int screenHeight, float terrainWidth, float terrainHeight)
{
    bool result;

The Initialize function starts by storing the location of the mini-map, its size, and the actual size of the terrain mesh.

    // Set the size of the mini-map  minus the borders.
    m_mapSizeX = 150.0f;
    m_mapSizeY = 150.0f;

    // Initialize the location of the mini-map on the screen.
    m_mapLocationX = screenWidth - (int)m_mapSizeX - 10;
    m_mapLocationY = 10;

    // Store the terrain size.
    m_terrainWidth = terrainWidth;
    m_terrainHeight = terrainHeight;

Next we create the mini-map from the minimap.tga file. Even though the rendered map is 1025x1025 we have shrunk it down to 154x154 so that displaying it does not take up too much of the screen.

    // Create and initialize the mini-map bitmap object.
    m_MiniMapBitmap = new BitmapClass;

    result = m_MiniMapBitmap->Initialize(OpenGL, screenWidth, screenHeight, "../Engine/data/minimap/minimap.tga", m_mapLocationX, m_mapLocationY);
    if(!result)
    {
        return false;
    }

And finally we load the point indicator. It is a 3x3 green pixel that we will use and constantly update to show where the user currently is located on the mini-map.

    // Create and initialize the point bitmap object.
    m_PointBitmap = new BitmapClass;

    result = m_PointBitmap->Initialize(OpenGL, screenWidth, screenHeight, "../Engine/data/minimap/point.tga", 0, 0);
    if(!result)
    {
        return false;
    }

    return true;
}

The Shutdown function releases the two bitmap objects that were used for rendering the mini-map elements.

void MiniMapClass::Shutdown()
{
    // Release the point bitmap object.
    if(m_PointBitmap)
    {
        m_PointBitmap->Shutdown();
        delete m_PointBitmap;
        m_PointBitmap = 0;
    }

    // Release the mini-map bitmap object.
    if(m_MiniMapBitmap)
    {
        m_MiniMapBitmap->Shutdown();
        delete m_MiniMapBitmap;
        m_MiniMapBitmap = 0;
    }

    return;
}


bool MiniMapClass::Render(OpenGLClass* OpenGL, ShaderManagerClass* ShaderManager, float* worldMatrix, float* viewMatrix, float* orthoMatrix)
{
    bool result;

Before rendering we first update the position of the green marker on the mini-map based on the frame updated position.

    // Update the position of the point on the mini-map.
    m_PointBitmap->SetRenderLocation(m_pointLocationX, m_pointLocationY);

Since this is 2D rendering we need to disable the Z buffer.

    // Disable the Z buffer to perform 2D rendering.
    OpenGL->TurnZBufferOff();

First we render the mini-map bitmap.

    // Render the mini-map bitmap using the texture shader.
    result = ShaderManager->RenderTextureShader(worldMatrix, viewMatrix, orthoMatrix);
    if(!result)
    {
        return false;
    }

    m_MiniMapBitmap->SetTexture(0);
    m_MiniMapBitmap->Render();

And then the point indicator is rendered on the mini-map according to where the user is currently located on the 3D terrain mesh.

    // Render the point bitmap using the texture shader.
    result = ShaderManager->RenderTextureShader(worldMatrix, viewMatrix, orthoMatrix);
    if(!result)
    {
        return false;
    }

    m_PointBitmap->SetTexture(0);
    m_PointBitmap->Render();

Disable 2D rendering once this is complete.

    // Enable the Z buffer to return to 3D rendering.
    OpenGL->TurnZBufferOn();

    return true;
}

The PositionUpdate function is used for updating where the 3x3 green pixel point indicator should be located on the mini-map. It converts the 3D float position of the camera on the terrain into a 2D position on the bitmap. It also makes sure the indicator never goes past the borders of the mini-map.

void MiniMapClass::PositionUpdate(float positionX, float positionZ)
{
    float percentX, percentY;


    // Ensure the point does not leave the minimap borders even if the camera goes past the terrain borders.
    if(positionX < 0)
    {
        positionX = 0;
    }

    if(positionZ < 0)
    {
        positionZ = 0;
    }

    if(positionX > m_terrainWidth)
    {
        positionX = m_terrainWidth;
    }

    if(positionZ > m_terrainHeight)
    {
        positionZ = m_terrainHeight;
    }

    // Calculate the position of the camera on the minimap in terms of percentage.
    percentX = positionX / m_terrainWidth;
    percentY = 1.0f - (positionZ / m_terrainHeight);

    // Determine the pixel location of the point on the mini-map.
    m_pointLocationX = (m_mapLocationX + 2) + (int)(percentX * m_mapSizeX);
    m_pointLocationY = (m_mapLocationY + 2) + (int)(percentY * m_mapSizeY);

    // Subtract one from the location to center the point on the mini-map according to the 3x3 point pixel image size.
    m_pointLocationX = m_pointLocationX - 1;
    m_pointLocationY = m_pointLocationY - 1;

    return;
}

Shadermanagerclass.h

The TextureShaderClass has been added to the ShaderManagerClass to perform 2D rendering of the mini-map.

////////////////////////////////////////////////////////////////////////////////
// Filename: shadermanagerclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _SHADERMANAGERCLASS_H_
#define _SHADERMANAGERCLASS_H_


///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "colorshaderclass.h"
#include "textureshaderclass.h"
#include "fontshaderclass.h"
#include "terrainshaderclass.h"
#include "skydomeshaderclass.h"
#include "skyplaneshaderclass.h"


////////////////////////////////////////////////////////////////////////////////
// Class name: ShaderManagerClass
////////////////////////////////////////////////////////////////////////////////
class ShaderManagerClass
{
public:
    ShaderManagerClass();
    ShaderManagerClass(const ShaderManagerClass&);
    ~ShaderManagerClass();

    bool Initialize(OpenGLClass*);
    void Shutdown();

    bool RenderColorShader(float*, float*, float*);
    bool RenderTextureShader(float*, float*, float*);
    bool RenderFontShader(float*, float*, float*, float*);
    bool RenderTerrainShader(float*, float*, float*, float*, float*);
    bool RenderSkyDomeShader(float*, float*, float*, float*, float*);
    bool RenderSkyPlaneShader(float*, float*, float*, float, float, float);

private:
    ColorShaderClass* m_ColorShader;
    TextureShaderClass* m_TextureShader;
    FontShaderClass* m_FontShader;
    TerrainShaderClass* m_TerrainShader;
    SkyDomeShaderClass* m_SkyDomeShader;
    SkyPlaneShaderClass* m_SkyPlaneShader;
};

#endif

Shadermanagerclass.cpp

////////////////////////////////////////////////////////////////////////////////
// Filename: shadermanagerclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "shadermanagerclass.h"


ShaderManagerClass::ShaderManagerClass()
{
    m_ColorShader = 0;
    m_TextureShader = 0;
    m_FontShader = 0;
    m_TerrainShader = 0;
    m_SkyDomeShader = 0;
    m_SkyPlaneShader = 0;
}


ShaderManagerClass::ShaderManagerClass(const ShaderManagerClass& other)
{
}


ShaderManagerClass::~ShaderManagerClass()
{
}


bool ShaderManagerClass::Initialize(OpenGLClass* OpenGL)
{
    bool result;


    // Create and initialize the texture shader object.
    m_ColorShader = new ColorShaderClass;

    result = m_ColorShader->Initialize(OpenGL);
    if(!result)
    {
        return false;
    }

    // Create and initialize the texture shader object.
    m_TextureShader = new TextureShaderClass;

    result = m_TextureShader->Initialize(OpenGL);
    if(!result)
    {
        return false;
    }

    // Create and initialize the font shader object.
    m_FontShader = new FontShaderClass;

    result = m_FontShader->Initialize(OpenGL);
    if(!result)
    {
        return false;
    }

    // Create and initialize the terrain shader object.
    m_TerrainShader = new TerrainShaderClass;

    result = m_TerrainShader->Initialize(OpenGL);
    if(!result)
    {
        return false;
    }

    // Create and initialize the sky dome shader object.
    m_SkyDomeShader = new SkyDomeShaderClass;

    result = m_SkyDomeShader->Initialize(OpenGL);
    if(!result)
    {
        return false;
    }

    // Create and initialize the sky plane shader object.
    m_SkyPlaneShader = new SkyPlaneShaderClass;

    result = m_SkyPlaneShader->Initialize(OpenGL);
    if(!result)
    {
        return false;
    }

    return true;
}


void ShaderManagerClass::Shutdown()
{
    // Release the sky plane shader object.
    if(m_SkyPlaneShader)
    {
        m_SkyPlaneShader->Shutdown();
        delete m_SkyPlaneShader;
        m_SkyPlaneShader = 0;
    }

    // Release the sky dome shader object.
    if(m_SkyDomeShader)
    {
        m_SkyDomeShader->Shutdown();
        delete m_SkyDomeShader;
        m_SkyDomeShader = 0;
    }

    // Release the terrain shader object.
    if(m_TerrainShader)
    {
        m_TerrainShader->Shutdown();
        delete m_TerrainShader;
        m_TerrainShader = 0;
    }

    // Release the font shader object.
    if(m_FontShader)
    {
        m_FontShader->Shutdown();
        delete m_FontShader;
        m_FontShader = 0;
    }

    // Release the texture shader object.
    if(m_TextureShader)
    {
        m_TextureShader->Shutdown();
        delete m_TextureShader;
        m_TextureShader = 0;
    }

    // Release the color shader object.
    if(m_ColorShader)
    {
        m_ColorShader->Shutdown();
        delete m_ColorShader;
        m_ColorShader = 0;
    }

    return;
}


bool ShaderManagerClass::RenderColorShader(float* worldMatrix, float* viewMatrix, float* projectionMatrix)
{
    return m_ColorShader->SetShaderParameters(worldMatrix, viewMatrix, projectionMatrix);
}


bool ShaderManagerClass::RenderTextureShader(float* worldMatrix, float* viewMatrix, float* projectionMatrix)
{
    return m_TextureShader->SetShaderParameters(worldMatrix, viewMatrix, projectionMatrix);
}


bool ShaderManagerClass::RenderFontShader(float* worldMatrix, float* viewMatrix, float* projectionMatrix, float* pixelColor)
{
    return m_FontShader->SetShaderParameters(worldMatrix, viewMatrix, projectionMatrix, pixelColor);
}


bool ShaderManagerClass::RenderTerrainShader(float* worldMatrix, float* viewMatrix, float* projectionMatrix, float* lightDirection, float* diffuseLightColor)
{
    return m_TerrainShader->SetShaderParameters(worldMatrix, viewMatrix, projectionMatrix, lightDirection, diffuseLightColor);
}


bool ShaderManagerClass::RenderSkyDomeShader(float* worldMatrix, float* viewMatrix, float* projectionMatrix, float* apexColor, float* centerColor)
{
    return m_SkyDomeShader->SetShaderParameters(worldMatrix, viewMatrix, projectionMatrix, apexColor, centerColor);
}


bool ShaderManagerClass::RenderSkyPlaneShader(float* worldMatrix, float* viewMatrix, float* projectionMatrix, float translationX, float translationZ, float scale)
{
    return m_SkyPlaneShader->SetShaderParameters(worldMatrix, viewMatrix, projectionMatrix, translationX, translationZ, scale);
}

Zoneclass.h

The MiniMapClass has been added to the ZoneClass.

///////////////////////////////////////////////////////////////////////////////
// Filename: zoneclass.h
///////////////////////////////////////////////////////////////////////////////
#ifndef _ZONECLASS_H_
#define _ZONECLASS_H_


///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "openglclass.h"
#include "inputclass.h"
#include "userinterfaceclass.h"
#include "cameraclass.h"
#include "positionclass.h"
#include "terrainclass.h"
#include "skydomeclass.h"
#include "skyplaneclass.h"
#include "minimapclass.h"


////////////////////////////////////////////////////////////////////////////////
// Class name: ZoneClass
////////////////////////////////////////////////////////////////////////////////
class ZoneClass
{
public:
    ZoneClass();
    ZoneClass(const ZoneClass&);
    ~ZoneClass();

    bool Initialize(OpenGLClass*, int, int);
    void Shutdown(OpenGLClass*);
    bool Frame(OpenGLClass*, ShaderManagerClass*, FontClass*, UserInterfaceClass*, InputClass*, float);

private:
    bool Render(OpenGLClass*, ShaderManagerClass*, FontClass*, UserInterfaceClass*);
    void HandleMovementInput(InputClass*, float);
    bool RenderSkyDome(OpenGLClass*, ShaderManagerClass*, float*, float*);
    bool RenderSkyPlane(OpenGLClass*, ShaderManagerClass*, float*, float*);

private:
    CameraClass* m_Camera;
    PositionClass* m_Position;
    TerrainClass* m_Terrain;
    LightClass* m_Light;
    FrustumClass* m_Frustum;
    SkyDomeClass* m_SkyDome;
    SkyPlaneClass* m_SkyPlane;
    MiniMapClass* m_MiniMap;
};

#endif

Zoneclass.cpp

////////////////////////////////////////////////////////////////////////////////
// Filename: zoneclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "zoneclass.h"


ZoneClass::ZoneClass()
{
    m_Camera = 0;
    m_Position = 0;
    m_Terrain = 0;
    m_Light = 0;
    m_Frustum = 0;
    m_SkyDome = 0;
    m_SkyPlane = 0;
    m_MiniMap = 0;
}


ZoneClass::ZoneClass(const ZoneClass& other)
{
}


ZoneClass::~ZoneClass()
{
}


bool ZoneClass::Initialize(OpenGLClass* OpenGL, int screenWidth, int screenHeight)
{
    char configFilename[256];
    bool result;


    // Create and initialize the camera object.
    m_Camera = new CameraClass;

    m_Camera->SetPosition(0.0f, 0.0f, -10.0f);
    m_Camera->Render();
    m_Camera->RenderBaseViewMatrix();

    // Create and initialize the position object.
    m_Position = new PositionClass;

    m_Position->SetPosition(500.0f, 50.0f, 10.0f);
    m_Position->SetRotation(0.0f, 0.0f, 0.0f);

    // Create and initialize the terrain object.
    m_Terrain = new TerrainClass;

    strcpy(configFilename, "../Engine/data/setup.txt");

    result = m_Terrain->Initialize(OpenGL, configFilename);
    if(!result)
    {
        cout << "Error: Could not initialize the terrain object." << endl;
        return false;
    }

    // Create and initialize the light object.
    m_Light = new LightClass;

    m_Light->SetDiffuseColor(1.0f, 1.0f, 1.0f, 1.0f);
    m_Light->SetDirection(-0.5f, -1.0f, -0.5f);

    // Create the frustum object.
    m_Frustum = new FrustumClass;

    // Create and initialize the sky dome object.
    m_SkyDome = new SkyDomeClass;

    result = m_SkyDome->Initialize(OpenGL);
    if(!result)
    {
        cout << "Error: Could not initialize the sky dome object." << endl;
        return false;
    }

    // Create and initialize the sky plane object.
    m_SkyPlane = new SkyPlaneClass;

    result = m_SkyPlane->Initialize(OpenGL);
    if(!result)
    {
        cout << "Error: Could not initialize the sky plane object." << endl;
        return false;
    }

We setup the mini-map object here.

    // Create and initialize the mini-map object.
    m_MiniMap = new MiniMapClass;

    result = m_MiniMap->Initialize(OpenGL, screenWidth, screenHeight, 1025, 1025);
    if(!m_MiniMap)
    {
        return false;
    }

    return true;
}


void ZoneClass::Shutdown(OpenGLClass* OpenGL)
{

The mini-map is released in the Shutdown function.

    // Release the mini-map object.
    if(m_MiniMap)
    {
        m_MiniMap->Shutdown();
        delete m_MiniMap;
        m_MiniMap = 0;
    }

    // Release the sky plane object.
    if(m_SkyPlane)
    {
        m_SkyPlane->Shutdown(OpenGL);
        delete m_SkyPlane;
        m_SkyPlane = 0;
    }

    // Release the sky dome object.
    if(m_SkyDome)
    {
        m_SkyDome->Shutdown(OpenGL);
        delete m_SkyDome;
        m_SkyDome = 0;
    }

    // Release the frustum object.
    if(m_Frustum)
    {
        delete m_Frustum;
        m_Frustum = 0;
    }

    // Release the light object.
    if(m_Light)
    {
        delete m_Light;
        m_Light = 0;
    }

    // Release the terrain object.
    if(m_Terrain)
    {
        m_Terrain->Shutdown(OpenGL);
        delete m_Terrain;
        m_Terrain = 0;
    }

    // Release the position object.
    if(m_Position)
    {
        delete m_Position;
        m_Position = 0;
    }

    // Release the camera object.
    if(m_Camera)
    {
        delete m_Camera;
        m_Camera = 0;
    }

    return;
}


bool ZoneClass::Frame(OpenGLClass* OpenGL, ShaderManagerClass* ShaderManager, FontClass* Font, UserInterfaceClass* UserInterface, InputClass* Input, float frameTime)
{
    float posX, posY, posZ, rotX, rotY, rotZ, height;
    bool result, foundHeight, heightLocked;


    // Set whether we lock to the terrain height or not.
    heightLocked = true;

    // Do the sky plane frame processing.
    m_SkyPlane->Frame(frameTime);

    // Do the frame input processing for the movement.
    HandleMovementInput(Input, frameTime);

    // Get the view point position/rotation.
    m_Position->GetPosition(posX, posY, posZ);
    m_Position->GetRotation(rotX, rotY, rotZ);

    // Get the height of the triangle that is directly underneath the given camera position.
    foundHeight =  m_Terrain->GetHeightAtPosition(posX, posZ, height);
    if(foundHeight)
    {
        // If there was a triangle under the camera then position the camera just above it by two units.
        if(heightLocked)
        {
            posY = height + 2.0f;
        }
    }

    // Set the position of the camera and update the camera view matrix for rendering.
    m_Camera->SetPosition(posX, posY, posZ);
    m_Camera->SetRotation(rotX, rotY, rotZ);
    m_Camera->Render();

    // Update the UI with the position.
    UserInterface->UpdatePositonStrings(Font, posX, posY, posZ, rotX, rotY, rotZ);

Each frame we update the X and Z position in the 2D mini-map to reflect where the camera has moved to on the 3D terrain.

    // Update the mini-map position indicator.
    m_MiniMap->PositionUpdate(posX, posZ);

    // Render the zone.
    result = Render(OpenGL, ShaderManager, Font, UserInterface);
    if(!result)
    {
        return false;
    }

    return true;
}


bool ZoneClass::Render(OpenGLClass* OpenGL, ShaderManagerClass* ShaderManager, FontClass* Font, UserInterfaceClass* UserInterface)
{
    float worldMatrix[16], viewMatrix[16], projectionMatrix[16], baseViewMatrix[16], orthoMatrix[16];
    int nodesDrawn, nodesCulled;
    bool result, renderMiniMap;

We add a variable for quickly turning on/off the mini-map.

    // Set whether we render the mini-map or not.
    renderMiniMap = true;

    // Get the world, view, and ortho matrices from the opengl and camera objects.
    OpenGL->GetWorldMatrix(worldMatrix);
    m_Camera->GetViewMatrix(viewMatrix);
    OpenGL->GetProjectionMatrix(projectionMatrix);
    m_Camera->GetBaseViewMatrix(baseViewMatrix);
    OpenGL->GetOrthoMatrix(orthoMatrix);

    // Construct the frustum.
    m_Frustum->ConstructFrustum(OpenGL, viewMatrix, projectionMatrix);

    // Clear the scene.
    OpenGL->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);

    // Render the sky dome.
    result = RenderSkyDome(OpenGL, ShaderManager, viewMatrix, projectionMatrix);
    if(!result)
    {
        return false;
    }

    // Render the sky plane.
    result = RenderSkyPlane(OpenGL, ShaderManager, viewMatrix, projectionMatrix);
    if(!result)
    {
        return false;
    }

    // Render the terrain using the terrain shader.
    result = m_Terrain->Render(OpenGL, ShaderManager, m_Light, m_Frustum, worldMatrix, viewMatrix, projectionMatrix);
    if(!result)
    {
        return false;
    }

The mini-map rendering is called here. We use the baseViewMatrix and orthoMatrix to perform 2D rendering.

    // Render the terrain mini-map.
    if(renderMiniMap)
    {
        result = m_MiniMap->Render(OpenGL, ShaderManager, worldMatrix, baseViewMatrix, orthoMatrix);
        if(!result)
        {
            return false;
        }
    }

    // Update with nodes drawn/culled.
    m_Terrain->GetNodesDrawn(nodesDrawn, nodesCulled);

    result = UserInterface->UpdateNodeStrings(Font, nodesDrawn, nodesCulled);
    if(!result)
    {
        return false;
    }

    // Render the user interface.
    result = UserInterface->Render(OpenGL, ShaderManager, Font, worldMatrix, baseViewMatrix, orthoMatrix);
    if(!result)
    {
        return false;
    }

    // Present the rendered scene to the screen.
    OpenGL->EndScene();

    return true;
}


void ZoneClass::HandleMovementInput(InputClass* Input, float frameTime)
{
    bool keyDown;


    // Set the frame time for calculating the updated position.
    m_Position->SetFrameTime(frameTime);

    // Check if the input keys have been pressed.  If so, then update the position accordingly.
    keyDown = Input->IsLeftPressed();
    m_Position->TurnLeft(keyDown);

    keyDown = Input->IsRightPressed();
    m_Position->TurnRight(keyDown);

    keyDown = Input->IsUpPressed();
    m_Position->MoveForward(keyDown);

    keyDown = Input->IsDownPressed();
    m_Position->MoveBackward(keyDown);

    keyDown = Input->IsAPressed();
    m_Position->MoveUpward(keyDown);

    keyDown = Input->IsZPressed();
    m_Position->MoveDownward(keyDown);

    keyDown = Input->IsPgUpPressed();
    m_Position->LookUpward(keyDown);

    keyDown = Input->IsPgDownPressed();
    m_Position->LookDownward(keyDown);

    keyDown = Input->IsQPressed();
    m_Position->StrafeLeft(keyDown);

    keyDown = Input->IsEPressed();
    m_Position->StrafeRight(keyDown);

    return;
}


bool ZoneClass::RenderSkyDome(OpenGLClass* OpenGL, ShaderManagerClass* ShaderManager, float* viewMatrix, float* projectionMatrix)
{
    float translateMatrix[16];
    float apexColor[4], centerColor[4];
    float cameraPosition[3];
    bool result;


    // Get the sky dome colors.
    m_SkyDome->GetApexColor(apexColor);
    m_SkyDome->GetCenterColor(centerColor);

    // Get the position of the camera.
    m_Camera->GetPosition(cameraPosition);

    // Translate the sky dome to be centered around the camera position.
    OpenGL->MatrixTranslation(translateMatrix, cameraPosition[0], cameraPosition[1], cameraPosition[2]);

    // Turn off back face culling and turn off the Z buffer.
    OpenGL->TurnOffCulling();
    OpenGL->TurnZBufferOff();

    // Render the sky dome using the sky dome shader.
    result = ShaderManager->RenderSkyDomeShader(translateMatrix, viewMatrix, projectionMatrix, apexColor, centerColor);
    if(!result)
    {
        return false;
    }

    m_SkyDome->Render(OpenGL);

    // Turn back face culling back on and turn the Z buffer back on.
    OpenGL->TurnOnCulling();
    OpenGL->TurnZBufferOn();

    return true;
}


bool ZoneClass::RenderSkyPlane(OpenGLClass* OpenGL, ShaderManagerClass* ShaderManager, float* viewMatrix, float* projectionMatrix)
{
    float translateMatrix[16];
    float cameraPosition[3];
    float translationX, translationZ, scale;
    bool result;


    // Get the position of the camera.
    m_Camera->GetPosition(cameraPosition);

    // Translate the sky dome to be centered around the camera position.
    OpenGL->MatrixTranslation(translateMatrix, cameraPosition[0], cameraPosition[1], cameraPosition[2]);

    translationX = m_SkyPlane->GetTranslation(0);
    translationZ = m_SkyPlane->GetTranslation(1);
    scale = m_SkyPlane->GetScale();

    // Turn Z buffer off and enable additive blending so the clouds blend with the sky dome color.
    OpenGL->TurnZBufferOff();
    OpenGL->EnableUIAlphaBlending();

    // Render the sky plane using the sky plane shader.
    result = ShaderManager->RenderSkyPlaneShader(translateMatrix, viewMatrix, projectionMatrix, translationX, translationZ, scale);
    if(!result)
    {
        return false;
    }

    m_SkyPlane->SetCloudTexture(OpenGL, 0);
    m_SkyPlane->SetPerturbTexture(OpenGL, 1);
    m_SkyPlane->SetFadeTexture(OpenGL, 2);

    m_SkyPlane->Render(OpenGL);

    // Turn Z buffer back on and disable blending.
    OpenGL->TurnZBufferOn();
    OpenGL->DisableAlphaBlending();

    return true;
}

Summary

We now have a mini-map implemented with a green pixel indicator which reflects the user's current position on the 3D terrain.


To Do Exercises

1. Recompile the code and run the program. Move around the terrain and you will notice the green pixel shows your current location on the mini-map.

2. Move the mini-map 2D rendering to a different location on the screen.

3. Create your own mini-map and indicator.

4. Write a section of code to move the camera on the terrain to wherever you clicked on the 2D mini-map using the mouse input.

5. Add a fog of war effect where the map becomes uncovered in a small circular radius as the point moves around the map.

6. Add a random moving object on the terrain that updates the mini-map with a red point.

7. Think about how to implement a 3D mini-map for your own project.


Source Code

Source Code and Data Files: gl4terlinux14.tar.gz

Back to Tutorial Index