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/W3DViewDoc.cpp

3114 lines
84 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/>.
*/
// W3DViewDoc.cpp : implementation of the CW3DViewDoc class
//
#include "stdafx.h"
#include "w3dview.h"
#include "w3dviewdoc.h"
#include "ffactory.h"
#include "globals.h"
#include "viewerassetmgr.h"
#include "globals.h"
#include "rendobj.h"
#include "graphicview.h"
#include "datatreeview.h"
#include "mainfrm.h"
#include "distlod.h"
#include "light.h"
#include "camera.h"
#include "w3d_file.h"
#include "wwfile.h"
#include "bmp2d.h"
#include "part_emt.h"
#include "part_ldr.h"
#include "utils.h"
#include "w3derr.h"
#include "chunkio.h"
#include "assetinfo.h"
#include "meshmdl.h"
#include "agg_def.h"
#include "hlod.h"
#include "restrictedfiledialog.h"
#include "viewerscene.h"
#include "ini.h"
#include "ww3d.h"
#include "emitterinstancelist.h"
#include "mesh.h"
#include "screencursor.h"
#include "sphereobj.h"
#include "ringobj.h"
#include "textfile.h"
#include "hmorphanim.h"
#include "mmsystem.h"
#include "soundrobj.h"
#include "dazzle.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CW3DViewDoc
IMPLEMENT_DYNCREATE(CW3DViewDoc, CDocument)
BEGIN_MESSAGE_MAP(CW3DViewDoc, CDocument)
//{{AFX_MSG_MAP(CW3DViewDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CW3DViewDoc construction/destruction
///////////////////////////////////////////////////////////////
//
// CW3DViewDoc
//
CW3DViewDoc::CW3DViewDoc (void)
: m_pCScene (NULL),
m_pC2DScene (NULL),
m_pCursorScene (NULL),
m_pCBackObjectScene (NULL),
m_pDazzleLayer (NULL),
m_pCBackObjectCamera (NULL),
m_pCBackgroundObject (NULL),
m_pC2DCamera (NULL),
m_pCSceneLight (NULL),
m_pCRenderObj (NULL),
m_pCAnimation (NULL),
m_pCAnimCombo (NULL),
m_pCBackgroundBMP (NULL),
m_CurrentFrame (0),
m_bAnimBlend (TRUE),
m_bAnimateCamera (false),
m_bAutoCameraReset (true),
m_bOneTimeReset (true),
m_pCursor (NULL),
m_backgroundColor (0.5F, 0.5F, 0.5F),
m_ManualFOV (false),
m_ManualClipPlanes (false),
m_IsInitialized (false),
m_bFogEnabled(false),
m_nChannelQnBytes(2),
m_bCompress_channel_Q(false)
{
// Read the camera animation settings from the registry
m_bAnimateCamera = ((BOOL)theApp.GetProfileInt ("Config", "AnimateCamera", 0)) == TRUE;
m_bAutoCameraReset = ((BOOL)theApp.GetProfileInt ("Config", "ResetCamera", 1)) == TRUE;
return ;
}
///////////////////////////////////////////////////////////////
//
// ~CW3DViewDoc
//
///////////////////////////////////////////////////////////////
CW3DViewDoc::~CW3DViewDoc (void)
{
CleanupResources ();
MEMBER_RELEASE (m_pCursor);
return ;
}
///////////////////////////////////////////////////////////////
//
// CleanupResources
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::CleanupResources (void)
{
if (m_pC2DScene)
{
if (m_pCBackgroundBMP)
{
// Remove the background BMP from the scene
m_pCBackgroundBMP->Remove ();
}
// Release the 2D scene we allocated to display background BMPs
m_pC2DScene->Release_Ref ();
m_pC2DScene = NULL;
}
if (m_pCBackObjectScene)
{
if (m_pCBackgroundObject)
{
// Remove the background BMP from the scene
m_pCBackgroundObject->Remove ();
}
// Release the scene we allocated to display background objects
m_pCBackObjectScene->Release_Ref ();
m_pCBackObjectScene = NULL;
}
if (m_pCursor != NULL) {
m_pCursor->Remove ();
}
MEMBER_RELEASE (m_pCursorScene);
if (m_pCScene)
{
if (m_pCRenderObj)
{
// Remove the currently displayed object from the scene
Remove_Object_From_Scene (m_pCRenderObj);
}
if (m_pCSceneLight)
{
// Remove the light from the scene
Remove_Object_From_Scene (m_pCSceneLight);
}
// Get rid of the lined up objects.
m_pCScene->Clear_Lineup();
// Release the scene object we allocated earlier
m_pCScene->Release_Ref ();
m_pCScene = NULL;
}
// Was there a dazzle layer?
if (m_pDazzleLayer) {
delete m_pDazzleLayer;
m_pDazzleLayer = NULL;
}
// Was there a valid scene object?
if (m_pCBackObjectScene)
{
// Free the scene object
m_pCBackObjectScene->Release_Ref ();
m_pCBackObjectScene = NULL;
}
// Was there a valid 2D camera?
if (m_pC2DCamera)
{
// Free the camera object
m_pC2DCamera->Release_Ref ();
m_pC2DCamera = NULL;
}
// Was there a valid background camera?
if (m_pCBackObjectCamera)
{
// Free the camera object
m_pCBackObjectCamera->Release_Ref ();
m_pCBackObjectCamera = NULL;
}
// Was there a valid background BMP?
if (m_pCBackgroundBMP)
{
m_pCBackgroundBMP->Release_Ref ();
m_pCBackgroundBMP = NULL;
}
// Was there a valid scene light?
if (m_pCSceneLight)
{
m_pCSceneLight->Release_Ref ();
m_pCSceneLight = NULL;
}
// Was there a valid display object?
if (m_pCRenderObj)
{
// Free the currently displayed object
SAFE_DELETE (m_pCAnimCombo);
MEMBER_RELEASE (m_pCAnimation);
MEMBER_RELEASE (m_pCRenderObj);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// OnNewDocument
//
///////////////////////////////////////////////////////////////
BOOL
CW3DViewDoc::OnNewDocument (void)
{
if (!CDocument::OnNewDocument())
return FALSE;
_TheAssetMgr->Start_Tracking_Textures ();
m_LoadList.Delete_All ();
m_bOneTimeReset = true;
if (m_pCScene && m_pCRenderObj)
{
// Remove the currently displayed object from the scene
Remove_Object_From_Scene (m_pCRenderObj);
}
if (m_pCScene)
{
// Remove all objects from the lineup.
m_pCScene->Clear_Lineup();
// Update the fog color.
m_pCScene->Set_Fog_Color(m_backgroundColor);
}
if (m_pCRenderObj)
{
// Free the currently displayed object
SAFE_DELETE (m_pCAnimCombo);
MEMBER_RELEASE (m_pCAnimation);
MEMBER_RELEASE (m_pCRenderObj);
}
CDataTreeView *pCDataTreeView = GetDataTreeView ();
if (pCDataTreeView)
{
// Delete everything from the tree
pCDataTreeView->GetTreeCtrl ().DeleteAllItems ();
// Recreate the root nodes
pCDataTreeView->CreateRootNodes ();
}
// Remove everything from the scene and the asset manager
CleanupResources ();
//WW3DAssetManager::Get_Instance ()->Release_All_Textures ();
WW3DAssetManager::Get_Instance ()->Free_Assets ();
WW3DAssetManager::Get_Instance ()->Load_Procedural_Textures();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// CW3DViewDoc
//
/////////////////////////////////////////////////////////////////////////////
void
CW3DViewDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
// CW3DViewDoc diagnostics
#ifdef _DEBUG
void CW3DViewDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CW3DViewDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
///////////////////////////////////////////////////////////////
//
// InitScene
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::InitScene (void)
{
if (m_pCScene == NULL) {
//
// Make sure the emitters don't remove themselves from the scene
// when they are finished emitting...
//
ParticleEmitterClass::Set_Default_Remove_On_Complete (false);
m_pCScene = new ViewerSceneClass;
ASSERT (m_pCScene);
if (m_pCScene != NULL) {
// Set some default ambient lighting
m_pCScene->Set_Ambient_Light (Vector3 (0.5F, 0.5F, 0.5F));
// Set up the correct fog color.
m_pCScene->Set_Fog_Color(GetBackgroundColor());
// Create a new scene light
m_pCSceneLight = new LightClass;
ASSERT (m_pCSceneLight);
if (m_pCSceneLight != NULL) {
// Create some default light settings
m_pCSceneLight->Set_Position (Vector3 (0, 5000, 3000));
m_pCSceneLight->Set_Intensity (1.0F);
m_pCSceneLight->Set_Force_Visible(true);
m_pCSceneLight->Set_Flag (LightClass::NEAR_ATTENUATION, false);
m_pCSceneLight->Set_Far_Attenuation_Range (1000000, 1000000);
m_pCSceneLight->Set_Ambient(Vector3(0,0,0));
m_pCSceneLight->Set_Diffuse (Vector3(1, 1, 1));
m_pCSceneLight->Set_Specular (Vector3(1, 1, 1));
// Add this light to the scene
m_pCScene->Add_Render_Object (m_pCSceneLight);
}
}
// Instantiate a new 2D scene
m_pC2DScene = new SimpleSceneClass;
ASSERT (m_pC2DScene);
// Instantiate a new 2D cursor scene
m_pCursorScene = new SimpleSceneClass;
ASSERT (m_pCursorScene);
Create_Cursor ();
m_pCursorScene->Add_Render_Object (m_pCursor);
m_pCBackObjectScene = new SimpleSceneClass;
// Were we successful in instantiating the scene object?
ASSERT (m_pCBackObjectScene);
if (m_pCBackObjectScene) {
// Set the default ambient light for the background object
m_pCBackObjectScene->Set_Ambient_Light (Vector3 (0.5F, 0.5F, 0.5F));
}
// Create a new instance of the camera class to use
// when rendering the background object
m_pCBackObjectCamera = new CameraClass ();
// Were we successful in creating the new instance?
ASSERT (m_pCBackObjectCamera);
if (m_pCBackObjectCamera) {
// Set the default values for the new camera
m_pCBackObjectCamera->Set_View_Plane (Vector2 (-1.00F, -1.00F), Vector2 (1.00F, 1.00F));
m_pCBackObjectCamera->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
m_pCBackObjectCamera->Set_Clip_Planes (0.1F, 10.0F);
}
// Create a new instance of the camera class to use
// when rendering the background BMP
m_pC2DCamera = new CameraClass ();
// Were we successful in creating the new instance?
ASSERT (m_pC2DCamera);
if (m_pC2DCamera) {
// Set the default values for the new camera
m_pC2DCamera->Set_View_Plane (Vector2 (-1.00F, -1.00F), Vector2 (1.00F, 1.00F));
m_pC2DCamera->Set_Position (Vector3 (0.00F, 0.00F, 1.00F));
m_pC2DCamera->Set_Clip_Planes (0.1F, 10.0F);
}
//
// Read the texture paths from the registry
//
CString path1 = theApp.GetProfileString ("Config", "TexturePath1", "");
CString path2 = theApp.GetProfileString ("Config", "TexturePath2", "");
Set_Texture_Path1 (path1);
Set_Texture_Path2 (path2);
// Construct a dazzle layer object
m_pDazzleLayer = new DazzleLayerClass();
DazzleRenderObjClass::Set_Current_Dazzle_Layer(m_pDazzleLayer);
// Enable fog if appropriate.
if (IsFogEnabled()) {
m_pCScene->Set_Fog_Enable(true);
}
}
Load_Camera_Settings ();
m_IsInitialized = true;
return ;
}
///////////////////////////////////////////////////////////////
//
// OnOpenDocument
//
///////////////////////////////////////////////////////////////
BOOL
CW3DViewDoc::OnOpenDocument (LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
//
// Don't allow repaints while the load is going on
//
CGraphicView *current_view = ::Get_Graphic_View ();
if (current_view != NULL) {
current_view->Allow_Update (false);
}
//
// Load the assets from this file into application
//
LoadAssetsFromFile (lpszPathName);
//
// Re-load the data list to include all new assets
//
CDataTreeView *data_view = GetDataTreeView ();
if (data_view != NULL) {
data_view->LoadAssetsIntoTree ();
}
//
// Turn repainting back on...
//
if (current_view != NULL) {
current_view->Allow_Update (true);
}
return TRUE;
}
///////////////////////////////////////////////////////////////
//
// LoadAssetsFromFile
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::LoadAssetsFromFile (LPCTSTR lpszPathName)
{
if (m_pCScene == NULL) {
InitScene ();
}
//
// Remember the last path we opened
//
m_LastPath = ::Strip_Filename_From_Path (lpszPathName);
//
// Add this path to the load list
//
m_LoadList.Add (lpszPathName);
//
// Don't allow repaints while the load is going on
//
CGraphicView *current_view = ::Get_Graphic_View ();
if (current_view != NULL) {
current_view->Allow_Update (false);
}
//
// HACK HACK -- Force the current directory to be the directory
// the file is located in.
//
if (::strrchr (lpszPathName, '\\')) {
CString stringTemp = lpszPathName;
stringTemp = stringTemp.Left ((long)::strrchr (lpszPathName, '\\') - (long)lpszPathName);
::SetCurrentDirectory (stringTemp);
_TheSimpleFileFactory->Append_Sub_Directory(stringTemp);
}
LPCTSTR extension = ::strrchr (lpszPathName, '.');
if (::lstrcmpi (extension, ".tga") == 0 || ::lstrcmpi (extension, ".dds") == 0) {
// Load the texture file into the asset manager
TextureClass *ptexture = WW3DAssetManager::Get_Instance()->Get_Texture (::Get_Filename_From_Path (lpszPathName));
if (ptexture != NULL) {
ptexture->Release_Ref();
}
} else {
WW3DAssetManager::Get_Instance()->Load_3D_Assets (::Get_Filename_From_Path (lpszPathName));
}
//
// Turn repainting back on...
//
if (current_view != NULL) {
current_view->Allow_Update (true);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Reload_Displayed_Object
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Reload_Displayed_Object (void)
{
GetDataTreeView ()->Display_Asset ();
//SAFE_ADD_REF (m_pCRenderObj);
//DisplayObject (m_pCRenderObj, false, false);
//SAFE_RELEASE_REF (m_pCRenderObj);
return ;
}
///////////////////////////////////////////////////////////////
//
// Display_Emitter
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Display_Emitter
(
ParticleEmitterClass *pemitter,
bool use_global_reset_flag,
bool allow_reset
)
{
ASSERT (m_pCScene);
// Data OK?
if (m_pCScene != NULL) {
// Lose the animation
SAFE_DELETE (m_pCAnimCombo);
MEMBER_RELEASE (m_pCAnimation);
if (m_pCRenderObj != NULL) {
// Remove this object from the scene
Remove_Object_From_Scene (m_pCRenderObj);
m_pCRenderObj->Release_Ref ();
m_pCRenderObj = NULL;
}
m_pCScene->Clear_Lineup();
// Do we have a new emitter to display?
if (pemitter != NULL) {
// Add the emitter to the scene
pemitter->Set_Transform (Matrix3D (1));
MEMBER_ADD (m_pCRenderObj, pemitter);
m_pCScene->Add_Render_Object (m_pCRenderObj);
pemitter->Start ();
CGraphicView *pCGraphicView = GetGraphicView ();
if (pCGraphicView) {
// Try to find a good view for the emitter
if ((use_global_reset_flag && m_bAutoCameraReset) ||
((use_global_reset_flag == false) && allow_reset) ||
m_bOneTimeReset) {
pCGraphicView->Reset_Camera_To_Display_Emitter (*pemitter);
m_bOneTimeReset = false;
}
}
}
}
return ;
}
///////////////////////////////////////////////////////////////
//
// DisplayObject
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::DisplayObject
(
RenderObjClass *pCModel,
bool use_global_reset_flag,
bool allow_reset,
bool add_ghost
)
{
ASSERT (m_pCScene);
// Data OK?
if (m_pCScene)
{
// Lose the animation
SAFE_DELETE (m_pCAnimCombo);
MEMBER_RELEASE (m_pCAnimation);
// Do we have an old object to remove from the scene?
if (add_ghost == false) {
if (m_pCRenderObj)
{
// Remove this object from the scene
Remove_Object_From_Scene (m_pCRenderObj);
m_pCRenderObj->Release_Ref ();
m_pCRenderObj = NULL;
}
}
m_pCScene->Clear_Lineup();
// Do we have a new object to display?
if (pCModel && (add_ghost == false))
{
// Reset the animation for this object
pCModel->Set_Animation ();
m_pCRenderObj = pCModel;
m_pCRenderObj->Add_Ref ();
m_pCRenderObj->Set_Transform (Matrix3D (1));
// Add this object to the scene
if (m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_BITMAP2D) {
m_pC2DScene->Add_Render_Object (m_pCRenderObj);
} else {
m_pCScene->Add_Render_Object (m_pCRenderObj);
}
// Reset the current lod to be the lowest possible LOD...
if ((m_pCScene->Are_LODs_Switching ()) &&
(m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_HLOD)) {
((HLodClass *)m_pCRenderObj)->Set_LOD_Level (0);
}
CGraphicView *pCGraphicView = GetGraphicView ();
if (pCGraphicView)
{
// Reset the camera to so the user can see
// the whole object
if ((use_global_reset_flag && m_bAutoCameraReset) ||
((use_global_reset_flag == false) && allow_reset) ||
m_bOneTimeReset) {
pCGraphicView->Reset_Camera_To_Display_Object (*m_pCRenderObj);
m_bOneTimeReset = false;
}
}
}
else if (pCModel) {
// Reset the animation for this object
pCModel->Set_Animation ();
RenderObjClass *m_pCRenderObj;
m_pCRenderObj = pCModel;
m_pCRenderObj->Add_Ref ();
m_pCRenderObj->Set_Transform (Matrix3D (1));
// Add this object to the scene
if (m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_BITMAP2D) {
m_pC2DScene->Add_Render_Object (m_pCRenderObj);
} else {
m_pCScene->Clear_Lineup();
m_pCScene->Add_Render_Object (m_pCRenderObj);
}
// Reset the current lod to be the lowest possible LOD...
if ((m_pCScene->Are_LODs_Switching ()) &&
(m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_HLOD)) {
((HLodClass *)m_pCRenderObj)->Set_LOD_Level (0);
}
CGraphicView *pCGraphicView = GetGraphicView ();
if (pCGraphicView)
{
// Reset the camera to so the user can see
// the whole object
if ((use_global_reset_flag && m_bAutoCameraReset) ||
((use_global_reset_flag == false) && allow_reset) ||
m_bOneTimeReset) {
pCGraphicView->Reset_Camera_To_Display_Object (*m_pCRenderObj);
m_bOneTimeReset = false;
}
}
}
}
return ;
}
///////////////////////////////////////////////////////////////
//
// ResetAnimation
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::ResetAnimation (void)
{
if (m_pCAnimation != NULL) {
//
// Reset the frame counter
//
m_CurrentFrame = 0;
m_animTime = 0.00F;
float frame_rate = m_pCAnimation->Get_Frame_Rate ();
float anim_speed = ::Get_Graphic_View ()->GetAnimationSpeed ();
//
// Update the status bar on the main window
//
((CMainFrame *)::AfxGetMainWnd ())->UpdateFrameCount ( 0,
m_pCAnimation->Get_Num_Frames () - 1,
frame_rate * anim_speed);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// StepAnimation
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::StepAnimation (int iFrameInc)
{
if (m_pCRenderObj && m_pCAnimation) {
int iTotalFrames = m_pCAnimation->Get_Num_Frames ();
// Increment the frame
m_CurrentFrame += iFrameInc;
//
// Wrap the animation
//
if (m_CurrentFrame >= iTotalFrames) {
m_CurrentFrame = 0;
m_animTime = 0.00F;
}
else if (m_CurrentFrame < 0) {
m_CurrentFrame = iTotalFrames-1;
}
//
// Update the status bar on the main window
//
float frame_rate = m_pCAnimation->Get_Frame_Rate ();
float anim_speed = ::Get_Graphic_View ()->GetAnimationSpeed ();
((CMainFrame *)::AfxGetMainWnd ())->UpdateFrameCount (m_CurrentFrame, iTotalFrames - 1, frame_rate * anim_speed);
//
// Update the animation frame
//
if (m_pCAnimCombo) {
for (int i = 0; i < m_pCAnimCombo->Get_Num_Anims(); i++)
{
m_pCAnimCombo->Set_Frame(i, m_CurrentFrame);
}
m_pCRenderObj->Set_Animation (m_pCAnimCombo);
} else {
m_pCRenderObj->Set_Animation (m_pCAnimation, m_CurrentFrame);
}
Update_Camera ();
}
return ;
}
///////////////////////////////////////////////////////////////
//
// PlayAnimation
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::PlayAnimation
(
RenderObjClass *pCModel,
LPCTSTR pszAnimationName,
bool use_global_reset_flag,
bool allow_reset
)
{
ASSERT (m_pCScene);
ASSERT (pCModel);
ASSERT (pszAnimationName);
// Data OK?
if (m_pCScene &&
pCModel &&
pszAnimationName)
{
// Display this hierarchy on the screen
DisplayObject (pCModel);
// Get an instance of the animation object
SAFE_DELETE (m_pCAnimCombo);
MEMBER_RELEASE (m_pCAnimation);
m_pCAnimation = WW3DAssetManager::Get_Instance()->Get_HAnim (pszAnimationName);
ASSERT (m_pCAnimation);
// Reset the frame counter
m_CurrentFrame = 0;
m_animTime = 0.00F;
if (m_pCRenderObj)
{
// Update the animation frame
m_pCRenderObj->Set_Animation (m_pCAnimation, 0);
CGraphicView *pCGraphicView = GetGraphicView ();
if (pCGraphicView)
{
// Reset the camera to so the user can see
// the whole object
if ((use_global_reset_flag && m_bAutoCameraReset) ||
((use_global_reset_flag == false) && allow_reset) ||
m_bOneTimeReset) {
pCGraphicView->Reset_Camera_To_Display_Object (*m_pCRenderObj);
m_bOneTimeReset = false;
}
AfxGetMainWnd ()->PostMessage (WM_COMMAND, MAKELPARAM (IDM_ANI_START, 0));
}
}
Update_Camera ();
Play_Animation_Sound ();
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Play_Animation_Sound
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Play_Animation_Sound (void)
{
if (m_pCAnimation != NULL) {
CString animation_name = m_pCAnimation->Get_Name ();
//
// Play a sound with the animation
//
const char *separator = ::strchr (animation_name , '.');
if (separator != NULL) {
CString sound_filename = separator + 1;
sound_filename += ".wav";
::PlaySound (NULL, NULL, SND_PURGE);
::PlaySound (sound_filename, NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
}
}
return ;
}
///////////////////////////////////////////////////////////////
//
// PlayAnimation
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::PlayAnimation
(
RenderObjClass *pCModel,
HAnimComboClass *pCAnimCombo,
bool use_global_reset_flag,
bool allow_reset
)
{
ASSERT (m_pCScene);
ASSERT (pCModel);
ASSERT (pCAnimCombo);
// Data OK?
if (m_pCScene &&
pCModel &&
pCAnimCombo)
{
// Display this hierarchy on the screen
DisplayObject (pCModel);
// Get an instance of the animation object
SAFE_DELETE (m_pCAnimCombo);
MEMBER_RELEASE (m_pCAnimation);
m_pCAnimCombo = pCAnimCombo;
m_pCAnimation = m_pCAnimCombo->Get_Motion(0); // ref added by get_motion
ASSERT (m_pCAnimation);
// It will be assumed that every animation in the m_pCAnimCombo
// has the same number of frames and has the same framerate as
// the first animation in the combo (m_pCAnimation).
// Reset the frame counter
m_CurrentFrame = 0;
m_animTime = 0.00F;
if (m_pCRenderObj)
{
// Update the animation frame
for (int i = 0; i < m_pCAnimCombo->Get_Num_Anims(); i++)
m_pCAnimCombo->Set_Frame(i, 0.0f);
m_pCRenderObj->Set_Animation(m_pCAnimCombo);
CGraphicView *pCGraphicView = GetGraphicView ();
if (pCGraphicView)
{
// Reset the camera to so the user can see
// the whole object
if ((use_global_reset_flag && m_bAutoCameraReset) ||
((use_global_reset_flag == false) && allow_reset) ||
m_bOneTimeReset) {
pCGraphicView->Reset_Camera_To_Display_Object (*m_pCRenderObj);
m_bOneTimeReset = false;
}
AfxGetMainWnd ()->PostMessage (WM_COMMAND, MAKELPARAM (IDM_ANI_START, 0));
}
}
Update_Camera ();
Play_Animation_Sound ();
}
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Get_Camera_Transform
//
////////////////////////////////////////////////////////////////////////////
bool
Get_Camera_Transform (RenderObjClass *render_obj, Matrix3D &tm)
{
bool retval = false;
if (render_obj != NULL) {
for (int index = 0; (index < render_obj->Get_Num_Sub_Objects ()) && !retval; index ++) {
RenderObjClass *psub_obj = render_obj->Get_Sub_Object (index);
if (psub_obj != NULL) {
retval = Get_Camera_Transform (psub_obj, tm);
}
MEMBER_RELEASE (psub_obj);
}
if (!retval) {
int index = render_obj->Get_Bone_Index ("CAMERA");
if (index > 0) {
tm = render_obj->Get_Bone_Transform (index);
retval = true;
}
}
}
return retval;
}
///////////////////////////////////////////////////////////////
//
// Update_Camera
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Update_Camera (void)
{
// Should we update the camera's position as well?
if (m_bAnimateCamera && m_pCRenderObj != NULL) {
Matrix3D transform (1);
if (Get_Camera_Transform (m_pCRenderObj, transform)) {
// Convert the bone's transform into a camera transform
//Matrix3D transform = m_pCRenderObj->Get_Bone_Transform (index);
Matrix3D cam_transform (Vector3 (0, -1, 0), Vector3 (0, 0, 1), Vector3 (-1, 0, 0), Vector3 (0, 0, 0));
Matrix3D new_transform = transform * cam_transform;
// Pass the new transform onto the camera
CameraClass *pcamera = GetGraphicView()->GetCamera ();
pcamera->Set_Transform (new_transform);
}
}
return ;
}
///////////////////////////////////////////////////////////////
//
// UpdateFrame
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::UpdateFrame (float relativeTimeSlice)
{
if (m_pCRenderObj && m_pCAnimation) {
int total_frames = m_pCAnimation->Get_Num_Frames ();
float frame_rate = m_pCAnimation->Get_Frame_Rate ();
float loop_time = ((float)(total_frames-1)) / frame_rate;
//
// Update the total elapsed animation time
//
m_animTime += relativeTimeSlice;
if (m_animTime > loop_time) {
m_animTime -= loop_time;
}
// Adjust the current frame counter
m_CurrentFrame = (frame_rate * m_animTime);
//
// Update the status bar on the main window
//
float anim_speed = ::Get_Graphic_View ()->GetAnimationSpeed ();
((CMainFrame *)::AfxGetMainWnd ())->UpdateFrameCount (m_CurrentFrame, total_frames - 1, frame_rate * anim_speed);
if (m_pCAnimCombo) {
//
// Update the animation frame for all anims in the combo.
//
for (int i = 0; i < m_pCAnimCombo->Get_Num_Anims(); i++) {
m_pCAnimCombo->Set_Frame(i, m_CurrentFrame);
}
m_pCRenderObj->Set_Animation (m_pCAnimCombo);
} else if (m_bAnimBlend) {
m_pCRenderObj->Set_Animation (m_pCAnimation, m_CurrentFrame);
} else {
m_pCRenderObj->Set_Animation (m_pCAnimation, (int)m_CurrentFrame);
}
Update_Camera ();
}
return ;
}
///////////////////////////////////////////////////////////////
//
// GetDataTreeView
//
///////////////////////////////////////////////////////////////
CDataTreeView *
CW3DViewDoc::GetDataTreeView (void)
{
CDataTreeView *pCDataTreeView = NULL;
// Get a pointer to the main window
CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
if (pCMainWnd)
{
// Get the pane from the main window
pCDataTreeView = (CDataTreeView *)pCMainWnd->GetPane (0, 0);
}
// Return a pointer to the tree view
return pCDataTreeView;
}
///////////////////////////////////////////////////////////////
//
// GetGraphicView
//
///////////////////////////////////////////////////////////////
CGraphicView *
CW3DViewDoc::GetGraphicView (void)
{
CGraphicView *pCGrephicView = NULL;
// Get a pointer to the main window
CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
if (pCMainWnd)
{
// Get the pane from the main window
pCGrephicView = (CGraphicView *)pCMainWnd->GetPane (0, 1);
}
// Return a pointer to the graphic view
return pCGrephicView;
}
///////////////////////////////////////////////////////////////
//
// GenerateLOD
//
///////////////////////////////////////////////////////////////
HLodPrototypeClass *
CW3DViewDoc::GenerateLOD
(
LPCTSTR pszLODBaseName,
LOD_NAMING_TYPE type
)
{
// Assume failure
HLodPrototypeClass *plod_prototype = NULL;
// Get an iterator from the asset manager that we can
// use to enumerate the currently loaded assets
RenderObjIterator *pObjEnum = WW3DAssetManager::Get_Instance()->Create_Render_Obj_Iterator ();
ASSERT (pObjEnum);
if (pObjEnum)
{
int lod_count = 0;
int iStartingIndex = 0xFFFF;
char starting_char = 'Z';
// Loop through all the assets in the manager looking for hierarchies that match the
// naming convention
for (pObjEnum->First ();
pObjEnum->Is_Done () == FALSE;
pObjEnum->Next ()) {
LPCTSTR pszItemName = pObjEnum->Current_Item_Name ();
// Is this a hierarchy?
if (WW3DAssetManager::Get_Instance()->Render_Obj_Exists (pszItemName) &&
(pObjEnum->Current_Item_Class_ID () == RenderObjClass::CLASSID_HLOD)) {
if (Is_Model_Part_of_LOD (pszItemName, pszLODBaseName, type)) {
lod_count ++;
if (type == TYPE_COMMANDO) {
iStartingIndex = min (iStartingIndex, ::atoi (&pszItemName[::lstrlen (pszItemName)-1]));
} else {
starting_char = min (starting_char, (char)::toupper (pszItemName[::lstrlen (pszItemName)-1]));
}
}
}
}
// Create an array of LOD models
RenderObjClass **plod_array = new RenderObjClass *[lod_count];
ASSERT (plod_array != NULL);
if (plod_array != NULL) {
// Loop through all the levels-of-detail and add them to our array
for (int lod_index = 0; lod_index < lod_count; lod_index ++) {
CString lod_name;
if (type == TYPE_COMMANDO) {
lod_name.Format ("%sL%d", pszLODBaseName, iStartingIndex + lod_index);
} else {
lod_name.Format ("%s%c", pszLODBaseName, starting_char++);
}
// Add this lod to the array in reverse order (LOD 0 is the lowest-level LOD)
plod_array[lod_count - (lod_index+1)] = WW3DAssetManager::Get_Instance ()->Create_Render_Obj (lod_name);
}
// Create a new HLod prototype from the provided lod array
HLodClass *pnew_lod = new HLodClass (pszLODBaseName, plod_array, lod_count);
HLodDefClass *pdefinition = new HLodDefClass (*pnew_lod);
plod_prototype = new HLodPrototypeClass (pdefinition);
MEMBER_RELEASE (pnew_lod);
// Loop through all the LOD definitions and free their names
for (lod_index = 0; lod_index < lod_count; lod_index ++) {
MEMBER_RELEASE (plod_array[lod_index]);
}
// Free the LOD definition array
SAFE_DELETE_ARRAY (plod_array);
}
SAFE_DELETE (pObjEnum);
}
// Return the LOD prototype to the caller
return plod_prototype;
}
///////////////////////////////////////////////////////////////
//
// SetBackgroundBMP
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::SetBackgroundBMP (LPCTSTR pszBackgroundBMP)
{
ASSERT (m_pC2DScene);
if (m_pC2DScene)
{
// Remove the old background BMP if there was one.
if (m_pCBackgroundBMP)
{
// Remove the background BMP from the scene
// and release its pointer
m_pCBackgroundBMP->Remove ();
m_pCBackgroundBMP->Release_Ref ();
m_pCBackgroundBMP = NULL;
}
// Is this a new background BMP?
if (pszBackgroundBMP &&
(m_stringBackgroundBMP.CompareNoCase (pszBackgroundBMP) != 0))
{
// Create a new instance of the BMP object to use
m_pCBackgroundBMP = new Bitmap2DObjClass (pszBackgroundBMP, 0.5F, 0.5F, TRUE, FALSE);
// Were we successful in creating the bitmap object?
ASSERT (m_pCBackgroundBMP);
if (m_pCBackgroundBMP)
{
// Add the object to the scene
m_pC2DScene->Add_Render_Object (m_pCBackgroundBMP);
}
}
// Remember what our current background BMP is
m_stringBackgroundBMP = pszBackgroundBMP;
}
return ;
}
///////////////////////////////////////////////////////////////
//
// LoadSettings
//
///////////////////////////////////////////////////////////////
BOOL
CW3DViewDoc::LoadSettings (LPCTSTR filename)
{
// Assume failure
BOOL bReturn = FALSE;
// Params OK?
ASSERT (filename != NULL);
if (filename != NULL) {
// Open the INI file
FileClass * pini_file = _TheFileFactory->Get_File (filename);
INIClass ini_obj (*pini_file);
CGraphicView *graphic_view = GetGraphicView ();
Vector3 color;
//
// Ambient light color
//
if (ini_obj.Is_Present ("Settings", "AmbientLightR") &&
ini_obj.Is_Present ("Settings", "AmbientLightG") &&
ini_obj.Is_Present ("Settings", "AmbientLightB")) {
// Read the settings from,the INI file
color.X = ini_obj.Get_Float ("Settings", "AmbientLightR");
color.Y = ini_obj.Get_Float ("Settings", "AmbientLightG");
color.Z = ini_obj.Get_Float ("Settings", "AmbientLightB");
// Pass the ambient light color onto the scene
m_pCScene->Set_Ambient_Light (color);
}
//
// Scene light color
//
if (ini_obj.Is_Present ("Settings", "SceneLightR") &&
ini_obj.Is_Present ("Settings", "SceneLightG") &&
ini_obj.Is_Present ("Settings", "SceneLightB")) {
// Read the settings from,the INI file
color.X = ini_obj.Get_Float ("Settings", "SceneLightR");
color.Y = ini_obj.Get_Float ("Settings", "SceneLightG");
color.Z = ini_obj.Get_Float ("Settings", "SceneLightB");
// Pass the scene light color onto the light
m_pCSceneLight->Set_Diffuse (color);
m_pCSceneLight->Set_Specular (color);
}
//
// Scene light orientation
//
if (ini_obj.Is_Present ("Settings", "SceneLightX") &&
ini_obj.Is_Present ("Settings", "SceneLightY") &&
ini_obj.Is_Present ("Settings", "SceneLightZ") &&
ini_obj.Is_Present ("Settings", "SceneLightW")) {
// Read the settings from,the INI file
Quaternion orientation;
orientation.X = ini_obj.Get_Float ("Settings", "SceneLightX");
orientation.Y = ini_obj.Get_Float ("Settings", "SceneLightY");
orientation.Z = ini_obj.Get_Float ("Settings", "SceneLightZ");
orientation.W = ini_obj.Get_Float ("Settings", "SceneLightW");
// Get the light's transform and inverse transform
Vector3 obj_pos = graphic_view->Get_Object_Center ();
Vector3 light_pos = m_pCSceneLight->Get_Position ();
float distance = (light_pos - obj_pos).Length ();
// Move the light to the object's center, perform the rotation, and
Matrix3D light_tm (1);
light_tm.Set_Translation (obj_pos);
Matrix3D::Multiply (light_tm, Build_Matrix3D (orientation), &light_tm);
light_tm.Translate (Vector3 (0, 0, distance));
// Pass the new transform onto the light
RenderObjClass *pLightMesh = graphic_view->Get_Light_Mesh ();
pLightMesh->Set_Transform (light_tm);
m_pCSceneLight->Set_Transform (light_tm);
}
//
// Scene light distance, intensity, and attenuation
//
if (ini_obj.Is_Present ("Settings", "SceneLightDistance") &&
ini_obj.Is_Present ("Settings", "SceneLightIntensity") &&
ini_obj.Is_Present ("Settings", "SceneLightAttenStart") &&
ini_obj.Is_Present ("Settings", "SceneLightAttenEnd") &&
ini_obj.Is_Present ("Settings", "SceneLightAttenOn")) {
// Read the settings from,the INI file
float distance = ini_obj.Get_Float ("Settings", "SceneLightDistance");
float intensity = ini_obj.Get_Float ("Settings", "SceneLightIntensity");
float start = ini_obj.Get_Float ("Settings", "SceneLightAttenStart");
float end = ini_obj.Get_Float ("Settings", "SceneLightAttenEnd");
int atten_on = ini_obj.Get_Int ("Settings", "SceneLightAttenOn");
// Pass the intensity and attenuation settings onto the light
m_pCSceneLight->Set_Intensity (intensity);
m_pCSceneLight->Set_Far_Attenuation_Range (start, end);
m_pCSceneLight->Set_Flag (LightClass::FAR_ATTENUATION, (atten_on == 1));
// Get the position of the light and the displayed object
Vector3 obj_pos = graphic_view->Get_Object_Center ();
Vector3 light_pos = m_pCSceneLight->Get_Position ();
Vector3 new_pos = (light_pos - obj_pos);
new_pos.Normalize ();
new_pos = new_pos * distance;
// Pass the new position onto the light
RenderObjClass *pLightMesh = graphic_view->Get_Light_Mesh ();
pLightMesh->Set_Position (new_pos);
m_pCSceneLight->Set_Position (new_pos);
}
//
// Background color
//
if (ini_obj.Is_Present ("Settings", "BackgroundR") &&
ini_obj.Is_Present ("Settings", "BackgroundG") &&
ini_obj.Is_Present ("Settings", "BackgroundB")) {
// Read the settings from,the INI file
color.X = ini_obj.Get_Float ("Settings", "BackgroundR");
color.Y = ini_obj.Get_Float ("Settings", "BackgroundG");
color.Z = ini_obj.Get_Float ("Settings", "BackgroundB");
// Record the background color for later use
SetBackgroundColor (color);
}
//
// Background bitmap
//
if (ini_obj.Is_Present ("Settings", "BackgroundBMP")) {
// Load this background BMP
TCHAR bmp_filename[MAX_PATH];
ini_obj.Get_String ("Settings", "BackgroundBMP", "", bmp_filename, sizeof (bmp_filename));
SetBackgroundBMP (bmp_filename);
}
//
// Fog Settings
//
if (ini_obj.Is_Present ("Settings", "FogEnabled")) {
bool enable = ini_obj.Get_Bool ("Settings", "FogEnabled");
EnableFog(enable);
}
// Close the INI file
_TheFileFactory->Return_File (pini_file);
}
// Return the TRUE/FALSE result code
return bReturn;
}
///////////////////////////////////////////////////////////////
//
// SaveSettings
//
///////////////////////////////////////////////////////////////
BOOL
CW3DViewDoc::SaveSettings
(
LPCTSTR pszFilename,
DWORD dwSettingsMask
)
{
// Assume failure
BOOL bReturn = FALSE;
ASSERT (pszFilename);
ASSERT (dwSettingsMask != 0L);
ASSERT (m_pCScene);
// Is the filename OK?
HANDLE hFile = ::CreateFile (pszFilename,
0,
0,
NULL,
OPEN_ALWAYS,
0L,
NULL);
ASSERT (hFile != NULL);
if (hFile == NULL)
{
// Invalid file, let the user know
::AfxGetMainWnd ()->MessageBox ("Unable to open file for writing. Please select another filename.", "File Error", MB_ICONERROR | MB_OK);
}
else if (pszFilename &&
(dwSettingsMask != 0L) &&
(m_pCScene != NULL))
{
CString stringCompleteFilename = pszFilename;
// Does this filename contain a path?
if (::strrchr (pszFilename, '\\') == NULL)
{
// Add the current directories path to the filename
TCHAR szPath[MAX_PATH] = { 0 };
::GetCurrentDirectory (sizeof (szPath), szPath);
if (szPath[::lstrlen (szPath)-1] != '\\')
{
// Ensure the path is directory delimited
::strcat (szPath, "\\");
}
// Prepend the filename with its new path
stringCompleteFilename = CString (szPath) + stringCompleteFilename;
}
// Should we save light settings?
if (dwSettingsMask & SAVE_SETTINGS_LIGHT)
{
Vector3 colorSettings = m_pCScene->Get_Ambient_Light ();
// Write the 'Red' component out to the file
CString stringValue;
stringValue.Format ("%f", colorSettings.X);
::WritePrivateProfileString ("Settings",
"AmbientLightR",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the 'Green' component out to the file
stringValue.Format ("%f", colorSettings.Y);
::WritePrivateProfileString ("Settings",
"AmbientLightG",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the 'Blue' component out to the file
stringValue.Format ("%f", colorSettings.Z);
::WritePrivateProfileString ("Settings",
"AmbientLightB",
stringValue,
(LPCTSTR)stringCompleteFilename);
m_pCSceneLight->Get_Diffuse (&colorSettings);
// Write the 'Red' component out to the file
stringValue.Format ("%f", colorSettings.X);
::WritePrivateProfileString ("Settings",
"SceneLightR",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the 'Green' component out to the file
stringValue.Format ("%f", colorSettings.Y);
::WritePrivateProfileString ("Settings",
"SceneLightG",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the 'Blue' component out to the file
stringValue.Format ("%f", colorSettings.Z);
::WritePrivateProfileString ("Settings",
"SceneLightB",
stringValue,
(LPCTSTR)stringCompleteFilename);
Matrix3D transform = m_pCSceneLight->Get_Transform ();
Quaternion orientation = ::Build_Quaternion (transform);
// Write the x-position out to the file
stringValue.Format ("%f", orientation.X);
::WritePrivateProfileString ("Settings",
"SceneLightX",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the y-position out to the file
stringValue.Format ("%f", orientation.Y);
::WritePrivateProfileString ("Settings",
"SceneLightY",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the z-position out to the file
stringValue.Format ("%f", orientation.Z);
::WritePrivateProfileString ("Settings",
"SceneLightZ",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the w-position out to the file
stringValue.Format ("%f", orientation.W);
::WritePrivateProfileString ("Settings",
"SceneLightW",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Get the light's transform and inverse transform
CGraphicView *pCGraphicView = GetGraphicView ();
Vector3 obj_pos = pCGraphicView->Get_Object_Center ();
Vector3 light_pos = m_pCSceneLight->Get_Position ();
float distance = (light_pos - obj_pos).Length ();
// Write the distance out to the file
stringValue.Format ("%f", distance);
::WritePrivateProfileString ("Settings",
"SceneLightDistance",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the intensity out to the file
float intensity = m_pCSceneLight->Get_Intensity ();
stringValue.Format ("%f", intensity);
::WritePrivateProfileString ("Settings",
"SceneLightIntensity",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the start attenuation out to the file
double start = 0;
double end = 0;
m_pCSceneLight->Get_Far_Attenuation_Range (start, end);
stringValue.Format ("%f", start);
::WritePrivateProfileString ("Settings",
"SceneLightAttenStart",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the end attenuation out to the file
stringValue.Format ("%f", end);
::WritePrivateProfileString ("Settings",
"SceneLightAttenEnd",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the end attenuation out to the file
BOOL atten_on = m_pCSceneLight->Get_Flag (LightClass::FAR_ATTENUATION);
stringValue.Format ("%d", atten_on);
::WritePrivateProfileString ("Settings",
"SceneLightAttenOn",
stringValue,
(LPCTSTR)stringCompleteFilename);
}
// Should we save background settings?
if (dwSettingsMask & SAVE_SETTINGS_BACK)
{
// Write the 'Red' component out to the file
CString stringValue;
stringValue.Format ("%f", m_backgroundColor.X);
::WritePrivateProfileString ("Settings",
"BackgroundR",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the 'Green' component out to the file
stringValue.Format ("%f", m_backgroundColor.Y);
::WritePrivateProfileString ("Settings",
"BackgroundG",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the 'Blue' component out to the file
stringValue.Format ("%f", m_backgroundColor.Z);
::WritePrivateProfileString ("Settings",
"BackgroundB",
stringValue,
(LPCTSTR)stringCompleteFilename);
// Write the BMP filename out to the profile
::WritePrivateProfileString ("Settings",
"BackgroundBMP",
(LPCTSTR)m_stringBackgroundBMP,
(LPCTSTR)stringCompleteFilename);
// Write the fog settings out to the file.
::WritePrivateProfileString("Settings",
"FogEnabled",
IsFogEnabled() ? "true" : "false",
(LPCTSTR)stringCompleteFilename);
}
// Should we save camera settings?
if (dwSettingsMask & SAVE_SETTINGS_CAMERA)
{
}
// Success!
bReturn = TRUE;
}
// Return the TRUE/FALSE result code
return bReturn;
}
///////////////////////////////////////////////////////////////
//
// Save_Selected_LOD
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Selected_LOD (void)
{
// Assume failure
bool retval = false;
// Is this an emitter?
if ((m_pCRenderObj != NULL) &&
m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_HLOD) {
// Build the default filename from the name of the LOD
CString default_filename = GetDataTreeView ()->GetCurrentSelectionName ();
default_filename += ".w3d";
RestrictedFileDialogClass dialog (FALSE,
".w3d",
(LPCTSTR)default_filename,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
"Westwood 3D Files (*.w3d)|*.~xyzabc||",
AfxGetMainWnd ());
// Ask the user what filename they wish to save as.
dialog.m_ofn.lpstrTitle = "Export LOD";
if (dialog.DoModal () == IDOK) {
// Save the LOD to the requested file
retval = Save_Current_LOD (dialog.GetPathName ());
}
}
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Save_Current_LOD
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Current_LOD (const CString &filename)
{
// Assume failure
bool retval = false;
// Get the prototype for this aggregate
HLodPrototypeClass *proto = NULL;
proto = (HLodPrototypeClass *)WW3DAssetManager::Get_Instance ()->Find_Prototype (m_pCRenderObj->Get_Name ());
ASSERT (proto != NULL);
if (proto != NULL) {
// Get the definition from the prototype
HLodDefClass *pdefinition = proto->Get_Definition ();
ASSERT (pdefinition != NULL);
if (pdefinition != NULL) {
// Get a file object for the new file
FileClass *pfile = _TheFileFactory->Get_File (filename);
if (pfile) {
// Open the file for writing
pfile->Open (FileClass::WRITE);
// Save the definition to the file
ChunkSaveClass save_chunk (pfile);
retval = (pdefinition->Save (save_chunk) == WW3D_ERROR_OK);
// Close the file
pfile->Close ();
_TheFileFactory->Return_File (pfile);
}
}
}
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// SetBackgroundObject
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::SetBackgroundObject (LPCTSTR pszBackgroundObjectName)
{
// State valid?
ASSERT (m_pCBackObjectScene);
ASSERT (m_pCBackObjectCamera);
if (m_pCBackObjectScene && m_pCBackObjectCamera)
{
// Did we have an old background object we needed to remove?
if (m_pCBackgroundObject)
{
// Remove the object from the scene
m_pCBackgroundObject->Remove ();
// Free the object
m_pCBackgroundObject->Release_Ref ();
m_pCBackgroundObject = NULL;
}
if (pszBackgroundObjectName)
{
// Create a new instance of the render object to use as the background
m_pCBackgroundObject = WW3DAssetManager::Get_Instance()->Create_Render_Obj (pszBackgroundObjectName);
ASSERT (m_pCBackgroundObject);
if (m_pCBackgroundObject)
{
// Place the object at world center
m_pCBackgroundObject->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
// Calculate the depth the camera should be at by the objects bouding sphere
float cameraDepth = m_pCBackgroundObject->Get_Bounding_Sphere ().Radius * 4.0F;
CGraphicView *pCGraphicView = GetGraphicView ();
if (pCGraphicView)
{
// Set the camera's rotation
m_pCBackObjectCamera->Set_Transform (pCGraphicView->GetCamera ()->Get_Transform ());
}
// Set the camera's position and depth
m_pCBackObjectCamera->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
//m_pCBackObjectCamera->Set_Depth (cameraDepth);
m_pCBackObjectCamera->Set_Clip_Planes (1, cameraDepth);
// Add the background object to the scene
m_pCBackObjectScene->Add_Render_Object (m_pCBackgroundObject);
}
}
// Remember this for later...
m_stringBackgroundObject = pszBackgroundObjectName;
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Remove_Object_From_Scene
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Remove_Object_From_Scene (RenderObjClass *prender_obj)
{
// If the render object is NULL, then remove the current render object
if (prender_obj == NULL) {
prender_obj = m_pCRenderObj;
}
// Recursively remove objects from the scene (to make sure we get all particle buffers)
//for (int index = 0; index < prender_obj->Get_Num_Sub_Objects (); index ++) {
while (prender_obj->Get_Num_Sub_Objects () > 0) {
RenderObjClass *psub_obj = prender_obj->Get_Sub_Object (0);
if (psub_obj != NULL) {
Remove_Object_From_Scene (psub_obj);
}
MEMBER_RELEASE (psub_obj);
}
// If this is an emitter, then remove its buffer
if ((prender_obj != NULL) &&
prender_obj->Class_ID () == RenderObjClass::CLASSID_PARTICLEEMITTER) {
// Attempt to remove this emitter's buffer
((ParticleEmitterClass *)prender_obj)->Stop ();
((ParticleEmitterClass *)prender_obj)->Remove_Buffer_From_Scene ();
((ParticleEmitterClass *)prender_obj)->Buffer_Scene_Not_Needed ();
}
// Remove the render object from the scene (if we have a valid scene)
if (m_pCScene != NULL) {
prender_obj->Remove ();
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Save_Selected_Primitive
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Selected_Primitive (void)
{
// Assume failure
bool retval = false;
// Is this an emitter?
if ((m_pCRenderObj != NULL) &&
(m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_SPHERE ||
m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_RING)) {
// Build the default filename from the name of the emitter
CString default_filename = GetDataTreeView ()->GetCurrentSelectionName ();
default_filename += ".w3d";
RestrictedFileDialogClass dialog (FALSE,
".w3d",
(LPCTSTR)default_filename,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
"Westwood 3D Files (*.w3d)|*.~xyzabc||",
AfxGetMainWnd ());
if (m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_SPHERE) {
dialog.m_ofn.lpstrTitle = "Export Sphere";
} else {
dialog.m_ofn.lpstrTitle = "Export Ring";
}
// Ask the user what filename they wish to save as.
if (dialog.DoModal () == IDOK) {
// Save the emitter to the requested file
if (m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_SPHERE) {
retval = Save_Current_Sphere (dialog.GetPathName ());
} else {
retval = Save_Current_Ring (dialog.GetPathName ());
}
}
}
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Save_Current_Sphere
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Current_Sphere (const CString &filename)
{
// Assume failure
bool retval = false;
//
// Get the prototype for this object
//
SpherePrototypeClass *proto = NULL;
proto = (SpherePrototypeClass *)WW3DAssetManager::Get_Instance ()->Find_Prototype (m_pCRenderObj->Get_Name ());
ASSERT (proto != NULL);
if (proto != NULL) {
//
// Get a file object for the new file
//
FileClass *file = _TheFileFactory->Get_File (filename);
if (file) {
// Open the file for writing
file->Open (FileClass::WRITE);
// Save the definition to the file
ChunkSaveClass csave (file);
proto->Save (csave);
retval = true;
// Close the file
file->Close ();
_TheFileFactory->Return_File (file);
}
}
return retval;
}
///////////////////////////////////////////////////////////////
//
// Save_Current_Ring
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Current_Ring (const CString &filename)
{
// Assume failure
bool retval = false;
//
// Get the prototype for this object
//
RingPrototypeClass *proto = NULL;
proto = (RingPrototypeClass *)WW3DAssetManager::Get_Instance ()->Find_Prototype (m_pCRenderObj->Get_Name ());
ASSERT (proto != NULL);
if (proto != NULL) {
//
// Get a file object for the new file
//
FileClass *file = _TheFileFactory->Get_File (filename);
if (file) {
// Open the file for writing
file->Open (FileClass::WRITE);
// Save the definition to the file
ChunkSaveClass csave (file);
proto->Save (csave);
retval = true;
// Close the file
file->Close ();
_TheFileFactory->Return_File (file);
}
}
return retval;
}
///////////////////////////////////////////////////////////////
//
// Save_Selected_Emitter
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Selected_Emitter (void)
{
// Assume failure
bool retval = false;
// Is this an emitter?
if ((m_pCRenderObj != NULL) &&
m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_PARTICLEEMITTER) {
// Build the default filename from the name of the emitter
CString default_filename = GetDataTreeView ()->GetCurrentSelectionName ();
default_filename += ".w3d";
RestrictedFileDialogClass dialog (FALSE,
".w3d",
(LPCTSTR)default_filename,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
"Westwood 3D Files (*.w3d)|*.~xyzabc||",
AfxGetMainWnd ());
// Ask the user what filename they wish to save as.
dialog.m_ofn.lpstrTitle = "Export Emitter";
if (dialog.DoModal () == IDOK) {
// Save the emitter to the requested file
retval = Save_Current_Emitter (dialog.GetPathName ());
}
}
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Save_Current_Emitter
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Current_Emitter (const CString &filename)
{
// Assume failure
bool retval = false;
// Get the prototype for this aggregate
ParticleEmitterPrototypeClass *proto = NULL;
proto = (ParticleEmitterPrototypeClass *)WW3DAssetManager::Get_Instance ()->Find_Prototype (m_pCRenderObj->Get_Name ());
ASSERT (proto != NULL);
if (proto != NULL) {
// Get the definition from the prototype
ParticleEmitterDefClass *pdefinition = proto->Get_Definition ();
ASSERT (pdefinition != NULL);
if (pdefinition != NULL) {
// Get a file object for the new file
FileClass *pfile = _TheFileFactory->Get_File (filename);
if (pfile) {
// Open the file for writing
pfile->Open (FileClass::WRITE);
// Save the definition to the file
ChunkSaveClass save_chunk (pfile);
retval = (pdefinition->Save_W3D (save_chunk) == WW3D_ERROR_OK);
// Close the file
pfile->Close ();
_TheFileFactory->Return_File (pfile);
}
}
}
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Save_Selected_Sound_Object
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Selected_Sound_Object (void)
{
bool retval = false;
//
// Is this a sound render object?
//
if ((m_pCRenderObj != NULL) &&
m_pCRenderObj->Class_ID () == RenderObjClass::CLASSID_SOUND)
{
//
// Build the default filename from the name of the emitter
//
CString default_filename = GetDataTreeView ()->GetCurrentSelectionName ();
default_filename += ".w3d";
RestrictedFileDialogClass dialog (FALSE,
".w3d",
(LPCTSTR)default_filename,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
"Westwood 3D Files (*.w3d)|*.~xyzabc||",
AfxGetMainWnd ());
//
// Ask the user what filename they wish to save as.
//
dialog.m_ofn.lpstrTitle = "Export Sound Object";
if (dialog.DoModal () == IDOK) {
//
// Save the sound object to the requested file
//
retval = Save_Current_Sound_Object (dialog.GetPathName ());
}
}
return retval;
}
///////////////////////////////////////////////////////////////
//
// Save_Current_Sound_Object
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Current_Sound_Object (const CString &filename)
{
bool retval = false;
//
// Get the prototype for this sound object
//
SoundRenderObjPrototypeClass *proto = NULL;
proto = (SoundRenderObjPrototypeClass *)WW3DAssetManager::Get_Instance ()->Find_Prototype (m_pCRenderObj->Get_Name ());
ASSERT (proto != NULL);
if (proto != NULL) {
//
// Get the definition from the prototype
//
SoundRenderObjDefClass *definition = proto->Peek_Definition ();
ASSERT (definition != NULL);
if (definition != NULL) {
//
// Get a file object for the new file
//
FileClass *file = _TheFileFactory->Get_File (filename);
if (file) {
//
// Open the file for writing
//
file->Open (FileClass::WRITE);
//
// Save the definition to the file
//
ChunkSaveClass csave (file);
retval = (definition->Save_W3D (csave) == WW3D_ERROR_OK);
//
// Close the file
//
file->Close ();
_TheFileFactory->Return_File (file);
}
}
}
return retval;
}
///////////////////////////////////////////////////////////////
//
// Auto_Assign_Bones
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Auto_Assign_Bones (void)
{
if (m_pCRenderObj != NULL) {
bool bupdate_prototype = false;
// Loop through all the bones in this render object
int bone_count = m_pCRenderObj->Get_Num_Bones ();
for (int index = 0; index < bone_count; index ++) {
const char *pbone_name = m_pCRenderObj->Get_Bone_Name (index);
// Attempt to find a render object with the same name as this bone
if (WW3DAssetManager::Get_Instance ()->Render_Obj_Exists (pbone_name)) {
// Add this render object to the bone
RenderObjClass *prender_obj = WW3DAssetManager::Get_Instance ()->Create_Render_Obj (pbone_name);
m_pCRenderObj->Add_Sub_Object_To_Bone (prender_obj, index);
MEMBER_RELEASE (prender_obj);
bupdate_prototype = true;
}
}
if (bupdate_prototype) {
Update_Aggregate_Prototype (*m_pCRenderObj);
}
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Save_Selected_Aggregate
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Selected_Aggregate (void)
{
// Assume failure
bool retval = false;
// Do we have a valid render object?
if (m_pCRenderObj != NULL) {
// Build the default filename from the name of render object
CString default_filename = GetDataTreeView ()->GetCurrentSelectionName ();
default_filename += ".w3d";
RestrictedFileDialogClass dialog (FALSE,
".w3d",
(LPCTSTR)default_filename,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
"Westwood 3D Files (*.w3d)|*.~xyzabc||",
AfxGetMainWnd ());
// Ask the user what filename they wish to save as.
dialog.m_ofn.lpstrTitle = "Export Aggregate";
if (dialog.DoModal () == IDOK) {
// Save the aggregate to the requested file
retval = Save_Current_Aggregate (dialog.GetPathName ());
}
}
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Save_Current_Aggregate
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Save_Current_Aggregate (const CString &filename)
{
// Assume failure
bool retval = false;
// Get the prototype for this aggregate
AggregatePrototypeClass *proto = NULL;
proto = (AggregatePrototypeClass *)WW3DAssetManager::Get_Instance ()->Find_Prototype (m_pCRenderObj->Get_Name ());
ASSERT (proto != NULL);
if (proto != NULL) {
// Get the definition from the prototype
AggregateDefClass *pdefinition = proto->Get_Definition ();
ASSERT (pdefinition != NULL);
if (pdefinition != NULL) {
// Get a file object for the new file
FileClass *pfile = _TheFileFactory->Get_File (filename);
if (pfile) {
// Open the file for writing
pfile->Open (FileClass::WRITE);
// Save the definition to the file
ChunkSaveClass save_chunk (pfile);
retval = (pdefinition->Save_W3D (save_chunk) == WW3D_ERROR_OK);
// Close the file
pfile->Close ();
_TheFileFactory->Return_File (pfile);
}
}
}
// Return the true/false result code
return retval;
}
///////////////////////////////////////////////////////////////
//
// Update_Aggregate_Prototype
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Update_Aggregate_Prototype (RenderObjClass &render_obj)
{
// Build a definition object from the render object
AggregateDefClass *pdefinition = new AggregateDefClass (render_obj);
AggregatePrototypeClass *pprototype = new AggregatePrototypeClass (pdefinition);
// Add this prototype to the asset manager
WW3DAssetManager::Get_Instance ()->Remove_Prototype (pdefinition->Get_Name ());
WW3DAssetManager::Get_Instance ()->Add_Prototype (pprototype);
return ;
}
///////////////////////////////////////////////////////////////
//
// Update_LOD_Prototype
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Update_LOD_Prototype (HLodClass &hlod)
{
// Build a definition object from the render object
HLodDefClass *pdefinition = new HLodDefClass (hlod);
HLodPrototypeClass *pprototype = new HLodPrototypeClass (pdefinition);
// Add this prototype to the asset manager
WW3DAssetManager::Get_Instance ()->Remove_Prototype (pdefinition->Get_Name ());
WW3DAssetManager::Get_Instance ()->Add_Prototype (pprototype);
return ;
}
///////////////////////////////////////////////////////////////
//
// Animate_Camera
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Animate_Camera (bool banimate)
{
m_bAnimateCamera = banimate;
// Restore the camera if we are done animating it
if (m_bAnimateCamera == false) {
::AfxGetMainWnd ()->SendMessage (WM_COMMAND, MAKEWPARAM (IDM_CAMERA_RESET, 0));
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Make_Movie
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Make_Movie (void)
{
// Hide the mouse cursor when we're making a movie.
bool restore_cursor = Is_Cursor_Shown();
Show_Cursor(false);
int i;
CGraphicView *graphic_view= GetGraphicView ();
if (m_pCRenderObj && m_pCAnimation) {
// 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;
}
::SetCurrentDirectory (filename);
// Rewind the animation
if (m_pCAnimCombo)
{
for (i = 0; i < m_pCAnimCombo->Get_Num_Anims(); i++)
m_pCAnimCombo->Set_Frame(i, 0.0f);
m_pCRenderObj->Set_Animation (m_pCAnimCombo);
}
else
m_pCRenderObj->Set_Animation (m_pCAnimation, (int)0);
graphic_view->RepaintView (FALSE);
// Begin our movie
WW3D::Pause_Movie (true);
WW3D::Start_Movie_Capture ("Grab", 30);
WW3D::Pause_Movie (true);
float frames = m_pCAnimation->Get_Num_Frames ();
float frame_inc = m_pCAnimation->Get_Frame_Rate () / 30.0F;
DWORD ticks = 1000 / 30;
// Loop through all the frames of animation
for (float frame = 0; frame <= (frames - 1.0F); frame += frame_inc) {
if (m_pCAnimCombo)
{
for (i = 0; i < m_pCAnimCombo->Get_Num_Anims(); i++)
m_pCAnimCombo->Set_Frame(i, frame);
m_pCRenderObj->Set_Animation (m_pCAnimCombo);
}
else
m_pCRenderObj->Set_Animation (m_pCAnimation, frame);
// Should we be updating the camera?
if (m_bAnimateCamera) {
int index = m_pCRenderObj->Get_Bone_Index ("CAMERA");
if (index != -1) {
// Convert the bone's transform into a camera transform
Matrix3D transform = m_pCRenderObj->Get_Bone_Transform (index);
Matrix3D cam_transform (Vector3 (0, -1, 0), Vector3 (0, 0, 1), Vector3 (-1, 0, 0), Vector3 (0, 0, 0));
Matrix3D new_transform = transform * cam_transform;
// Pass the new transform onto the camera
CameraClass *pcamera = GetGraphicView()->GetCamera ();
pcamera->Set_Transform (new_transform);
}
}
graphic_view->RepaintView (FALSE, ticks);
graphic_view->RepaintView (FALSE, 1);
WW3D::Update_Movie_Capture ();
if (::GetAsyncKeyState (VK_ESCAPE) < 0) {
break;
}
}
// Stop capturing the movie data
WW3D::Stop_Movie_Capture ();
}
// Restore the mouse cursor to its previous visibility state.
Show_Cursor(restore_cursor);
return ;
}
///////////////////////////////////////////////////////////////
//
// Build_Emitter_List
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Build_Emitter_List
(
EmitterInstanceListClass *emitter_list,
LPCTSTR emitter_name,
RenderObjClass *render_obj
)
{
//
// If the render object is NULL, then start from the current render object
//
if (render_obj == NULL) {
render_obj = m_pCRenderObj;
}
//
// Recursively walk through the objects in the scene
//
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) {
Build_Emitter_List (emitter_list, emitter_name, psub_obj);
}
MEMBER_RELEASE (psub_obj);
}
//
// Is this the emitter we are requesting?
//
if ((render_obj != NULL) &&
(render_obj->Class_ID () == RenderObjClass::CLASSID_PARTICLEEMITTER) &&
(::lstrcmpi (emitter_name, render_obj->Get_Name ()) == 0)) {
emitter_list->Add_Emitter ((ParticleEmitterClass *)render_obj);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Show_Cursor
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Show_Cursor (bool onoff)
{
if (m_pCursor == NULL) {
Create_Cursor ();
}
m_pCursor->Set_Hidden (!onoff);
return ;
}
///////////////////////////////////////////////////////////////
//
// Is_Cursor_Shown
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Is_Cursor_Shown (void) const
{
return m_pCursor != NULL && m_pCursor->Is_Not_Hidden_At_All ();
}
///////////////////////////////////////////////////////////////
//
// Set_Cursor
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Set_Cursor (LPCTSTR resource_name)
{
m_pCursor->Set_Texture (::Load_RC_Texture (resource_name));
return ;
}
///////////////////////////////////////////////////////////////
//
// Create_Cursor
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Create_Cursor (void)
{
if (m_pCursor == NULL) {
m_pCursor = new ScreenCursorClass;
m_pCursor->Set_Window (GetGraphicView ()->m_hWnd);
m_pCursor->Set_Texture (::Load_RC_Texture ("cursor.tga"));
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Count_Particles
//
///////////////////////////////////////////////////////////////
int
CW3DViewDoc::Count_Particles (RenderObjClass *render_obj)
{
int count = 0;
//
// If the render object is NULL, then start from the current render object
//
if (render_obj == NULL) {
render_obj = m_pCRenderObj;
}
//
// Recursively walk through the subobjects
//
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) {
count += Count_Particles (psub_obj);
}
MEMBER_RELEASE (psub_obj);
}
// If this is an emitter, then remove its buffer
if (render_obj->Class_ID () == RenderObjClass::CLASSID_PARTICLEEMITTER) {
//
// Add the number of particles in the buffer to the total
//
ParticleEmitterClass *emitter = static_cast<ParticleEmitterClass *> (render_obj);
ParticleBufferClass *buffer = emitter->Peek_Buffer ();
if (buffer != NULL) {
count += buffer->Get_Particle_Count ();
}
}
}
return count;
}
///////////////////////////////////////////////////////////////
//
// Update_Particle_Count
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Update_Particle_Count (void)
{
int particles = Count_Particles ();
((CMainFrame *)::AfxGetMainWnd ())->Update_Particle_Count (particles);
return ;
}
///////////////////////////////////////////////////////////////
//
// Switch_LOD
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Switch_LOD (int increment, RenderObjClass *render_obj)
{
//
// If the render object is NULL, then start from the current render object
//
if (render_obj == NULL) {
render_obj = m_pCRenderObj;
}
//
// Recursively walk through the subobjects
//
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) {
Switch_LOD (increment, psub_obj);
}
MEMBER_RELEASE (psub_obj);
}
//
// If this is an HLOD then switch its LOD
//
if (render_obj->Class_ID () == RenderObjClass::CLASSID_HLOD) {
int current_lod = ((HLodClass *)render_obj)->Get_LOD_Level ();
((HLodClass *)render_obj)->Set_LOD_Level (current_lod + increment);
}
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Toggle_Alternate_Materials
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Toggle_Alternate_Materials(RenderObjClass * render_obj)
{
//
// If the render object is NULL, start from the current render object
//
if (render_obj == NULL) {
render_obj = m_pCRenderObj;
}
if (render_obj != NULL) {
//
// If this is a mesh, toggle the materials
//
if (render_obj->Class_ID() == RenderObjClass::CLASSID_MESH) {
MeshModelClass * mdl = ((MeshClass *)render_obj)->Get_Model();
mdl->Enable_Alternate_Material_Description(!mdl->Is_Alternate_Material_Description_Enabled());
}
//
// Recurse into any children
//
for (int index = 0; index < render_obj->Get_Num_Sub_Objects(); index++) {
RenderObjClass * sub_obj = render_obj->Get_Sub_Object(index);
Toggle_Alternate_Materials(sub_obj);
}
}
return;
}
///////////////////////////////////////////////////////////////
//
// Lookup_Path
//
///////////////////////////////////////////////////////////////
bool
CW3DViewDoc::Lookup_Path (LPCTSTR asset_name, CString &path)
{
bool retval = false;
//
// Loop over every file we've loaded...
//
int counter = m_LoadList.Count ();
while ((counter --) && !retval) {
//
// Does this path contain the W3D this asset came from?
//
CString curr_path = m_LoadList[counter];
CString curr_asset = ::Asset_Name_From_Filename (curr_path);
if (::lstrcmpi (asset_name, curr_asset) == 0) {
path = curr_path;
retval = true;
}
}
return retval;
}
///////////////////////////////////////////////////////////////
//
// Copy_Assets_To_Dir
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Copy_Assets_To_Dir (LPCTSTR directory)
{
CDataTreeView *data_tree = GetDataTreeView ();
SANITY_CHECK ((m_pCRenderObj != NULL && data_tree != NULL)) {
return ;
}
//
// Attempt to locate the file this asset came from
//
LPCTSTR asset_name = data_tree->GetCurrentSelectionName ();
CString filename;
if (Lookup_Path (asset_name, filename)) {
CString src_path = ::Strip_Filename_From_Path (filename);
CString dest_path = directory;
::Delimit_Path (src_path);
::Delimit_Path (dest_path);
//
// Get a list of dependent files from the render object
//
DynamicVectorClass<StringClass> dependency_list;
m_pCRenderObj->Build_Dependency_List (dependency_list);
//
// Loop over the list of dependent files and copy them
// each to the destination directory
//
DynamicVectorClass<CString> copy_failure_list;
int counter = dependency_list.Count ();
while (counter --) {
//
// Determine the source and destination filenames
//
StringClass filename = dependency_list[counter];
CString src_filename = src_path + CString (filename);
CString dest_filename = dest_path + CString (filename);
//
// Copy the file
//
if (::Copy_File (src_filename, dest_filename, true) == false) {
copy_failure_list.Add (src_filename);
}
}
//
// Let the user know if something failed to copy
//
if (copy_failure_list.Count () > 0) {
CString message = "Unable to copy the following files:\r\n\r\n";
counter = copy_failure_list.Count ();
while (counter --) {
message += copy_failure_list[counter];
message += "\r\n";
}
::MessageBox (::AfxGetMainWnd ()->m_hWnd, message, "Copy Failure", MB_ICONERROR | MB_OK);
}
} else {
//
// Let the user know if we were unable to find the asset's W3D file
//
CString message;
message.Format ("Unable to find file for asset: %s.", asset_name);
::MessageBox (::AfxGetMainWnd ()->m_hWnd, message, "File Not Found", MB_ICONEXCLAMATION | MB_OK);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Set_Texture_Path1
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Set_Texture_Path1 (LPCTSTR path)
{
if (m_TexturePath1.CompareNoCase (path) != 0) {
//
// Pass the new search path onto the File Factory
//
if (::lstrlen (path) > 0) {
_TheSimpleFileFactory->Append_Sub_Directory(path);
}
m_TexturePath1 = path;
theApp.WriteProfileString ("Config", "TexturePath1", m_TexturePath1);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Set_Texture_Path2
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Set_Texture_Path2 (LPCTSTR path)
{
if (m_TexturePath2.CompareNoCase (path) != 0) {
//
// Pass the new search path onto Surrender
//
if (::lstrlen (path) > 0) {
_TheSimpleFileFactory->Append_Sub_Directory(path);
}
m_TexturePath2 = path;
theApp.WriteProfileString ("Config", "TexturePath2", m_TexturePath2);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Import_Facial_Animation
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Import_Facial_Animation (const CString &heirarchy_name, const CString &filename)
{
//
// Crate a new text file object that can be used to import the animation
//
TextFileClass *anim_desc_file = new TextFileClass (filename);
if (anim_desc_file->Open () == (int)true) {
//
// Create the new animation and import its data from the text file
//
HMorphAnimClass *new_anim = new HMorphAnimClass;
new_anim->Import (heirarchy_name, *anim_desc_file);
//
// Give the new animation a name
//
CString new_name;
CString animation_name = ::Asset_Name_From_Filename (filename);
animation_name.MakeUpper ();
new_name.Format ("%s.%s", (LPCTSTR)heirarchy_name, (LPCTSTR)animation_name);
new_anim->Set_Name (new_name);
//
// Add this animation to the asset manager
//
WW3DAssetManager::Get_Instance ()->Add_Anim (new_anim);
//
// Save this animation to disk
//
CString directory = ::Strip_Filename_From_Path (filename);
::Delimit_Path (directory);
CString path = directory + animation_name + CString (".w3d");
RawFileClass *animation_file = new RawFileClass (path);
if ( animation_file->Create () == (int)true &&
animation_file->Open (FileClass::WRITE) == (int)true)
{
ChunkSaveClass csave (animation_file);
new_anim->Save_W3D (csave);
animation_file->Close ();
}
SAFE_DELETE (animation_file);
//
// Cleanup
//
anim_desc_file->Close ();
MEMBER_RELEASE (new_anim);
SAFE_DELETE (anim_desc_file);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Get_Current_HTree
//
///////////////////////////////////////////////////////////////
const HTreeClass *
CW3DViewDoc::Get_Current_HTree (void) const
{
const HTreeClass *htree = NULL;
if (m_pCRenderObj != NULL) {
htree = m_pCRenderObj->Get_HTree ();
}
return htree;
}
///////////////////////////////////////////////////////////////
//
// Save_Camera_Settings
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Save_Camera_Settings (void)
{
theApp.WriteProfileInt ("Config", "UseManualFOV", m_ManualFOV);
theApp.WriteProfileInt ("Config", "UseManualClipPlanes", m_ManualClipPlanes);
CGraphicView *graphic_view = ::Get_Graphic_View ();
CameraClass *camera = graphic_view->GetCamera ();
if (camera != NULL) {
double hfov = camera->Get_Horizontal_FOV ();
double vfov = camera->Get_Vertical_FOV ();
float znear = 0;
float zfar = 0;
camera->Get_Clip_Planes (znear, zfar);
CString hfov_string;
CString vfov_string;
CString znear_string;
CString zfar_string;
hfov_string.Format ("%f", hfov);
vfov_string.Format ("%f", vfov);
znear_string.Format ("%f", znear);
zfar_string.Format ("%f", zfar);
theApp.WriteProfileString ("Config", "hfov", hfov_string);
theApp.WriteProfileString ("Config", "vfov", vfov_string);
theApp.WriteProfileString ("Config", "znear", znear_string);
theApp.WriteProfileString ("Config", "zfar", zfar_string);
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Load_Camera_Settings
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Load_Camera_Settings (void)
{
m_ManualFOV = (theApp.GetProfileInt ("Config", "UseManualFOV", 0) == TRUE);
m_ManualClipPlanes = (theApp.GetProfileInt ("Config", "UseManualClipPlanes", 0) == TRUE);
CGraphicView *graphic_view = GetGraphicView ();
if (graphic_view != NULL) {
CameraClass *camera = graphic_view->GetCamera ();
if (camera != NULL) {
//
// Should we load the FOV settings from the registry?
//
if (m_ManualFOV) {
CString hfov_string = theApp.GetProfileString ("Config", "hfov", "0");
CString vfov_string = theApp.GetProfileString ("Config", "vfov", "0");
double hfov = ::atof (hfov_string);
double vfov = ::atof (vfov_string);
camera->Set_View_Plane (hfov, vfov);
}
//
// Should we load the clip planes from the registry?
//
if (m_ManualClipPlanes) {
CString znear_string = theApp.GetProfileString ("Config", "znear", "0.1F");
CString zfar_string = theApp.GetProfileString ("Config", "zfar", "100.0F");
float znear = ::atof (znear_string);
float zfar = ::atof (zfar_string);
camera->Set_Clip_Planes (znear, zfar);
if (m_pCScene != NULL) {
m_pCScene->Set_Fog_Range (znear, zfar);
m_pCScene->Recalculate_Fog_Planes();
}
}
}
}
return ;
}
///////////////////////////////////////////////////////////////
//
// Render_Dazzles
//
///////////////////////////////////////////////////////////////
void
CW3DViewDoc::Render_Dazzles (CameraClass * camera)
{
if (m_pDazzleLayer != NULL) {
m_pDazzleLayer->Render(camera);
}
}
void
CW3DViewDoc::SetBackgroundColor (const Vector3 &backgroundColor)
{
m_backgroundColor = backgroundColor;
// If this assert fires, then we will be getting the background color
// and the fog color out of sync. That would look funky.
ASSERT(m_pCScene);
if (m_pCScene)
m_pCScene->Set_Fog_Color(backgroundColor);
}
void
CW3DViewDoc::EnableFog (bool enable)
{
if (m_pCScene)
{
m_pCScene->Set_Fog_Enable(enable);
m_bFogEnabled = enable;
}
}