3114 lines
84 KiB
C++
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;
|
|
}
|
|
}
|