This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Tools/W3DView/GraphicView.cpp

1792 lines
47 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// GraphicView.cpp : implementation file
//
#include "stdafx.h"
#include "w3dview.h"
#include "graphicview.h"
#include "ww3d.h"
#include "globals.h"
#include "w3dviewdoc.h"
#include <process.h>
#include "quat.h"
#include "mainfrm.h"
#include "utils.h"
#include "mmsystem.h"
#include "light.h"
#include "viewerassetmgr.h"
#include "rcfile.h"
#include "part_emt.h"
#include "part_buf.h"
#include "hlod.h"
#include "viewerscene.h"
#include "screencursor.h"
#include "mesh.h"
#include "coltest.h"
#include "mpu.h"
#include "dazzle.h"
#include "soundscene.h"
#include "wwaudio.h"
#include "metalmap.h"
#include "dx8wrapper.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////
// Local Prototypes
/////////////////////////////////////////////////////////////////////////
void CALLBACK fnTimerCallback (UINT, UINT, DWORD, DWORD, DWORD);
IMPLEMENT_DYNCREATE(CGraphicView, CView)
////////////////////////////////////////////////////////////////////////////
//
// CGraphicView
//
////////////////////////////////////////////////////////////////////////////
CGraphicView::CGraphicView (void)
: m_bInitialized (FALSE),
m_pCamera (NULL),
m_TimerID (0),
m_bMouseDown (FALSE),
m_bRMouseDown (FALSE),
m_bActive (TRUE),
m_animationSpeed (1.0F),
m_dwLastFrameUpdate (0),
m_iWindowed (1),
m_animationState (AnimInvalid),
m_objectRotation (NoRotation),
m_LightRotation (NoRotation),
m_bLightMeshInScene (false),
m_pLightMesh (NULL),
m_ParticleCountUpdate (0),
m_CameraBonePosX (false),
m_UpdateCounter (0),
m_allowedCameraRotation (FreeRotation),
m_ObjectCenter (0.0f, 0.0f, 0.0f)
{
// Get the windowed mode from the registry
CString string_windowed = theApp.GetProfileString ("Config", "Windowed", "1");
m_iWindowed = ::atoi ((LPCTSTR)string_windowed);
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// ~CGraphicView
//
////////////////////////////////////////////////////////////////////////////
CGraphicView::~CGraphicView ()
{
return ;
}
BEGIN_MESSAGE_MAP(CGraphicView, CView)
//{{AFX_MSG_MAP(CGraphicView)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_DESTROY()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_RBUTTONUP()
ON_WM_RBUTTONDOWN()
ON_WM_GETMINMAXINFO()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
////////////////////////////////////////////////////////////////////////////
//
// OnDraw
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnDraw (CDC* pDC)
{
// Get the document to display
CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
// Are we in a valid state?
if (!pDC->IsPrinting ())
{
}
return ;
}
#ifdef _DEBUG
void CGraphicView::AssertValid() const
{
CView::AssertValid();
}
void CGraphicView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
#endif //_DEBUG
////////////////////////////////////////////////////////////////////////////
//
// PreCreateWindow
//
////////////////////////////////////////////////////////////////////////////
int
CGraphicView::OnCreate (LPCREATESTRUCT lpCreateStruct)
{
// Allow the base class to process this message
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
m_dwLastFrameUpdate = timeGetTime ();//::GetTickCount ();
return 0;
}
////////////////////////////////////////////////////////////////////////////
//
// InitializeGraphicView
//
////////////////////////////////////////////////////////////////////////////
BOOL
CGraphicView::InitializeGraphicView (void)
{
// Assume failure
BOOL bReturn = FALSE;
if (g_iDeviceIndex < 0) {
return FALSE;
}
m_bInitialized = FALSE;
// Initialize the rendering engine with the information from
// this window.
RECT rect;
GetClientRect (&rect);
int cx = rect.right-rect.left;
int cy = rect.bottom-rect.top;
if (m_iWindowed == 0) {
cx = g_iWidth;
cy = g_iHeight;
((CW3DViewDoc *)GetDocument())->Show_Cursor (true);
} else {
((CW3DViewDoc *)GetDocument())->Show_Cursor (false);
}
bReturn = (WW3D::Set_Render_Device (g_iDeviceIndex,
cx,
cy,
g_iBitsPerPixel,
m_iWindowed) == WW3D_ERROR_OK);
ASSERT (bReturn);
if (bReturn && (m_pCamera == NULL))
{
// Instantiate a new camera class
m_pCamera = new CameraClass ();
bReturn = (m_pCamera != NULL);
// Were we successful in creating a camera?
ASSERT (m_pCamera);
if (m_pCamera)
{
// Create a transformation matrix
Matrix3D transform (1);
transform.Translate (Vector3 (0.0F, 0.0F, 35.0F));
// Point the camera in this direction (I think)
m_pCamera->Set_Transform (transform);
}
//
// Attach the 'listener' to the camera
//
WWAudioClass::Get_Instance ()->Get_Sound_Scene ()->Attach_Listener_To_Obj (m_pCamera);
}
Reset_FOV ();
if (m_pLightMesh == NULL)
{
ResourceFileClass light_mesh_file (NULL, "Light.w3d");
WW3DAssetManager::Get_Instance()->Load_3D_Assets (light_mesh_file);
m_pLightMesh = WW3DAssetManager::Get_Instance()->Create_Render_Obj ("LIGHT");
ASSERT (m_pLightMesh != NULL);
m_bLightMeshInScene = false;
}
// Remember whether or not we are initialized
m_bInitialized = bReturn;
if (m_bInitialized && (m_TimerID == 0))
{
// Kick off a timer that we can use to update
// the display (kinda like a game loop iterator)
TIMECAPS caps = { 0 };
::timeGetDevCaps (&caps, sizeof (TIMECAPS));
UINT freq = max (caps.wPeriodMin, 16U);
m_TimerID = (UINT)::timeSetEvent (freq,
freq,
fnTimerCallback,
(DWORD)m_hWnd,
TIME_PERIODIC);
}
// Return the TRUE/FALSE result code
return bReturn;
}
////////////////////////////////////////////////////////////////////////////
//
// OnSize
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnSize
(
UINT nType,
int cx,
int cy
)
{
// Allow the base class to process this message
CView::OnSize (nType, cx, cy);
if (m_bInitialized) {
if (m_iWindowed == 0) {
cx = g_iWidth;
cy = g_iHeight;
}
// Change the resolution of the rendering device to
// match that of the view's current dimensions
if (m_iWindowed == 1) {
WW3D::Set_Device_Resolution (cx, cy, g_iBitsPerPixel, m_iWindowed);
}
// Force a repaint of the screen
Reset_FOV ();
RepaintView ();
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnDestroy
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnDestroy (void)
{
// Allow the base class to process this message
CView::OnDestroy ();
//
// Remove the listener from the camera
//
WWAudioClass::Get_Instance ()->Get_Sound_Scene ()->Attach_Listener_To_Obj (NULL);
//
// Free the camera object
//
MEMBER_RELEASE (m_pCamera);
MEMBER_RELEASE (m_pLightMesh);
// Is there an update thread running?
if (m_TimerID == 0) {
// Stop the timer
::timeKillEvent ((UINT)m_TimerID);
m_TimerID = 0;
}
// Cache this information in the registry
TCHAR temp_string[10];
::itoa (m_iWindowed, temp_string, 10);
theApp.WriteProfileString ("Config", "Windowed", temp_string);
// We are no longer initialized
m_bInitialized = FALSE;
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnInitialUpdate
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnInitialUpdate (void)
{
// Allow the base class to process this message
CView::OnInitialUpdate ();
CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
if (doc)
{
// Ask the document to initialize the scene (if it hasn't
// already done so)
doc->InitScene ();
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Set_Lowest_LOD
//
////////////////////////////////////////////////////////////////////////////
void
Set_Lowest_LOD (RenderObjClass *render_obj)
{
if (render_obj != NULL) {
for (int index = 0; index < render_obj->Get_Num_Sub_Objects (); index ++) {
RenderObjClass *psub_obj = render_obj->Get_Sub_Object (index);
if (psub_obj != NULL) {
Set_Lowest_LOD (psub_obj);
}
MEMBER_RELEASE (psub_obj);
}
//
// Switcht this LOD to its lowest level
//
if (render_obj->Class_ID () == RenderObjClass::CLASSID_HLOD) {
((HLodClass *)render_obj)->Set_LOD_Level (0);
}
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Allow_Update
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Allow_Update (bool onoff)
{
if (onoff) {
m_UpdateCounter --;
} else {
m_UpdateCounter ++;
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// RepaintView
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::RepaintView
(
BOOL bUpdateAnimation,
DWORD ticks_to_use
)
{
//
// Simple check to avoid re-entrance
//
static bool _already_painting = false;
if (_already_painting) return;
_already_painting = true;
//
// Are we in a valid state?
//
CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
if (doc->Is_Initialized () && doc->GetScene () && m_UpdateCounter == 0) {
// Only update the frame if the animation is
// supposed to be playing
int cur_ticks = timeGetTime();
int ticks_elapsed = cur_ticks - m_dwLastFrameUpdate;
m_dwLastFrameUpdate = cur_ticks;
// Update the W3D frame times according to our elapsed tick count
if (ticks_to_use == 0) {
WW3D::Sync (WW3D::Get_Sync_Time() + (ticks_elapsed * m_animationSpeed));
} else {
WW3D::Sync (WW3D::Get_Sync_Time() + ticks_to_use);
}
// Do we need to update the current animation?
if ((m_animationState == AnimPlaying) &&
bUpdateAnimation)
{
float animationSpeed = ((float)ticks_elapsed) / 1000.00F;
animationSpeed = (animationSpeed * m_animationSpeed);
doc->UpdateFrame (animationSpeed);
}
// Perform the object rotation if necessary
if ((m_objectRotation != NoRotation) &&
(bUpdateAnimation == TRUE))
{
Rotate_Object ();
}
// Perform the light rotation if necessary
if ((m_LightRotation != NoRotation) &&
(bUpdateAnimation == TRUE))
{
Rotate_Light ();
}
// Reset the current lod to be the lowest possible LOD...
RenderObjClass *prender_obj = doc->GetDisplayedObject ();
if ((prender_obj != NULL) &&
(doc->GetScene ()->Are_LODs_Switching ()))
{
Set_Lowest_LOD (prender_obj);
}
// Update the metal map
// assuming object is at origin
MetalMapManagerClass *metal=_TheAssetMgr->Peek_Metal_Map_Manager();
if (metal)
{
LightClass *pscene_light = doc->GetSceneLight();
Vector3 ambient,diffuse,l,v;
ambient=doc->GetScene()->Get_Ambient_Light();
pscene_light->Get_Diffuse(&diffuse);
l=pscene_light->Get_Position();
l.Normalize();
v=m_pCamera->Get_Position();
v.Normalize();
metal->Update_Lighting(ambient,diffuse,l,v);
metal->Update_Textures();
}
//
// Render the background BMP
//
WW3D::Begin_Render (TRUE, TRUE, doc->GetBackgroundColor ());
WW3D::Render (doc->Get2DScene (), doc->Get2DCamera (), FALSE, FALSE);
//
// Render the background scene
//
if (doc->GetBackgroundObjectName ().GetLength () > 0) {
WW3D::Render (doc->GetBackObjectScene (), doc->GetBackObjectCamera (), FALSE, FALSE);
}
//
// Render the main scene
//
DWORD pt_high = 0L;
// Wait for all previous rendering to complete before starting benchmark.
DWORD profile_time = ::Get_CPU_Clock (pt_high);
WW3D::Render (doc->GetScene (), m_pCamera, FALSE, FALSE);
// Wait for all rendering to complete before stopping benchmark.
DWORD milliseconds = (::Get_CPU_Clock (pt_high) - profile_time) / 1000;
//
// Render the cursor
//
WW3D::Render (doc->GetCursorScene (), doc->Get2DCamera (), FALSE, FALSE);
// Render the dazzles
doc->Render_Dazzles(m_pCamera);
// Finish out the rendering process
WW3D::End_Render ();
//
// Let the audio class think
//
WWAudioClass::Get_Instance ()->On_Frame_Update ();
//
// Update the count of particles and polys in the status bar
//
if ((cur_ticks - m_ParticleCountUpdate > 250)) {
m_ParticleCountUpdate = cur_ticks;
doc->Update_Particle_Count ();
int polys = (prender_obj != NULL) ? prender_obj->Get_Num_Polys () : 0;
((CMainFrame *)::AfxGetMainWnd ())->UpdatePolygonCount (polys);
}
//
// Update the frame time in the status bar
//
((CMainFrame *)::AfxGetMainWnd ())->Update_Frame_Time (milliseconds);
}
_already_painting = false;
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// UpdateDisplay
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::UpdateDisplay (void)
{
// Get the document to display
CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
// Are we in a valid state?
/*if (m_bInitialized && doc->GetScene ())
{
RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
if (pCRenderObj)
{
Matrix3D transform = pCRenderObj->Get_Transform ();
transform.Rotate_X (0.05F);
transform.Rotate_Y (0.05F);
transform.Rotate_Z (0.05F);
pCRenderObj->Set_Transform (transform);
}
// Render the current view inside the frame
WW3D::Begin_Render (TRUE, TRUE, Vector3 (0.2,0.4,0.6));
WW3D::Render (doc->GetScene (), m_pCamera, FALSE, FALSE);
WW3D::End_Render ();
} */
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// WindowProc
//
////////////////////////////////////////////////////////////////////////////
LRESULT
CGraphicView::WindowProc
(
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
// Is this the repaint message we are expecting?
if (message == WM_USER+101) {
//
// Force the repaint...
//
RepaintView ();
RemoveProp (m_hWnd, "WaitingToProcess");
} else if (message == WM_PAINT) {
// If we are in fullscreen mode, then erase the window background
if (m_iWindowed == 0) {
// Get the client rectangle of the window
RECT rect;
GetClientRect (&rect);
// Get the window's DC
HDC hDC = ::GetDC (m_hWnd);
if (hDC) {
// Erase the background
::FillRect (hDC, &rect, (HBRUSH)(COLOR_WINDOW + 1));
::ReleaseDC (m_hWnd, hDC);
}
}
RepaintView (FALSE);
ValidateRect (NULL);
return 0;
} else if (message == WM_KEYDOWN) {
if ((wParam == VK_CONTROL) && (m_bLightMeshInScene == false)) {
CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
m_pLightMesh->Add (doc->GetScene ());
m_bLightMeshInScene = true;
}
} else if (message == WM_KEYUP) {
if ((wParam == VK_CONTROL) && (m_bLightMeshInScene == true)) {
CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
m_pLightMesh->Remove ();
m_bLightMeshInScene = false;
}
}
// Allow the base class to process this message
return CView::WindowProc(message, wParam, lParam);
}
////////////////////////////////////////////////////////////////////////////
//
// fnTimerCallback
//
////////////////////////////////////////////////////////////////////////////
void CALLBACK
fnTimerCallback
(
UINT uID,
UINT uMsg,
DWORD dwUser,
DWORD dw1,
DWORD dw2
)
{
HWND hwnd = (HWND)dwUser;
if (hwnd != NULL) {
// Send this event off to the view to process (hackish, but fine for now)
if ((GetProp (hwnd, "WaitingToProcess") == NULL) &&
(GetProp (hwnd, "Inactive") == NULL)) {
SetProp (hwnd, "WaitingToProcess", (HANDLE)1);
// Send the message to the view so it will be in the
// same thread (Surrender doesn't seem to be thread-safe)
::PostMessage (hwnd, WM_USER + 101, 0, 0L);
}
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnLButtonDown
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnLButtonDown
(
UINT nFlags,
CPoint point
)
{
// Capture all mouse messages
SetCapture ();
// Mouse button is down
m_bMouseDown = TRUE;
m_lastPoint = point;
if (m_bRMouseDown) {
::SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_CURSOR_GRAB)));
((CW3DViewDoc *)GetDocument())->Set_Cursor ("grab.tga");
} else {
((CW3DViewDoc *)GetDocument())->Set_Cursor ("orbit.tga");
}
CView::OnLButtonDown (nFlags, point);
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnLButtonUp
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnLButtonUp
(
UINT nFlags,
CPoint point
)
{
if (!m_bRMouseDown)
{
// Release the mouse capture
ReleaseCapture ();
}
// Mouse button is up
m_bMouseDown = FALSE;
if (m_bRMouseDown == TRUE)
{
::SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_CURSOR_ZOOM)));
((CW3DViewDoc *)GetDocument())->Set_Cursor ("zoom.tga");
}
else
{
::SetCursor (::LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW)));
((CW3DViewDoc *)GetDocument())->Set_Cursor ("cursor.tga");
}
// Allow the base class to process this message
CView::OnLButtonUp (nFlags, point);
return ;
}
float minZoomAdjust = 0.0F;
Vector3 sphereCenter;
Quaternion rotation;
////////////////////////////////////////////////////////////////////////////
//
// OnMouseMove
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnMouseMove
(
UINT nFlags,
CPoint point
)
{
int iDeltaX = m_lastPoint.x-point.x;
int iDeltaY = m_lastPoint.y-point.y;
// Get the document to display
CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
if (!(nFlags & MK_CONTROL) && m_bLightMeshInScene) {
m_pLightMesh->Remove ();
m_bLightMeshInScene = false;
} else if ((nFlags & MK_CONTROL) && (m_bLightMeshInScene == false)) {
m_pLightMesh->Add (doc->GetScene ());
m_bLightMeshInScene = true;
}
// Is the mouse button down?
if (m_bMouseDown && m_bRMouseDown)
{
// Get the transformation matrix for the camera and its inverse
Matrix3D transform = m_pCamera->Get_Transform ();
RECT rect;
GetClientRect (&rect);
float midPointX = float(rect.right >> 1);
float midPointY = float(rect.bottom >> 1);
float lastPointX = ((float)m_lastPoint.x - midPointX) / midPointX;
float lastPointY = (midPointY - (float)m_lastPoint.y) / midPointY;
float pointX = ((float)point.x - midPointX) / midPointX;
float pointY = (midPointY - (float)point.y) / midPointY;
Vector3 cameraPan = Vector3(-1.00F*m_CameraDistance*(pointX - lastPointX), -1.00F*m_CameraDistance*(pointY - lastPointY), 0.00F);
transform.Translate (cameraPan);
Matrix3 view = Build_Matrix3 (rotation);
Vector3 move = view * cameraPan;
sphereCenter += move;
// Move the camera back to get a good view of the object
m_pCamera->Set_Transform (transform);
m_lastPoint = point;
}
// Is the mouse button down?
else if ((nFlags & MK_CONTROL) && m_bMouseDown)
{
LightClass *pSceneLight = doc->GetSceneLight ();
if ((pSceneLight != NULL) && (m_pLightMesh != NULL))
{
RECT rect;
GetClientRect (&rect);
Vector3 point_in_view;
Vector3 lastpoint_in_view;
float midPointX = float(rect.right >> 1);
float midPointY = float(rect.bottom >> 1);
float lastPointX = ((float)m_lastPoint.x - midPointX) / midPointX;
float lastPointY = (midPointY - (float)m_lastPoint.y) / midPointY;
float pointX = ((float)point.x - midPointX) / midPointX;
float pointY = (midPointY - (float)point.y) / midPointY;
Quaternion mouse_motion = Inverse(::Trackball(lastPointX, lastPointY, pointX, pointY, 0.8F));
Quaternion light_orientation;
Quaternion camera = Build_Quaternion(m_pCamera->Get_Transform());
Quaternion cur_light = Build_Quaternion(pSceneLight->Get_Transform());
light_orientation = camera;
light_orientation = light_orientation * mouse_motion;
light_orientation = light_orientation * Inverse(camera);
light_orientation = light_orientation * cur_light;
light_orientation.Normalize();
Vector3 to_center;
Matrix3D matrix = pSceneLight->Get_Transform();
Matrix3D::Inverse_Transform_Vector(matrix,sphereCenter,&to_center);
Matrix3D light_tm(light_orientation, sphereCenter);
light_tm.Translate(-to_center);
m_pLightMesh->Set_Transform(light_tm);
pSceneLight->Set_Transform(light_tm);
}
m_lastPoint = point;
}
// Is the mouse button down?
else if ((nFlags & MK_CONTROL) && m_bRMouseDown)
{
// Get the currently displayed object
CW3DViewDoc *doc= (CW3DViewDoc *)GetDocument();
LightClass *pscene_light = doc->GetSceneLight ();
RenderObjClass *prender_obj = doc->GetDisplayedObject ();
if ((pscene_light != NULL) && (prender_obj != NULL)) {
// Calculate a light adjustment factor
CRect rect;
GetClientRect (&rect);
float deltay = (float(iDeltaY))/(float(rect.bottom - rect.top));
float adjustment = deltay * (m_ViewedSphere.Radius * 3.0F);
// Determine the light's new position based on this factor
Matrix3D transform = pscene_light->Get_Transform ();
transform.Translate (Vector3 (0, 0, adjustment));
// Determine what the distance from the light to the object
// would be with this new position
Vector3 light_pos = transform.Get_Translation ();
Vector3 obj_pos = prender_obj->Get_Position ();
float distance = (light_pos - obj_pos).Length ();
// If the new position is acceptable, move the light
if (distance > m_ViewedSphere.Radius) {
m_pLightMesh->Set_Transform (transform);
pscene_light->Set_Transform (transform);
}
}
m_lastPoint = point;
}
// Is the mouse button down?
else if (m_bMouseDown)
{
// Get the document to display
CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
// Are we in a valid state?
if (m_bInitialized && doc->GetScene ())
{
RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
if (pCRenderObj)
{
RECT rect;
GetClientRect (&rect);
float midPointX = float(rect.right >> 1);
float midPointY = float(rect.bottom >> 1);
float lastPointX = ((float)m_lastPoint.x - midPointX) / midPointX;
float lastPointY = (midPointY - (float)m_lastPoint.y) / midPointY;
float pointX = ((float)point.x - midPointX) / midPointX;
float pointY = (midPointY - (float)point.y) / midPointY;
// Rotate around the object (orbit) using a 0.00F - 1.00F percentage of
// the mouse coordinates
rotation = ::Trackball (lastPointX, lastPointY, pointX, pointY, 0.8F);
// Do we want to 'lock-out' all rotation except X?
if (m_allowedCameraRotation == OnlyRotateX)
{
Matrix3D tempMatrix = Build_Matrix3D (rotation);
Matrix3D tempMatrix2 (1);
tempMatrix2.Rotate_X (tempMatrix.Get_X_Rotation ());
tempMatrix2.Set_Translation (tempMatrix.Get_Translation ());
rotation = Build_Quaternion (tempMatrix2);
}
// Do we want to 'lock-out' all rotation except Y?
else if (m_allowedCameraRotation == OnlyRotateY)
{
Matrix3D tempMatrix = Build_Matrix3D (rotation);
Matrix3D tempMatrix2 (1);
tempMatrix2.Rotate_Y (tempMatrix.Get_Y_Rotation ());
tempMatrix2.Set_Translation (tempMatrix.Get_Translation ());
rotation = Build_Quaternion (tempMatrix2);
}
// Do we want to 'lock-out' all rotation except Z?
else if (m_allowedCameraRotation == OnlyRotateZ)
{
Matrix3D tempMatrix = Build_Matrix3D (rotation);
Matrix3D tempMatrix2 (1);
tempMatrix2.Rotate_Z (tempMatrix.Get_Z_Rotation ());
tempMatrix2.Set_Translation (tempMatrix.Get_Translation ());
rotation = Build_Quaternion (tempMatrix2);
}
// Get the transformation matrix for the camera and its inverse
Matrix3D transform = m_pCamera->Get_Transform ();
Matrix3D inverseMatrix;
transform.Get_Orthogonal_Inverse (inverseMatrix);
Vector3 to_object = inverseMatrix * sphereCenter;
transform.Translate (to_object);
Matrix3D::Multiply (transform, Build_Matrix3D (rotation), &transform);
transform.Translate (-to_object);
// Rotate and translate the camera
m_pCamera->Set_Transform (transform);
doc->GetBackObjectCamera ()->Set_Transform (transform);
doc->GetBackObjectCamera ()->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
}
}
m_lastPoint = point;
}
else if (m_bRMouseDown)
{
m_lastPoint = point;
// Get the transformation matrix for the camera and its inverse
Matrix3D transform = m_pCamera->Get_Transform ();
Vector3 distanceVectorZ = transform.Get_Z_Vector ();
if (iDeltaY != 0)
{
// Get the bouding rectangle of the main view
CRect rect;
GetClientRect (&rect);
float deltay = (float(iDeltaY))/(float(rect.bottom - rect.top));
float adjustment = deltay * m_CameraDistance * 3.0F;
if ((adjustment < minZoomAdjust) && (adjustment >= 0.00F))
{
adjustment = minZoomAdjust;
}
if ((adjustment > -minZoomAdjust) && (adjustment <= 0.00F))
{
adjustment = -minZoomAdjust;
}
if ((m_CameraDistance + adjustment) > 0.00F)
{
m_CameraDistance += adjustment;
transform.Translate (Vector3 (0.0F, 0.0F, adjustment));
// Move the camera back to get a good view of the object
m_pCamera->Set_Transform (transform);
// Get the main window of our app
CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
if (pCMainWnd != NULL)
{
// Ensure the background camera matches the main camera
CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
doc->GetBackObjectCamera ()->Set_Transform (transform);
doc->GetBackObjectCamera ()->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
// Update the current object if necessary
RenderObjClass *prender_obj = doc->GetDisplayedObject ();
if (prender_obj != NULL) {
// Ensure the status bar is updated with the correct poly count
pCMainWnd->UpdatePolygonCount (prender_obj->Get_Num_Polys ());
}
// Ensure the status bar is updated with the correct camera distance
pCMainWnd->UpdateCameraDistance (m_CameraDistance);
}
}
}
m_lastPoint = point;
}
// Allow the base class to process this message
CView::OnMouseMove (nFlags, point);
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Reset_Camera_To_Display_Emitter
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Reset_Camera_To_Display_Emitter (ParticleEmitterClass &emitter)
{
// Get some of the emitter settings
Vector3 velocity = emitter.Get_Start_Velocity ();
const Vector3 &acceleration = emitter.Get_Acceleration ();
float lifetime = emitter.Get_Lifetime ();
// If the velocity is 0, then use the randomizer as the default velocity
bool use_vel_rand = false;
if ((velocity.X == 0) && (velocity.Y == 0) && (velocity.Z == 0)) {
//velocity.Set (emitter.Get_Velocity_Random (), emitter.Get_Velocity_Random (), emitter.Get_Velocity_Random ());
//use_vel_rand = true;
}
// Determine what the max extent covered by a particle will be.
Vector3 distance = (velocity * lifetime) + ((acceleration * (lifetime * lifetime)) / 2.0F);
// Do we need to take into account acceleration?
Vector3 distance_maxima (0, 0, 0);
if ((acceleration.X != 0) || (acceleration.Y != 0) || (acceleration.Z != 0)) {
// Determine at what time (for each x,y,z) a maxima will occur.
Vector3 time_max (0, 0, 0);
time_max.X = (acceleration.X != 0) ? ((-velocity.X) / acceleration.X) : 0.00F;
time_max.Y = (acceleration.Y != 0) ? ((-velocity.Y) / acceleration.Y) : 0.00F;
time_max.Z = (acceleration.Z != 0) ? ((-velocity.Z) / acceleration.Z) : 0.00F;
// Is there a maxima for the X direction?
if ((time_max.X >= 0.0F) && (time_max.X < lifetime)) {
distance_maxima.X = (velocity.X * time_max.X) + ((acceleration.X * (time_max.X * time_max.X)) / 2.0F);
distance_maxima.X = fabs (distance_maxima.X);
}
// Is there a maxima for the Y direction?
if ((time_max.Y >= 0.0F) && (time_max.Y < lifetime)) {
distance_maxima.Y = (velocity.Y * time_max.Y) + ((acceleration.Y * (time_max.Y * time_max.Y)) / 2.0F);
distance_maxima.Y = fabs (distance_maxima.Y);
}
// Is there a maxima for the Z direction?
if ((time_max.Z >= 0.0F) && (time_max.Z < lifetime)) {
distance_maxima.Z = (velocity.Z * time_max.Z) + ((acceleration.Z * (time_max.Z * time_max.Z)) / 2.0F);
distance_maxima.Z = fabs (distance_maxima.Z);
}
}
distance.X = fabs (distance.X);
distance.Y = fabs (distance.Y);
distance.Z = fabs (distance.Z);
// Determine what the maximum distance convered in a single direction is
float max_dist = max (distance.X, distance.Y);
max_dist = max (max_dist, distance.Z);
max_dist = max (max_dist, distance_maxima.X);
max_dist = max (max_dist, distance_maxima.Y);
max_dist = max (max_dist, distance_maxima.Z);
Vector3 center = distance / 2.00F;
center.X = max (center.X, distance_maxima.X / 2.00F);
center.Y = max (center.Y, distance_maxima.Y / 2.00F);
center.Z = max (center.Z, distance_maxima.Z / 2.00F);
if (use_vel_rand) {
center.Set (0, 0, 0);
}
// Build a logical sphere from the emitters settings
// that should provide a good viewing distance for the emitter.
SphereClass sphere;
sphere.Center = center;
sphere.Radius = max (emitter.Get_Particle_Size () * 5, (max_dist * 3.0F) / 5.0F);
// View this sphere
Reset_Camera_To_Display_Sphere (sphere);
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Reset_Camera_To_Display_Sphere
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Reset_Camera_To_Display_Sphere (SphereClass &sphere)
{
// Calculate a default camera distance to view this sphere
m_CameraDistance = sphere.Radius * 3.00F;
m_CameraDistance = (m_CameraDistance < 1.0F) ? 1.0F : m_CameraDistance;
// Calculate a transform that is the appropriate distance
// from the sphere center and is looking at the center
Matrix3D transform (1);
transform.Look_At (sphere.Center + Vector3 (m_CameraDistance, 0, 0), sphere.Center, 0);
// Record some variables for later use
sphereCenter = sphere.Center;
m_ObjectCenter = sphereCenter;
minZoomAdjust = m_CameraDistance / 190.0F;
rotation = Build_Quaternion (transform);
// Move the camera back to get a good view of the object
m_pCamera->Set_Transform (transform);
// Make the same adjustment for the scene light
CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
LightClass *pSceneLight = doc->GetSceneLight ();
if ((m_pLightMesh != NULL) && (pSceneLight != NULL)) {
// Reposition the light and its 'mesh' as appropriate
transform.Make_Identity ();
transform.Set_Translation (sphereCenter);
transform.Translate (0, 0, 0.7F * m_CameraDistance);
pSceneLight->Set_Transform (transform);
m_pLightMesh->Set_Transform (transform);
// Scale the light's mesh appropriately
static float last_scale = 1.0F;
m_pLightMesh->Scale (m_CameraDistance / (14 * last_scale));
last_scale = m_CameraDistance / 14;
}
float max_dist = m_CameraDistance * 60.0F;
float min_dist = max (0.2F, minZoomAdjust / 2);
// Set the clipping planes so objects are clipped correctly
if (doc->Are_Clip_Planes_Manual () == false) {
m_pCamera->Set_Clip_Planes (min_dist, max_dist);
// Adjust the fog near clipping plane to the new value, but
// leave the far clip plane alone (since it is scene dependant
// not camera dependant).
float fog_near, fog_far;
doc->GetScene()->Get_Fog_Range(&fog_near, &fog_far);
doc->GetScene()->Set_Fog_Range(min_dist, fog_far);
doc->GetScene()->Recalculate_Fog_Planes();
}
// Reset the background camera to match the main camera
doc->GetBackObjectCamera ()->Set_Transform (transform);
doc->GetBackObjectCamera ()->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
// Update the camera distance in the status bar
CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
if (pCMainWnd != NULL) {
pCMainWnd->UpdateCameraDistance (m_CameraDistance);
pCMainWnd->UpdateFrameCount (0, 0, 0);
}
// Record the sphere we are viewing for later
m_ViewedSphere = sphere;
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Reset_Camera_To_Display_Object
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Reset_Camera_To_Display_Object (RenderObjClass &render_object)
{
// Reset the camera to get a good look at this object's bounding sphere
SphereClass sp = render_object.Get_Bounding_Sphere ();
Reset_Camera_To_Display_Sphere (sp);
// Should we update the camera's position as well?
int index = render_object.Get_Bone_Index ("CAMERA");
if (index > 0) {
// Convert the bone's transform into a camera transform
Matrix3D transform = render_object.Get_Bone_Transform (index);
if (m_CameraBonePosX) {
Matrix3D tmp = transform;
Matrix3D cam_transform (Vector3 (0, -1, 0), Vector3 (0, 0, 1), Vector3 (-1, 0, 0), Vector3 (0, 0, 0));
transform = tmp * cam_transform;
}
// Pass the new transform onto the camera
CameraClass *camera = GetCamera ();
camera->Set_Transform (transform);
}
// Update the polygon count in the main window
CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
if (pCMainWnd != NULL) {
pCMainWnd->UpdatePolygonCount (render_object.Get_Num_Polys ());
}
// Load the settings in the default.dat if its in the local directory.
Load_Default_Dat ();
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Load_Default_Dat
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Load_Default_Dat (void)
{
// Get the directory where this executable was run from
TCHAR filename[MAX_PATH];
::GetModuleFileName (NULL, filename, sizeof (filename));
// Strip the filename from the path
LPTSTR ppath = ::strrchr (filename, '\\');
if (ppath != NULL) {
ppath[0] = 0;
}
// Concat the default.dat filename onto the path
::strcat (filename, "\\default.dat");
// Does the file exist in the directory?
if (::GetFileAttributes (filename) != 0xFFFFFFFF) {
// Ask the document to load the settings from this data file
CW3DViewDoc *pCDoc = (CW3DViewDoc *)GetDocument ();
if (pCDoc != NULL) {
pCDoc->LoadSettings (filename);
}
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnRButtonUp
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnRButtonUp
(
UINT nFlags,
CPoint point
)
{
// Mouse button is up
m_bRMouseDown = FALSE;
if (m_bMouseDown) {
((CW3DViewDoc *)GetDocument())->Set_Cursor ("orbit.tga");
} else {
::SetCursor (::LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW)));
((CW3DViewDoc *)GetDocument())->Set_Cursor ("cursor.tga");
ReleaseCapture ();
}
// Allow the base class to process this message
CView::OnRButtonUp(nFlags, point);
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnRButtonDown
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnRButtonDown
(
UINT nFlags,
CPoint point
)
{
// Capture all mouse messages
SetCapture ();
// Mouse button is down
m_bRMouseDown = TRUE;
m_lastPoint = point;
if (m_bMouseDown)
{
::SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_CURSOR_GRAB)));
((CW3DViewDoc *)GetDocument())->Set_Cursor ("grab.tga");
}
else
{
::SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_CURSOR_ZOOM)));
((CW3DViewDoc *)GetDocument())->Set_Cursor ("zoom.tga");
}
// Allow the base class to process this message
CView::OnRButtonDown(nFlags, point);
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// SetAnimationState
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::SetAnimationState (ANIMATION_STATE animationState)
{
// Has the state changed?
if (m_animationState != animationState)
{
switch (animationState)
{
// We want to stop the animation
case AnimStopped:
{
// Get the document so we can get our current object
CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
ASSERT_VALID (doc);
// Get the currently displayed object
RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
if (pCRenderObj)
{
// Reset the animation to frame 0
if (doc->GetCurrentAnimation()) {
pCRenderObj->Set_Animation (doc->GetCurrentAnimation (), 0);
}
}
// Reset the animation to frame 0
doc->ResetAnimation ();
}
break;
case AnimPlaying:
{
CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument ();
doc->Play_Animation_Sound ();
// Reset the frame timer
m_dwLastFrameUpdate = timeGetTime ();
}
break;
}
// Save the new state
m_animationState = animationState;
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// SetCameraPos
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::SetCameraPos (CAMERA_POS cameraPos)
{
// Get the document so we can get our current object
CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
ASSERT_VALID (doc);
// Get the currently displayed object
RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
if (pCRenderObj)
{
SphereClass sphere = m_ViewedSphere;
m_CameraDistance = sphere.Radius * 3.00F;
m_CameraDistance = (m_CameraDistance < 1.0F) ? 1.0F : m_CameraDistance;
m_CameraDistance = (m_CameraDistance > 400.0F) ? 400.0F : m_CameraDistance;
Matrix3D transform (1);
switch (cameraPos)
{
case CameraFront:
{
transform.Look_At (sphere.Center + Vector3 (m_CameraDistance, 0.00F, 0.00F), sphere.Center, 0);
}
break;
case CameraBack:
{
transform.Look_At (sphere.Center + Vector3 (-m_CameraDistance, 0.00F, 0.00F), sphere.Center, 0);
}
break;
case CameraLeft:
{
transform.Look_At (sphere.Center + Vector3 (0.00F, -m_CameraDistance, 0.00F), sphere.Center, 0);
}
break;
case CameraRight:
{
transform.Look_At (sphere.Center + Vector3 (0.00F, m_CameraDistance, 0.00F), sphere.Center, 0);
}
break;
case CameraTop:
{
transform.Look_At (sphere.Center + Vector3 (0.00F, 0.00F, m_CameraDistance), sphere.Center, 3.1415926535F);
}
break;
case CameraBottom:
{
transform.Look_At (sphere.Center + Vector3 (0.00F, 0.00F, -m_CameraDistance), sphere.Center, 3.1415926535F);
}
break;
}
// Move the camera back to get a good view of the object
m_pCamera->Set_Transform (transform);
// Get the main window of our app
CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
if (pCMainWnd != NULL)
{
CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
doc->GetBackObjectCamera ()->Set_Transform (transform);
doc->GetBackObjectCamera ()->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
if (pCRenderObj)
{
pCMainWnd->UpdatePolygonCount (pCRenderObj->Get_Num_Polys ());
}
pCMainWnd->UpdateCameraDistance(m_CameraDistance);
}
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// RotateObject
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::RotateObject (OBJECT_ROTATION rotation)
{
// Is this rotation different?
if (m_objectRotation != rotation)
{
// Save the rotation state
m_objectRotation = rotation;
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// SetAllowedCameraRotation
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::SetAllowedCameraRotation (CAMERA_ROTATION cameraRotation)
{
// Store this for later reference
m_allowedCameraRotation = cameraRotation;
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// ResetObject
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::ResetObject (void)
{
// Get the current document
CW3DViewDoc *doc = ::GetCurrentDocument ();
ASSERT (doc);
if (doc)
{
// Get the currently displayed object
RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
if (pCRenderObj)
{
// Reset the rotation of the object
pCRenderObj->Set_Transform (Matrix3D(1));
}
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// OnGetMinMaxInfo
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::OnGetMinMaxInfo (MINMAXINFO FAR* lpMMI)
{
CView::OnGetMinMaxInfo (lpMMI);
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Rotate_Object
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Rotate_Object (void)
{
// Get the document to display
CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
// Get the currently displayed object
RenderObjClass *prender_obj = doc->GetDisplayedObject ();
if (prender_obj != NULL)
{
// Get the current transform for the object
Matrix3D transform = prender_obj->Get_Transform ();
if ((m_objectRotation & RotateX) == RotateX) {
transform.Rotate_X (0.05F);
} else if ((m_objectRotation & RotateXBack) == RotateXBack) {
transform.Rotate_X (-0.05F);
}
if ((m_objectRotation & RotateY) == RotateY) {
transform.Rotate_Y (-0.05F);
} else if ((m_objectRotation & RotateYBack) == RotateYBack) {
transform.Rotate_Y (0.05F);
}
if ((m_objectRotation & RotateZ) == RotateZ) {
transform.Rotate_Z (0.05F);
} else if ((m_objectRotation & RotateZBack) == RotateZBack) {
transform.Rotate_Z (-0.05F);
}
if (!transform.Is_Orthogonal()) {
transform.Re_Orthogonalize();
}
// Set the new transform for the object
prender_obj->Set_Transform (transform);
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Rotate_Light
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Rotate_Light (void)
{
// Get the document to display
CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
// Get the currently displayed object
LightClass *pscene_light = doc->GetSceneLight ();
RenderObjClass *prender_obj = doc->GetDisplayedObject ();
if ((pscene_light != NULL) && (prender_obj != NULL)) {
Matrix3D rotation_matrix (1);
// Build a rotation matrix that contains the x,y,z
// rotations we want to apply to the light
if ((m_LightRotation & RotateX) == RotateX) {
rotation_matrix.Rotate_X (0.05F);
} else if ((m_LightRotation & RotateXBack) == RotateXBack) {
rotation_matrix.Rotate_X (-0.05F);
}
if ((m_LightRotation & RotateY) == RotateY) {
rotation_matrix.Rotate_Y (-0.05F);
} else if ((m_LightRotation & RotateYBack) == RotateYBack) {
rotation_matrix.Rotate_Y (0.05F);
}
if ((m_LightRotation & RotateZ) == RotateZ) {
rotation_matrix.Rotate_Z (0.05F);
} else if ((m_LightRotation & RotateZBack) == RotateZBack) {
rotation_matrix.Rotate_Z (-0.05F);
}
//
// Now, use the rotation matrix to rotate the
// light 'around' the displayed object (in its coordinate system)
//
Matrix3D coord_inv;
Matrix3D coord_to_obj;
Matrix3D coord_system = prender_obj->Get_Transform ();
coord_system.Get_Orthogonal_Inverse (coord_inv);
Matrix3D transform = pscene_light->Get_Transform ();
Matrix3D::Multiply (coord_inv, transform, &coord_to_obj);
Matrix3D::Multiply (coord_system, rotation_matrix, &transform);
Matrix3D::Multiply (transform, coord_to_obj, &transform);
// Ensure the matrix hasn't degenerated
if (!transform.Is_Orthogonal ()) {
transform.Re_Orthogonalize ();
}
// Pass the new transform onto the light
m_pLightMesh->Set_Transform (transform);
pscene_light->Set_Transform (transform);
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Set_FOV
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Set_FOV (double hfov, double vfov, bool force)
{
CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
if (force || (doc->Is_FOV_Manual () == false)) {
m_pCamera->Set_View_Plane (hfov, vfov);
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Reset_FOV
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Reset_FOV (void)
{
int cx = 0;
int cy = 0;
if (m_iWindowed == 0) {
cx = g_iWidth;
cy = g_iHeight;
} else {
CRect rect;
GetClientRect (&rect);
cx = rect.Width ();
cy = rect.Height ();
}
// update the camera FOV settings
// take the larger of the two dimensions, give it the
// full desired FOV, then give the other dimension an
// FOV proportional to its relative size
double hfov,vfov;
if (cy > cx) {
vfov = (float)DEG_TO_RAD(45.0f);
hfov = (double)cx / (double)cy * vfov;
} else {
hfov = (float)DEG_TO_RAD(45.0f);
vfov = (double)cy / (double)cx * hfov;
}
// Reset the field of view
Set_FOV (hfov, vfov);
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Set_Camera_Distance
//
////////////////////////////////////////////////////////////////////////////
void
CGraphicView::Set_Camera_Distance (float dist)
{
m_CameraDistance = dist;
//
// Reposition the camera
//
Matrix3D new_tm(1);
new_tm.Look_At (m_ViewedSphere.Center + Vector3 (m_CameraDistance, 0.00F, 0.00F), m_ViewedSphere.Center, 0);
m_pCamera->Set_Transform (new_tm);
//
// Update the status bar
//
CMainFrame *main_wnd = (CMainFrame *)::AfxGetMainWnd ();
if (main_wnd != NULL) {
main_wnd->UpdateCameraDistance (m_CameraDistance);
}
return ;
}