/*==========================================================================
*
* Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
*
* File: rm.cpp
*
***************************************************************************/
// Includes....
#include "rm.h"
#include "directx.h"
#include "mmsystem.h"
#include "stdio.h"
#include "control.h"
// Globals....
LPDIRECT3DRMFRAMEg_lpScene = NULL;// Scene frame
LPDIRECT3DRMFRAMEg_lpCamera = NULL;// Camera frame
LPDIRECT3DRMFRAMEg_lpArena = NULL;// Arena frame
LPDIRECT3DRMFRAMEg_lpBackground = NULL;// Background frame
LPDIRECT3DRMFRAMEg_lpPlayers = NULL;// Encapsulating frame
LPDIRECT3DRMFRAMEg_lpPlayer1 = NULL;// Human player
LPDIRECT3DRMFRAMEg_lpPlayer1HeadFrame = NULL;// Human player head frame
LPDIRECT3DRMANIMATIONSETg_lpPlayer1AnimSet = NULL;// Human player animation set
LPDIRECT3DRMFRAMEg_lpPlayer2 = NULL;// Computer player
LPDIRECT3DRMFRAMEg_lpPlayer2HeadFrame = NULL;// Computer player head frame
LPDIRECT3DRMANIMATIONSETg_lpPlayer2AnimSet = NULL;// Computer player animation set
LPDIRECT3DRMFRAMEg_lpTmp = NULL;// Temporary frame
LPDIRECT3DRMLIGHTg_lpDir;// Global light frame
LPDIRECT3DRMMESHBUILDERg_lpRedDebris = NULL;// Red debris model
LPDIRECT3DRMMESHBUILDERg_lpBlueDebris = NULL;// Blue debris model
Debrisg_debris[NUM_DEBRIS];// Debris
LPDIRECT3DRMANIMATIONg_lpAnim = NULL;// Intro anim
// Timing stuff
D3DVALUEg_timingDelta = D3DVAL(0.0f);
// Frame rate stuff
DWORDg_dwLastTime = 0;
DWORDg_dwCurTime = 0;
DWORDg_dwFpsTime = 0;
DWORDg_dwDeltaTime = 0;
DWORDg_dwFramesRendered = 0;
DWORDg_dwFps = 0;
// Externals....
extern BOOLg_bShowStats;// Defined in WINMAIN.CPP
extern BOOLg_bHardware3D;// Defined in DIRECTX.CPP
extern LPDIRECT3DRMg_lpD3DRM;// Defined in DIRECTX.CPP
extern LPDIRECT3DRMVIEWPORTg_lpD3DRMViewport;// Defined in DIRECTX.CPP
extern LPDIRECT3DRMDEVICEg_lpD3DRMDevice;// Defined in DIRECTX.CPP
extern LPDIRECTDRAWSURFACEg_lpPrimary;// Defined in DIRECTX.CPP
extern LPDIRECTDRAWSURFACEg_lpBackBuffer;// Defined in DIRECTX.CPP
extern LPDIRECTDRAWSURFACEg_lpZBuffer;// Defined in DIRECTX.CPP
extern DWORDg_vidModeX;// Defined in DIRECTX.CPP
extern DWORDg_vidModeY;// Defined in DIRECTX.CPP
extern DWORDg_vidModeBIT;// Defined in DIRECTX.CPP
extern DWORDg_dwFontHeight;// Defined in DIRECTX.CPP
extern DWORDg_dwAveCharWidth;// Defined in DIRECTX.CPP
extern DWORDg_player1health;// Defined in CONTROL.CPP
extern DWORDg_player2health;// Defined in CONTROL.CPP
extern DWORDg_lbar1;// Defined in DIRECTX.CPP
extern DWORDg_wbar1;// Defined in DIRECTX.CPP
extern DWORDg_lbar2;// Defined in DIRECTX.CPP
extern DWORDg_wbar2;// Defined in DIRECTX.CPP
extern DWORDg_hbar1;// Defined in DIRECTX.CPP
extern DWORDg_hbar2;// Defined in DIRECTX.CPP
extern AnimArgsg_player1AnimArgs;
extern AnimArgsg_player2AnimArgs;
//----------------------------------------------------------------------
//
// Function: InitScene
//
// Purpose: Initialises Direct3D RM objects and loads scene for demo
//
//----------------------------------------------------------------------
BOOL InitScene()
{
LPDIRECT3DRMLIGHTpAmb;
LPDIRECT3DRMFRAMEpLight;
LPDIRECT3DRMMESHBUILDER pMeshBuilder;
// Create the scene (parent) frame
TRY_D3DRM(g_lpD3DRM->CreateFrame(NULL, &g_lpScene))
// Create the camera (child of g_lpScene)
TRY_D3DRM(g_lpD3DRM->CreateFrame(g_lpScene, &g_lpCamera))
// Create the arena frame
TRY_D3DRM(g_lpD3DRM->CreateFrame(g_lpScene, &g_lpArena))
// Create the frame that encapsulates both players
TRY_D3DRM(g_lpD3DRM->CreateFrame(g_lpScene, &g_lpPlayers))
// Create player frames
TRY_D3DRM(g_lpD3DRM->CreateFrame(g_lpPlayers, &g_lpPlayer1))
TRY_D3DRM(g_lpD3DRM->CreateFrame(g_lpPlayers, &g_lpPlayer2))
// Create temporary frame
TRY_D3DRM(g_lpD3DRM->CreateFrame(g_lpScene, &g_lpTmp))
// Create lights and position in world
TRY_D3DRM(g_lpD3DRM->CreateLightRGB(D3DRMLIGHT_AMBIENT, D3DVAL(0.2), D3DVAL(0.2), D3DVAL(0.2), &pAmb))
TRY_D3DRM(g_lpD3DRM->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, D3DVAL(0.7), D3DVAL(0.7), D3DVAL(0.7), &g_lpDir))
// Create ambient light frame
TRY_D3DRM(g_lpD3DRM->CreateFrame(g_lpScene, &pLight))
// Add the light to the frame
TRY_D3DRM(pLight->AddLight(pAmb))
// Release the light frame
pLight->Release();
// Create directional light frame
TRY_D3DRM(g_lpD3DRM->CreateFrame(g_lpScene, &pLight))
// Set position and orientation of directional light
pLight->SetPosition(g_lpScene, D3DVAL(1000), D3DVAL(1000), D3DVAL(1000));
pLight->SetOrientation(g_lpScene, D3DVAL(-1.0), D3DVAL(-1.0), D3DVAL(1.0), D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0));
// Add the light to the frame
TRY_D3DRM(pLight->AddLight(g_lpDir))
// Enable lights only for any object that is a child of g_lpPlayers
TRY_D3DRM(g_lpDir->SetEnableFrame(g_lpPlayers))
// Release the light frame
pLight->Release();
// Create mesh builder for arena
TRY_D3DRM(g_lpD3DRM->CreateMeshBuilder(&pMeshBuilder))
// Load the arena
TRY_D3DRM(pMeshBuilder->Load("ARENA.X", NULL, D3DRMLOAD_FROMFILE, LoadTextures, NULL))
// Make sure we use perspective correct!
pMeshBuilder->SetPerspective(TRUE);
// Add the mesh to the scene
TRY_D3DRM(g_lpArena->AddVisual(pMeshBuilder))
g_lpArena->SetZbufferMode(D3DRMZBUFFER_DISABLE);
// Release the mesh builder
pMeshBuilder->Release();
// Load player 1's model
TRY_D3DRM(g_lpD3DRM->CreateAnimationSet(&g_lpPlayer1AnimSet))
// Load the model and animation
TRY_D3DRM(g_lpPlayer1AnimSet->Load("SKMECH.X", NULL, D3DRMLOAD_FROMFILE, LoadTextures, NULL, g_lpPlayer1))
// Add animation callback for player 1
g_player1AnimArgs.lpAnimSet = g_lpPlayer1AnimSet;
g_player1AnimArgs.time= D3DVAL(0);
TRY_D3DRM(g_lpPlayer1->AddMoveCallback(Player1AnimationCallback, NULL))
// Setup the initial position of player 1
g_lpPlayer1->SetPosition(g_lpScene, D3DVAL(0), D3DVAL(0), D3DVAL(-200));
// Load player 2's model
TRY_D3DRM(g_lpD3DRM->CreateAnimationSet(&g_lpPlayer2AnimSet))
// Load the model and animation
TRY_D3DRM(g_lpPlayer2AnimSet->Load("DEMECH.X", NULL, D3DRMLOAD_FROMFILE, LoadTextures, NULL, g_lpPlayer2))
// Add animation callback for player 2
g_player2AnimArgs.lpAnimSet = g_lpPlayer2AnimSet;
g_player2AnimArgs.time= D3DVAL(0);
TRY_D3DRM(g_lpPlayer2->AddMoveCallback(Player2AnimationCallback, NULL))
for (int i = 0; i < NUM_DEBRIS; i ++)
{
TRY_D3DRM(g_lpD3DRM->CreateFrame(g_lpPlayers, &g_debris[i].m_pFrame))
g_debris[i].m_bInUse = FALSE;
}
// Load the red debris
TRY_D3DRM(g_lpD3DRM->CreateMeshBuilder(&g_lpRedDebris))
TRY_D3DRM(g_lpRedDebris->Load("debris_r.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL))
// Load the blue debris
TRY_D3DRM(g_lpD3DRM->CreateMeshBuilder(&g_lpBlueDebris))
TRY_D3DRM(g_lpBlueDebris->Load("debris_b.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL))
// Setup the initial position of player 2
g_lpPlayer2->SetPosition(g_lpScene, D3DVAL(0), D3DVAL(0), D3DVAL(200));
// Create the intro path
TRY_D3DRM(g_lpD3DRM->CreateAnimation(&g_lpAnim))
// Setup the animation options
g_lpAnim->SetOptions(D3DRMANIMATION_OPEN |
D3DRMANIMATION_LINEARPOSITION |
D3DRMANIMATION_POSITION);
// Add the starting position (as a keyframe)
g_lpAnim->AddPositionKey(D3DVAL(0), D3DVAL(200), D3DVAL(2000), D3DVAL(0));
// Add the ending position (as a keyframe)
g_lpAnim->AddPositionKey(D3DVAL(1), D3DVAL(700), D3DVAL(100), D3DVAL(0));
// Make the camera follow this animation
g_lpAnim->SetFrame(g_lpCamera);
// Retrieve player 1 and player 2's head frames
LPDIRECT3DRMOBJECT tmp;
TRY_D3DRM(g_lpD3DRM->GetNamedObject("x3ds_Head", &tmp))
g_lpPlayer1HeadFrame = (LPDIRECT3DRMFRAME)tmp;
TRY_D3DRM(g_lpD3DRM->GetNamedObject("x3ds_xHead", &tmp))
g_lpPlayer2HeadFrame = (LPDIRECT3DRMFRAME)tmp;
// Yahoo!
return TRUE;
}
//----------------------------------------------------------------------
//
// Function: TermScene
//
// Purpose: Destroys scene
//
//----------------------------------------------------------------------
void TermScene()
{
// Destroy the scene frame
if (g_lpScene)
{
g_lpScene->Release();
g_lpScene = NULL;
}
// Destroy the animation sets
if (g_lpPlayer1AnimSet)
{
g_lpPlayer1AnimSet->Release();
g_lpPlayer1AnimSet = NULL;
}
if (g_lpPlayer2AnimSet)
{
g_lpPlayer2AnimSet->Release();
g_lpPlayer2AnimSet = NULL;
}
}
//----------------------------------------------------------------------
//
// Function: RenderScene
//
// Purpose: Renders scene
//
//----------------------------------------------------------------------
BOOL RenderScene()
{
static BOOL b = FALSE;
// Verify both surfaces
if (!g_lpPrimary) return FALSE;
if (!g_lpZBuffer) return FALSE;
// Perform some timing stuff
g_dwCurTime = timeGetTime();
g_dwDeltaTime = g_dwCurTime - g_dwLastTime;
g_dwLastTime = g_dwCurTime;
g_dwFpsTime += g_dwDeltaTime;
// Move the scene
g_lpScene->Move(D3DVAL(g_dwDeltaTime));
if (b) {
b = FALSE;
TRY_D3DRM(g_lpD3DRMViewport->ForceUpdate(0, 0, g_vidModeX, g_vidModeY))
}
// Restore the primary surface if it has been lost
if (g_lpPrimary->IsLost())
{
HRESULT rval = g_lpPrimary->Restore();
if (rval != DD_OK) return TRUE;
TRY_D3DRM(g_lpD3DRMViewport->ForceUpdate(0, 0, g_vidModeX, g_vidModeY))
b = TRUE;
}
// Restore the ZBuffer if it has been lost
if (g_lpZBuffer->IsLost())
{
HRESULT rval = g_lpZBuffer->Restore();
if (rval != DD_OK) return TRUE;
TRY_D3DRM(g_lpD3DRMViewport->ForceUpdate(0, 0, g_vidModeX, g_vidModeY))
}
// Clear the viewport ready for rendering
TRY_D3DRM(g_lpD3DRMViewport->Clear())
// Render the scene
TRY_D3DRM(g_lpD3DRMViewport->Render(g_lpScene))
g_dwFramesRendered ++;
// Show stats if necessary
if (g_bShowStats)
{
// String to hold stats
char sStats[256];
// If 2 seconds have elapsed, calculate the frame rate
if (g_dwFpsTime > 2000)
{
g_dwFps= g_dwFramesRendered / 2;
g_dwFramesRendered= 0;
g_dwFpsTime= 0;
}
// Copy info into stat string
sprintf(sStats, "SX:%d, SY:%d, SBD:%d FPS:%d, %s", g_vidModeX, g_vidModeY, g_vidModeBIT, g_dwFps, g_bHardware3D ? "(H)" : "(S)");
// Get a DC to the backbuffer (very useful!)
HDC hDC;
g_lpBackBuffer->GetDC(&hDC);
if (!hDC) return FALSE;
// Use TextOut to draw the text onto the surface
DWORD dwStringPixelWidth = strlen(sStats) * g_dwAveCharWidth;
SetBkMode( hDC, TRANSPARENT );
SetTextColor( hDC, RGB(255,255,255) );
TextOut(hDC, (g_vidModeX >> 1) - (dwStringPixelWidth >> 1), g_vidModeY - g_dwFontHeight, sStats, strlen(sStats));
// Must release DC before calling Flip()
g_lpBackBuffer->ReleaseDC(hDC);
}
// Draw the power bars
DDBLTFX ddBltFx;
memset(&ddBltFx, 0, sizeof(DDBLTFX));
ddBltFx.dwSize = sizeof(DDBLTFX);
RECT rcBar1 = { g_lbar1, g_hbar1, g_lbar1 + g_wbar1, g_hbar1 + g_hbar2 };
RECT rcBar2 = { g_lbar2, g_hbar1, g_lbar2 + g_wbar2, g_hbar1 + g_hbar2 };
switch (g_vidModeBIT)
{
case 8 : ddBltFx.dwFillColor = 253; break;
case 16 : ddBltFx.dwFillColor = 1 << 4; break;
case 24 : ddBltFx.dwFillColor = 1 << 7; break;
}
if (g_player1health > 0) {
TRY_DD(g_lpBackBuffer->Blt(&rcBar1, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx))
TRY_D3DRM(g_lpD3DRMViewport->ForceUpdate(rcBar1.left, rcBar1.top, rcBar1.right, rcBar1.bottom))
}
switch (g_vidModeBIT)
{
case 8 : ddBltFx.dwFillColor = 254; break;
case 16 : ddBltFx.dwFillColor = 1 << 5 << 5 << 4; break;
case 24 : ddBltFx.dwFillColor = 1 << 8 << 8 << 7; break;
}
if (g_player2health > 0) {
TRY_DD(g_lpBackBuffer->Blt(&rcBar2, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx))
TRY_D3DRM(g_lpD3DRMViewport->ForceUpdate(rcBar2.left, rcBar2.top, rcBar2.right, rcBar2.bottom))
}
// And update the device
TRY_D3DRM(g_lpD3DRMDevice->Update())
// Finally, flip the back buffer onto the primary surface, displaying
// the last rendered frame
TRY_DD(g_lpPrimary->Flip(NULL, DDFLIP_WAIT))
// Yahoo!
return TRUE;
}
//------------------------------------------------------------------
//
// Function: LoadTextures
//
// Purpose: Loads an individual texture
//
// NOTE: Textures must have a size divisible by 2 (e.g. 128x64, 256x256)
//
//------------------------------------------------------------------
HRESULT LoadTextures(char *sName, void *pArg, LPDIRECT3DRMTEXTURE *hTexture)
{
char *sTmpName = sName;
// Find the extension
while(sTmpName[0] != '.') sTmpName ++;
// Add .ppm to the picture file used by 3D Studio (.TGA, .GIF, .CEL etc)
strcpy(sTmpName, ".ppm");
// Load the texture
if (FAILED(g_lpD3DRM->LoadTexture(sName, hTexture))) return -1;
if (!strcmp(sName, "gdk_fill.ppm"))
{
(*hTexture)->SetShades(1);
}
return 0;
}