⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 testterrain.cpp

📁 《3D游戏引擎设计》的源码
💻 CPP
字号:
// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// FREE SOURCE CODE
// http://www.magic-software.com/License.html/free.pdf

#include "TestTerrain.h"

//---------------------------------------------------------------------------
MgcApplication* MgcApplication::Create ()
{
    return new TestTerrain;
}
//---------------------------------------------------------------------------
TestTerrain::TestTerrain ()
    :
    MgcApplication("TestTerrain",640,480,0,2)
{
    // initialize 'last time'
    MeasureTime();

    m_fHeightAboveTerrain = 2.0;
    m_fTrnSpeed = 0.5;
    m_fRotSpeed = 0.05;
    m_bUArrowPressed = false;
    m_bDArrowPressed = false;
    m_bLArrowPressed = false;
    m_bRArrowPressed = false;
    m_bPgUpPressed = false;
    m_bPgDnPressed = false;
}
//---------------------------------------------------------------------------
void TestTerrain::CreateTerrain ()
{
    // Load Windows BMP.  It is known that the image is 256-by-256.  This
    // fact is 'hard-coded' into this block of code.
    HBITMAP hImage = (HBITMAP) LoadImage(NULL,"terrain.bmp",IMAGE_BITMAP,0,0,
        LR_LOADFROMFILE | LR_CREATEDIBSECTION);

    DIBSECTION dibSection;
    GetObject(hImage,sizeof(DIBSECTION),&dibSection);

    int iWidth = dibSection.dsBm.bmWidth;
    int iHeight = dibSection.dsBm.bmHeight;
    int iQuantity = dibSection.dsBm.bmWidth*dibSection.dsBm.bmHeight;
    assert( iWidth == 256 && iHeight == 256 );
    assert( dibSection.dsBm.bmBitsPixel == 24 );

    // Windows BMP stores BGR, need to invert to RGB.
    unsigned char* acSrc = (unsigned char*) dibSection.dsBm.bmBits;
    unsigned char* acDst = new unsigned char[3*iQuantity];
    int i, i0, i1, i2;
    for (i = 0, i0 = 0, i1 = 1, i2 = 2; i < iQuantity; i++)
    {
        acDst[i0] = acSrc[i2];
        acDst[i1] = acSrc[i1];
        acDst[i2] = acSrc[i0];
        i0 += 3;
        i1 += 3;
        i2 += 3;
    }
    DeleteObject(hImage);

    // Image is grey scale.  Use one of the channels to generate heights.
    unsigned short usSize = 129;
    unsigned short* ausHeight = new unsigned short[usSize*usSize];
    memset(ausHeight,0,usSize*usSize*sizeof(unsigned short));
    for (unsigned short usY = 0; usY < 128; usY++)
    {
        for (unsigned short usX = 0; usX < 128; usX++)
        {
            unsigned short usHIndex = usX + usSize*usY;
            unsigned int uiDIndex = 6*(usX + iWidth*usY);
            ausHeight[usHIndex] = 3*((unsigned short)acDst[uiDIndex]);
        }
    }

    MgcVector2 kOrigin = MgcVector2::ZERO;
    MgcReal fMinElevation = 0.0;
    MgcReal fMaxElevation = 255.0;
    MgcReal fSpacing = 1.0;

    // create the terrain
    m_spkPage = new MgcTerrainPage(usSize,ausHeight,kOrigin,fMinElevation,
        fMaxElevation,fSpacing);
    m_spkScene->AttachChild(m_spkPage);

    // color remap
    MgcReal fFrac;
    for (i = 0, i0 = 0, i1 = 1, i2 = 2; i < iQuantity; i++)
    {
        if ( acDst[i0] < 8 )
        {
            // blue
            fFrac = acDst[i0]/7.0;
            acDst[i0] = 0;
            acDst[i1] = 0;
            acDst[i2] = 192 + (255-192)*fFrac;
        }
        else if ( acDst[i0] < 72 )
        {
            // yellow
            fFrac = (acDst[i0] - 8.0)/64.0;
            acDst[i0] = 128 + (255-128)*fFrac;
            acDst[i1] = acDst[i0];
            acDst[i2] = 0;
        }
        else if ( acDst[i0] < 128 )
        {
            // green
            fFrac = (acDst[i0] - 72.0)/56.0;
            acDst[i0] = 0;
            acDst[i1] = 128+(255-128)*fFrac;
            acDst[i2] = 0;
        }
        else if ( acDst[i0] < 192 )
        {
            // brown
            fFrac = (acDst[i0] - 128.0)/64.0;
            acDst[i0] = 64+(128-64)*fFrac;
            acDst[i1] = acDst[i0];
            acDst[i2] = 32;
        }
        else
        {
            // grey
            fFrac = (acDst[i0] - 192.0)/64.0;
            acDst[i0] = 192+(255-192)*fFrac;
            acDst[i1] = acDst[i0];
            acDst[i2] = acDst[i0];
        }

        i0 += 3;
        i1 += 3;
        i2 += 3;
    }

    // create the terrain texture
    MgcImage* pkImage = new MgcImage(MgcImage::IT_RGB888,iWidth,iHeight,acDst);
    MgcTexture* pkTexture = new MgcTexture;
    pkTexture->SetImage(pkImage);
    pkTexture->Filter() = MgcTexture::FM_LINEAR;
    pkTexture->Mipmap() = MgcTexture::MM_LINEAR_LINEAR;
    MgcTextureState* pkTextureState = new MgcTextureState;
    pkTextureState->Set(0,pkTexture);
    m_spkScene->SetRenderState(pkTextureState);
}
//---------------------------------------------------------------------------
bool TestTerrain::Initialize ()
{
    // create camera and renderer
    m_spkCamera = new MgcOglCamera(640,480);
    m_spkCamera->SetFrustum(1.0,1000.0,-0.55,0.55,0.4125,-0.4125);
    m_spkRenderer = new MgcOglRenderer(GetWindowHandle(),640,480);
    m_spkRenderer->SetBackgroundColor(MgcColor(0.5f,0.0f,1.0f));
    m_spkRenderer->SetCamera(m_spkCamera);

    // create root of scene graph
    MgcStream kStream;
    m_spkScene = new MgcNode(1);
    m_spkWireframeState = new MgcWireframeState;
    m_spkScene->SetRenderState(m_spkWireframeState);
    m_spkZBufferState = new MgcZBufferState;
    m_spkZBufferState->Enabled() = true;
    m_spkZBufferState->Writeable() = true;
    m_spkZBufferState->Compare() = MgcZBufferState::CF_LEQUAL;
    m_spkScene->SetRenderState(m_spkZBufferState);

    // create terrain heights and textures
    CreateTerrain();

    // position the camera in the middle of the page
    MgcReal fHeight = m_spkPage->GetHeight(MgcVector2(64.0,64.0));
    MgcVector3 kCLoc(64.0,64.0,fHeight + m_fHeightAboveTerrain);
    MgcVector3 kCLeft(0.0,-1.0,0.0);
    MgcVector3 kCUp(0.0,0.0,1.0);
    MgcVector3 kCDir(-1.0,0,0.0);
    m_spkCamera->SetFrame(kCLoc,kCLeft,kCUp,kCDir);
    m_spkCamera->Update();

    Simplify();
    m_spkScene->UpdateGS(0.0);
    m_spkScene->UpdateRS();
    return true;
}
//---------------------------------------------------------------------------
void TestTerrain::Terminate ()
{
    m_spkPage = 0;
    m_spkWireframeState = 0;
    m_spkZBufferState = 0;
    m_spkRenderer = 0;
    m_spkScene = 0;
}
//---------------------------------------------------------------------------
void TestTerrain::OnIdle ()
{
    MeasureTime();

    if ( m_bUArrowPressed )
        MoveForward();
    else if ( m_bDArrowPressed )
        MoveBackward();

    if ( m_bLArrowPressed )
        TurnLeft();
    else if ( m_bRArrowPressed )
        TurnRight();

    if ( m_bPgUpPressed )
        LookUp();
    else if ( m_bPgDnPressed )
        LookDown();

    m_spkRenderer->ClearBuffers();
    m_spkRenderer->Draw(m_spkScene);
    m_spkRenderer->DisplayBackBuffer();

    DrawFrameRate();
    DisplayStatistics();
    UpdateClicks();
}
//---------------------------------------------------------------------------
bool TestTerrain::WmChar (char cCharCode, long lKeyData)
{
    switch ( cCharCode )
    {
    case '0':  // reset frame rate measurements
        ResetTime();
        return true;
    case 'w':
        m_spkWireframeState->Enabled() = !m_spkWireframeState->Enabled();
        return true;
    case 's':
        Simplify();
        return true;
    case '+':
    case '=':
        m_spkPage->SetPixelTolerance(m_spkRenderer,
            m_spkPage->GetPixelTolerance() + 1.0);
        Simplify();
        return true;
    case '-':
    case '_':
        if ( m_spkPage->GetPixelTolerance() > 1.0 )
        {
            m_spkPage->SetPixelTolerance(m_spkRenderer,
                m_spkPage->GetPixelTolerance() - 1.0);
            Simplify();
        }
        return true;
    case 'q':
    case 'Q':
    case VK_ESCAPE:
        PostMessage(GetWindowHandle(),WM_DESTROY,0,0);
        return true;
    }

    return false;
}
//---------------------------------------------------------------------------
bool TestTerrain::WmKeyDown (int iVirtKey, long lKeyData)
{
    MgcVector3 kLoc;
    MgcReal fHeight;

    switch ( iVirtKey )
    {
    case VK_UP:
        m_bUArrowPressed = true;
        break;
    case VK_DOWN:
        m_bDArrowPressed = true;
        break;
    case VK_LEFT:
        m_bLArrowPressed = true;
        break;
    case VK_RIGHT:
        m_bRArrowPressed = true;
        break;
    case VK_PRIOR:
        m_bPgUpPressed = true;
        break;
    case VK_NEXT:
        m_bPgDnPressed = true;
        break;
    case 'U':
        m_fHeightAboveTerrain += 1.0;

        kLoc = m_spkCamera->GetLocation();
        fHeight = m_spkPage->GetHeight(MgcVector2(kLoc.x,kLoc.y));
        kLoc.z = fHeight + m_fHeightAboveTerrain;
        m_spkCamera->SetLocation(kLoc);
        m_spkCamera->Update();
        Simplify();
        break;
    case 'D':
        if ( m_fHeightAboveTerrain >= 1.0 )
            m_fHeightAboveTerrain -= 1.0;

        kLoc = m_spkCamera->GetLocation();
        fHeight = m_spkPage->GetHeight(MgcVector2(kLoc.x,kLoc.y));
        kLoc.z = fHeight + m_fHeightAboveTerrain;
        m_spkCamera->SetLocation(kLoc);
        m_spkCamera->Update();
        Simplify();
        break;
    default:
        return false;
    }

    return true;
}
//---------------------------------------------------------------------------
bool TestTerrain::WmKeyUp (int iVirtKey, long lKeyData)
{
    switch ( iVirtKey )
    {
    case VK_UP:
        m_bUArrowPressed = false;
        break;
    case VK_DOWN:
        m_bDArrowPressed = false;
        break;
    case VK_LEFT:
        m_bLArrowPressed = false;
        break;
    case VK_RIGHT:
        m_bRArrowPressed = false;
        break;
    case VK_PRIOR:
        m_bPgUpPressed = false;
        break;
    case VK_NEXT:
        m_bPgDnPressed = false;
        break;
    default:
        return false;
    }

    return true;
}
//---------------------------------------------------------------------------
void TestTerrain::MoveForward ()
{
    MgcVector3 kLoc = m_spkCamera->GetLocation();
    MgcReal fHeight = m_spkPage->GetHeight(MgcVector2(kLoc.x,kLoc.y));
    kLoc += m_fTrnSpeed*m_spkCamera->GetDirection();
    kLoc.z = fHeight + m_fHeightAboveTerrain;
    m_spkCamera->SetLocation(kLoc);
    m_spkCamera->Update();

    Simplify();
}
//---------------------------------------------------------------------------
void TestTerrain::MoveBackward ()
{
    MgcVector3 kLoc = m_spkCamera->GetLocation();
    MgcReal fHeight = m_spkPage->GetHeight(MgcVector2(kLoc.x,kLoc.y));
    kLoc -= m_fTrnSpeed*m_spkCamera->GetDirection();
    kLoc.z = fHeight + m_fHeightAboveTerrain;
    m_spkCamera->SetLocation(kLoc);
    m_spkCamera->Update();

    Simplify();
}
//---------------------------------------------------------------------------
void TestTerrain::TurnLeft ()
{
    MgcMatrix3 kIncr;

    kIncr.FromAxisAngle(m_spkCamera->GetUp(),m_fRotSpeed);
    MgcVector3 kLeft = kIncr*m_spkCamera->GetLeft();
    MgcVector3 kDirection = kIncr*m_spkCamera->GetDirection();
    m_spkCamera->SetAxes(kLeft,m_spkCamera->GetUp(),kDirection);
    m_spkCamera->Update();

    Simplify();
}
//---------------------------------------------------------------------------
void TestTerrain::TurnRight ()
{
    MgcMatrix3 kIncr;

    kIncr.FromAxisAngle(m_spkCamera->GetUp(),-m_fRotSpeed);
    MgcVector3 kLeft = kIncr*m_spkCamera->GetLeft();
    MgcVector3 kDirection = kIncr*m_spkCamera->GetDirection();
    m_spkCamera->SetAxes(kLeft,m_spkCamera->GetUp(),kDirection);
    m_spkCamera->Update();

    Simplify();
}
//---------------------------------------------------------------------------
void TestTerrain::LookUp ()
{
    MgcMatrix3 kIncr;

    kIncr.FromAxisAngle(m_spkCamera->GetLeft(),-m_fRotSpeed);
    MgcVector3 kUp = kIncr*m_spkCamera->GetUp();
    MgcVector3 kDirection = kIncr*m_spkCamera->GetDirection();
    m_spkCamera->SetAxes(m_spkCamera->GetLeft(),kUp,kDirection);
    m_spkCamera->Update();

    Simplify();
}
//---------------------------------------------------------------------------
void TestTerrain::LookDown ()
{
    MgcMatrix3 kIncr;

    kIncr.FromAxisAngle(m_spkCamera->GetLeft(),m_fRotSpeed);
    MgcVector3 kUp = kIncr*m_spkCamera->GetUp();
    MgcVector3 kDirection = kIncr*m_spkCamera->GetDirection();
    m_spkCamera->SetAxes(m_spkCamera->GetLeft(),kUp,kDirection);
    m_spkCamera->Update();

    Simplify();
}
//---------------------------------------------------------------------------
void TestTerrain::Simplify ()
{
    // initialize the page
    m_spkPage->ResetBlocks();

    // camera location in terrain model space
    const MgcVector3& rkWorldEye = m_spkCamera->GetLocation();
    MgcVector3 kDiff = rkWorldEye - m_spkPage->WorldTranslate();
    MgcReal fInvScale = 1.0/m_spkPage->WorldScale();
    MgcVector3 kModelEye = fInvScale*(kDiff*m_spkPage->WorldRotate());

    // camera direction in terrain model space
    const MgcVector3& rkWorldDir = m_spkCamera->GetDirection();
    MgcVector3 kModelDir = rkWorldDir*m_spkPage->WorldRotate();

    bool bCloseAssumption = false;
    m_spkPage->Simplify(m_spkRenderer,kModelEye,kModelDir,bCloseAssumption);
}
//---------------------------------------------------------------------------
void TestTerrain::DisplayStatistics ()
{
    char acMsg[256];
    sprintf(acMsg,"vertices = %u  triangles = %u",
        m_spkPage->GetVertexQuantity(),m_spkPage->GetTriangleQuantity());
    unsigned int uiPane = 1;
    HWND hStatusWnd = GetStatusWindowHandle();
    SendMessage(hStatusWnd,SB_SETTEXT,(WPARAM)uiPane,(LPARAM)acMsg);
    SendMessage(hStatusWnd,WM_PAINT,0,0); 
}
//---------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -