422 lines
13 KiB
C++
422 lines
13 KiB
C++
/*****************************************************************************\
|
|
FILE: CameraMove.cpp
|
|
|
|
DESCRIPTION:
|
|
The caller can create this object to tell it to move from point a to
|
|
point b from time t1 to time t2.
|
|
|
|
BryanSt 12/24/2000
|
|
|
|
Copyright (C) Microsoft Corp 2000-2001. All rights reserved.
|
|
\*****************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include <d3d8.h>
|
|
#include <d3dx8.h>
|
|
#include <d3dsaver.h>
|
|
#include <d3d8rgbrast.h>
|
|
#include <dxutil.h>
|
|
|
|
#include <shlobj.h>
|
|
#include "CameraMove.h"
|
|
|
|
|
|
enum eCameraMoveType
|
|
{
|
|
cameraMoveLocation = 0,
|
|
cameraRotate,
|
|
cameraWait,
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
eCameraMoveType type;
|
|
D3DXVECTOR3 vSourceLoc; // For cameraMoveLocation and cameraRotate
|
|
D3DXVECTOR3 vSourceTangent; // For cameraMoveLocation and cameraRotate
|
|
D3DXVECTOR3 vDestLoc; // For cameraMoveLocation
|
|
D3DXVECTOR3 vDestTangent; // For cameraMoveLocation and cameraRotate
|
|
float fTime; // For cameraMoveLocation cameraRotate, and cameraWait
|
|
int nMinFrames;
|
|
int nMaxFrames;
|
|
int nBatch;
|
|
int nPreFetch;
|
|
} CAMERA_MOVEMENT;
|
|
|
|
|
|
CCameraMove::CCameraMove()
|
|
{
|
|
m_hdpaMovements = DPA_Create(4);
|
|
m_fTimeInPreviousMovements = NULL;
|
|
m_vLookAtLast = m_vUpVec = m_vLocLast = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
|
|
m_nCurrent = 0;
|
|
m_fTimeInPreviousMovements = 0.0f;
|
|
m_nFramesFromCurrent = 1;
|
|
|
|
m_fTimeToLookAtPainting = 1.0f;
|
|
DWORD dwSpeedSlider = DEFAULT_SPEEDSLIDER;
|
|
if (g_pConfig)
|
|
{
|
|
m_fTimeToLookAtPainting = (float) g_pConfig->GetDWORDSetting(CONFIG_DWORD_VIEWPAINTINGTIME);
|
|
dwSpeedSlider = g_pConfig->GetDWORDSetting(CONFIG_DWORD_SPEED_SLIDER);
|
|
}
|
|
|
|
m_fTimeToRotate = s_SpeedSettings[dwSpeedSlider].fTimeToRotate;
|
|
m_nMinTurnFrames = s_SpeedSettings[dwSpeedSlider].nMinTurnFrames;
|
|
m_nMaxTurnFrames = s_SpeedSettings[dwSpeedSlider].nMaxTurnFrames;
|
|
|
|
m_fTimeToWalk = s_SpeedSettings[dwSpeedSlider].fTimeToWalk;
|
|
m_nMinWalkFrames = s_SpeedSettings[dwSpeedSlider].nMinWalkFrames;
|
|
m_nMaxWalkFrames = s_SpeedSettings[dwSpeedSlider].nMaxWalkFrames;
|
|
}
|
|
|
|
|
|
CCameraMove::~CCameraMove()
|
|
{
|
|
DeleteAllMovements(0.0f);
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT CCameraMove::Init(D3DXVECTOR3 vStartLoc, D3DXVECTOR3 vStartTangent, D3DXVECTOR3 vUpVec)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Initialize member variables
|
|
m_vUpVec = vUpVec;
|
|
m_vLocLast = vStartLoc;
|
|
m_vLookAtLast = vStartTangent;
|
|
|
|
m_nFramesFromCurrent = 0;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CCameraMove::CreateNextMove(D3DXVECTOR3 vSourceLoc, D3DXVECTOR3 vSourceTangent, D3DXVECTOR3 vDestLoc, D3DXVECTOR3 vDestTangent)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
if (m_hdpaMovements)
|
|
{
|
|
CAMERA_MOVEMENT * pNew = (CAMERA_MOVEMENT *) LocalAlloc(LPTR, sizeof(*pNew));
|
|
|
|
if (pNew)
|
|
{
|
|
D3DXVECTOR3 vDelta = (vSourceLoc - vDestLoc);
|
|
float fLen = D3DXVec3Length(&vDelta); // How far are we traveling
|
|
float fRatio = (fLen / 50.0f); // The speed values are stored per 50.0f distance
|
|
|
|
pNew->type = cameraMoveLocation;
|
|
pNew->vSourceLoc = vSourceLoc;
|
|
pNew->vSourceTangent = vSourceTangent;
|
|
pNew->vDestLoc = vDestLoc;
|
|
pNew->vDestTangent = vDestTangent;
|
|
pNew->fTime = (m_fTimeToWalk * fRatio);
|
|
pNew->nMinFrames = (int) max((m_nMinWalkFrames * fRatio), 1);
|
|
pNew->nMaxFrames = (int) max((m_nMaxWalkFrames * fRatio), 1);
|
|
pNew->nBatch = 0;
|
|
pNew->nPreFetch = 0;
|
|
|
|
if (-1 != DPA_AppendPtr(m_hdpaMovements, pNew))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pNew);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CCameraMove::CreateNextRotate(D3DXVECTOR3 vSourceLoc, D3DXVECTOR3 vSourceTangent, D3DXVECTOR3 vDestTangent)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
if (m_hdpaMovements)
|
|
{
|
|
CAMERA_MOVEMENT * pNew = (CAMERA_MOVEMENT *) LocalAlloc(LPTR, sizeof(*pNew));
|
|
|
|
if (pNew)
|
|
{
|
|
float fDotProduct = D3DXVec3Dot(&vSourceTangent, &vDestTangent);
|
|
float fRatio;
|
|
|
|
if (fDotProduct)
|
|
{
|
|
float fRads = (float)acos(fDotProduct / max(1, (D3DXVec3Length(&vSourceTangent) * D3DXVec3Length(&vDestTangent)))); // How far are we traveling
|
|
fRatio = (D3DXToDegree(fRads) / 90.0f); // The speed values are stored per 90.0f distance
|
|
}
|
|
else
|
|
{
|
|
// Assume a dot product of 0 means 90 degrees.
|
|
fRatio = 1.0f; // The speed values are stored per 90.0f distance
|
|
}
|
|
|
|
pNew->type = cameraRotate;
|
|
pNew->vSourceLoc = vSourceLoc;
|
|
pNew->vSourceTangent = vSourceTangent;
|
|
pNew->vDestLoc = vSourceLoc;
|
|
pNew->vDestTangent = vDestTangent;
|
|
pNew->fTime = (m_fTimeToRotate * fRatio);
|
|
pNew->nMinFrames = (int) max((m_nMinTurnFrames * fRatio), 1);
|
|
pNew->nMaxFrames = (int) max((m_nMaxTurnFrames * fRatio), 1);
|
|
pNew->nBatch = 0;
|
|
pNew->nPreFetch = 0;
|
|
|
|
if (-1 != DPA_AppendPtr(m_hdpaMovements, pNew))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pNew);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CCameraMove::CreateNextWait(int nBatch, int nPreFetch, float fTime)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
if (-1.0f == fTime)
|
|
{
|
|
fTime = m_fTimeToLookAtPainting;
|
|
}
|
|
|
|
if (m_hdpaMovements)
|
|
{
|
|
CAMERA_MOVEMENT * pNew = (CAMERA_MOVEMENT *) LocalAlloc(LPTR, sizeof(*pNew));
|
|
|
|
if (pNew)
|
|
{
|
|
pNew->type = cameraWait;
|
|
pNew->vSourceLoc = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
|
|
pNew->vSourceTangent = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
|
|
pNew->vDestLoc = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
|
|
pNew->vDestTangent = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
|
|
pNew->fTime = fTime;
|
|
pNew->nMinFrames = 1;
|
|
pNew->nMaxFrames = 1000000;
|
|
pNew->nBatch = nBatch;
|
|
pNew->nPreFetch = nPreFetch;
|
|
|
|
if (-1 != DPA_AppendPtr(m_hdpaMovements, pNew))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pNew);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CCameraMove::SetCamera(IDirect3DDevice8 * pD3DDevice, FLOAT fTimeKeyIn)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pD3DDevice && m_hdpaMovements)
|
|
{
|
|
float fTimeInSegment = 0.0f;
|
|
CAMERA_MOVEMENT * pCurrent = NULL;
|
|
|
|
if (0 > m_nCurrent)
|
|
{
|
|
m_nCurrent = 0;
|
|
}
|
|
|
|
if (m_nCurrent >= DPA_GetPtrCount(m_hdpaMovements))
|
|
{
|
|
hr = S_FALSE; // This means we left the room.
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
pCurrent = (CAMERA_MOVEMENT *) DPA_GetPtr(m_hdpaMovements, m_nCurrent);
|
|
|
|
if (!pCurrent)
|
|
{
|
|
// ASSERT(FAILED(hr));
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
float fTimePerFrameMin = (pCurrent->fTime / pCurrent->nMinFrames);
|
|
|
|
fTimeInSegment = (fTimeKeyIn - m_fTimeInPreviousMovements);
|
|
|
|
if (fTimeInSegment < 0)
|
|
{
|
|
fTimeInSegment = 0;
|
|
}
|
|
|
|
// Do we need to warp time in order to have enough frames for the motion so we don't
|
|
// jump?
|
|
if ((fTimeInSegment > (fTimePerFrameMin * m_nFramesFromCurrent)) &&
|
|
(m_nFramesFromCurrent <= pCurrent->nMinFrames))
|
|
{
|
|
// Yes.
|
|
float fTimeWarp = (fTimeInSegment - (fTimePerFrameMin * m_nFramesFromCurrent));
|
|
|
|
m_fTimeInPreviousMovements += fTimeWarp;
|
|
fTimeInSegment = (fTimeKeyIn - m_fTimeInPreviousMovements);
|
|
}
|
|
|
|
if (fTimeInSegment > pCurrent->fTime)
|
|
{
|
|
m_fTimeInPreviousMovements += pCurrent->fTime;
|
|
|
|
if (cameraRotate == pCurrent->type)
|
|
{
|
|
m_vLocLast = pCurrent->vSourceLoc;
|
|
m_vLookAtLast = pCurrent->vDestTangent;
|
|
}
|
|
else if (cameraMoveLocation == pCurrent->type)
|
|
{
|
|
m_vLocLast = pCurrent->vDestLoc;
|
|
m_vLookAtLast = pCurrent->vDestTangent;
|
|
}
|
|
|
|
m_nFramesFromCurrent = 0;
|
|
m_nCurrent++;
|
|
}
|
|
else
|
|
{
|
|
m_nFramesFromCurrent++;
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (1);
|
|
}
|
|
|
|
if (S_OK == hr) // S_FALSE means we left the room, so do nothing.
|
|
{
|
|
D3DXVECTOR3 vEye = m_vLocLast;
|
|
D3DXVECTOR3 vLookAt = (m_vLocLast + m_vLookAtLast);
|
|
float fTimeRatio = (fTimeInSegment / pCurrent->fTime);
|
|
float fTimeRemainingInSeg = 0.0f;
|
|
|
|
switch (pCurrent->type)
|
|
{
|
|
case cameraMoveLocation:
|
|
D3DXVec3Lerp(&vEye, &pCurrent->vSourceLoc, &pCurrent->vDestLoc, fTimeRatio);
|
|
D3DXVec3Lerp(&vLookAt, &pCurrent->vSourceTangent, &pCurrent->vDestTangent, fTimeRatio);
|
|
|
|
vLookAt += vEye;
|
|
break;
|
|
case cameraRotate:
|
|
// TODO: Use D3DXVec3Lerp() instead.
|
|
D3DXVec3Lerp(&vLookAt, &pCurrent->vSourceTangent, &pCurrent->vDestTangent, fTimeRatio);
|
|
vLookAt += vEye;
|
|
// vLookAt = (vEye + (pCurrent->vSourceTangent + (fTimeRatio * (pCurrent->vDestTangent - pCurrent->vSourceTangent))));
|
|
// How do we rotate? Quaternion.
|
|
break;
|
|
case cameraWait:
|
|
if (m_nFramesFromCurrent > 1)
|
|
{
|
|
if ((2 == m_nFramesFromCurrent) && g_pPictureMgr)
|
|
{
|
|
DWORD dwMaxPixelSize = ((3 * g_dwHeight) / 4);
|
|
|
|
// Let's take the hit now of converting an image into a texture object since we don't have
|
|
// any work to do while looking at this painting. This can normally take 1.5 seconds, so
|
|
// it's big perf hit to do it any other time.
|
|
hr = g_pPictureMgr->PreFetch(pCurrent->nBatch, pCurrent->nPreFetch);
|
|
}
|
|
else
|
|
{
|
|
// We don't have any work remaining to do, so sleep so the computer can get some work
|
|
// done. (Like in background services or let it do any paging that we may have caused)
|
|
fTimeRemainingInSeg = (pCurrent->fTime - fTimeInSegment);
|
|
int nSleepTime = 1000 * (int) fTimeRemainingInSeg;
|
|
|
|
Sleep(nSleepTime);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
// Do nothing.
|
|
break;
|
|
};
|
|
|
|
|
|
D3DXMATRIX matView;
|
|
D3DXMATRIX matIdentity;
|
|
|
|
D3DXMatrixIdentity(&matIdentity);
|
|
if (g_fOverheadViewTest)
|
|
{
|
|
static float s_fHeight = 600.0f;
|
|
D3DXVECTOR3 vDelta = (vEye - vLookAt);
|
|
|
|
vEye += D3DXVECTOR3(0.0f, s_fHeight, 0.0f);
|
|
vEye += (4 * vDelta);
|
|
D3DXMatrixLookAtLH(&matView, &vEye, &vLookAt, &m_vUpVec);
|
|
}
|
|
else
|
|
{
|
|
D3DXMatrixLookAtLH(&matView, &vEye, &vLookAt, &m_vUpVec);
|
|
}
|
|
|
|
// PrintLocation(TEXT("Camera angle at: %s and looking at: %s"), vEye, vLookAt);
|
|
hr = pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
|
|
|
|
m_vEyePrev = vEye;
|
|
m_vLookAtPrev = vLookAt;
|
|
}
|
|
else
|
|
{
|
|
D3DXMATRIX matView;
|
|
|
|
D3DXMatrixLookAtLH(&matView, &m_vEyePrev, &m_vLookAtPrev, &m_vUpVec);
|
|
// PrintLocation(TEXT("xxxxxx Camera angle at: %s and looking at: %s"), m_vEyePrev, m_vLookAtPrev);
|
|
pD3DDevice->SetTransform(D3DTS_VIEW, &matView);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DXUtil_Trace(TEXT("ERROR: pD3DDevice or m_hdpaMovements is NULL"));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT CCameraMove::DeleteAllMovements(float fCurrentTime)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_hdpaMovements)
|
|
{
|
|
DPA_DestroyCallback(m_hdpaMovements, DPALocalFree_Callback, NULL);
|
|
m_hdpaMovements = DPA_Create(4);
|
|
}
|
|
|
|
m_fTimeInPreviousMovements = fCurrentTime;
|
|
m_nCurrent = 0;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|