889 lines
20 KiB
C++
889 lines
20 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/>.
|
||
|
*/
|
||
|
|
||
|
// LevelEditView.cpp : implementation of the CLevelEditView class
|
||
|
//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "leveledit.h"
|
||
|
#include "leveleditdoc.h"
|
||
|
#include "leveleditview.h"
|
||
|
#include "camera.h"
|
||
|
#include "cameramgr.h"
|
||
|
#include "mainfrm.h"
|
||
|
#include "ww3d.h"
|
||
|
#include "mousemgr.h"
|
||
|
#include "sceneeditor.h"
|
||
|
#include <process.h>
|
||
|
#include "nodemgr.h"
|
||
|
#include "mmsystem.h"
|
||
|
#include "dynamesh.h"
|
||
|
#include "vertmaterial.h"
|
||
|
#include "win.h"
|
||
|
#include "wwaudio.h"
|
||
|
#include "combat.h"
|
||
|
#include "timemgr.h"
|
||
|
#include "gameobjmanager.h"
|
||
|
#include "gameobjobserver.h"
|
||
|
#include "scripts.h"
|
||
|
#include "backgroundmgr.h"
|
||
|
#include "dazzle.h"
|
||
|
#include "phys.h"
|
||
|
#include "weathermgr.h"
|
||
|
#include "soundenvironment.h"
|
||
|
#include "heightfieldeditor.h"
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
// Local Prototypes
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
void CALLBACK fnTimerCallback (UINT, UINT, DWORD, DWORD, DWORD);
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
// Static member initialization
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
int CLevelEditView::_iPaintingLock = 0;
|
||
|
bool CLevelEditView::_bNeedsRepaint = false;
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
// Globals
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
CRITICAL_SECTION _CriticalSection;
|
||
|
|
||
|
|
||
|
IMPLEMENT_DYNCREATE(CLevelEditView, CView)
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CLevelEditView, CView)
|
||
|
//{{AFX_MSG_MAP(CLevelEditView)
|
||
|
ON_WM_SIZE()
|
||
|
ON_WM_CREATE()
|
||
|
ON_WM_LBUTTONDOWN()
|
||
|
ON_WM_LBUTTONUP()
|
||
|
ON_WM_RBUTTONDOWN()
|
||
|
ON_WM_RBUTTONUP()
|
||
|
ON_WM_MOUSEMOVE()
|
||
|
ON_WM_DESTROY()
|
||
|
ON_WM_LBUTTONDBLCLK()
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// CLevelEditView
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
CLevelEditView::CLevelEditView (void)
|
||
|
: m_iDeviceIndex (-1),
|
||
|
m_iBitsPerPixel (16),
|
||
|
m_iWindowed (1),
|
||
|
m_bRenderDeviceInitialized (FALSE),
|
||
|
m_pCameraMgr (NULL),
|
||
|
m_pMouseMgr (NULL),
|
||
|
m_bActive (false),
|
||
|
m_p2DScene (NULL),
|
||
|
m_p2DCamera (NULL),
|
||
|
m_TimerID (0),
|
||
|
m_HorzFOV (0),
|
||
|
m_VertFOV (0),
|
||
|
m_CursorXRatio (1),
|
||
|
m_CursorYRatio (1),
|
||
|
m_hMouseHook (NULL)
|
||
|
{
|
||
|
// Get the windowed mode from the registry
|
||
|
CString string_windowed = theApp.GetProfileString ("Config", "Windowed", "1");
|
||
|
m_iWindowed = ::atoi ((LPCTSTR)string_windowed) || Is_Silent_Mode ();
|
||
|
|
||
|
|
||
|
::InitializeCriticalSection (&_CriticalSection);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// ~CLevelEditView
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
CLevelEditView::~CLevelEditView (void)
|
||
|
{
|
||
|
// If the camera manager exists, free it.
|
||
|
SAFE_DELETE (m_pCameraMgr);
|
||
|
SAFE_DELETE (m_pMouseMgr);
|
||
|
|
||
|
m_pCursorMesh->Remove ();
|
||
|
MEMBER_RELEASE (m_pCursorMesh);
|
||
|
MEMBER_RELEASE (m_p2DScene);
|
||
|
MEMBER_RELEASE (m_p2DCamera);
|
||
|
|
||
|
// Cache this information in the registry
|
||
|
TCHAR temp_string[10];
|
||
|
::itoa (m_iWindowed, temp_string, 10);
|
||
|
theApp.WriteProfileString ("Config", "Windowed", temp_string);
|
||
|
|
||
|
::DeleteCriticalSection (&_CriticalSection);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// PreCreateWindow
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
BOOL
|
||
|
CLevelEditView::PreCreateWindow (CREATESTRUCT& cs)
|
||
|
{
|
||
|
// Allow the base class to process this message
|
||
|
return CView::PreCreateWindow (cs);
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnDraw
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnDraw (CDC* pDC)
|
||
|
{
|
||
|
CLevelEditDoc* doc = GetDocument();
|
||
|
ASSERT_VALID(doc);
|
||
|
|
||
|
// If we are in fullscreen mode, then erase the window background
|
||
|
if (m_iWindowed == 0) {
|
||
|
|
||
|
// Get the client rectangle of the window
|
||
|
RECT rect;
|
||
|
GetClientRect (&rect);
|
||
|
|
||
|
// Erase the background
|
||
|
::FillRect (*pDC, &rect, (HBRUSH)(COLOR_WINDOW + 1));
|
||
|
}
|
||
|
|
||
|
// Ask the view to repaint itself.
|
||
|
Repaint_View ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// MFC Junk
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
#ifdef _DEBUG
|
||
|
void CLevelEditView::AssertValid() const
|
||
|
{
|
||
|
CView::AssertValid();
|
||
|
}
|
||
|
|
||
|
void CLevelEditView::Dump(CDumpContext& dc) const
|
||
|
{
|
||
|
CView::Dump(dc);
|
||
|
}
|
||
|
|
||
|
CLevelEditDoc* CLevelEditView::GetDocument() // non-debug version is inline
|
||
|
{
|
||
|
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CLevelEditDoc)));
|
||
|
return (CLevelEditDoc*)m_pDocument;
|
||
|
}
|
||
|
#endif //_DEBUG
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Initialize_Render_Device
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
CLevelEditView::Initialize_Render_Device (void)
|
||
|
{
|
||
|
::EnterCriticalSection (&_CriticalSection);
|
||
|
|
||
|
// Assume failure
|
||
|
m_bRenderDeviceInitialized = FALSE;
|
||
|
|
||
|
// Initialize the rendering engine with the information from
|
||
|
// this window.
|
||
|
RECT rect;
|
||
|
GetClientRect (&rect);
|
||
|
|
||
|
int cx = rect.right-rect.left;
|
||
|
int cy = rect.bottom-rect.top;
|
||
|
int bpp = m_iBitsPerPixel;
|
||
|
if (m_iWindowed == 0) {
|
||
|
cx = 640;
|
||
|
cy = 480;
|
||
|
bpp = 16;
|
||
|
|
||
|
// Determine what our aspect ratio should be to
|
||
|
// constrain the mouse to the 'window' while in full screen mode.
|
||
|
m_CursorXRatio = cx / ((float)rect.right);
|
||
|
m_CursorYRatio = cy / ((float)rect.bottom);
|
||
|
} else {
|
||
|
m_CursorXRatio = 1.0F;
|
||
|
m_CursorYRatio = 1.0F;
|
||
|
}
|
||
|
|
||
|
// Ask W3D to use this rendering device
|
||
|
m_bRenderDeviceInitialized = (WW3D::Set_Render_Device (m_iDeviceIndex,
|
||
|
cx,
|
||
|
cy,
|
||
|
bpp,
|
||
|
m_iWindowed) == WW3D_ERROR_OK);
|
||
|
|
||
|
ASSERT (m_bRenderDeviceInitialized);
|
||
|
|
||
|
// Create a new camera manager object
|
||
|
if (m_pCameraMgr == NULL) {
|
||
|
m_pCameraMgr = new CameraMgr;
|
||
|
}
|
||
|
|
||
|
// Create a new mouse manager object
|
||
|
if (m_pMouseMgr == NULL) {
|
||
|
m_pMouseMgr = new MouseMgrClass;
|
||
|
}
|
||
|
|
||
|
// Reset the camera's FOV
|
||
|
m_pCameraMgr->Get_Camera ()->Set_View_Plane (m_HorzFOV, m_VertFOV);
|
||
|
|
||
|
if (m_p2DCamera == NULL) {
|
||
|
|
||
|
// Create a new instance of the camera class to use
|
||
|
// when rendering the background BMP
|
||
|
m_p2DCamera = new CameraClass ();
|
||
|
|
||
|
// Were we successful in creating the new instance?
|
||
|
ASSERT (m_p2DCamera != NULL);
|
||
|
if (m_p2DCamera != NULL) {
|
||
|
|
||
|
// Set the default values for the new camera
|
||
|
m_p2DCamera->Set_View_Plane (Vector2 (-1.00F, -1.00F), Vector2 (1.00F, 1.00F));
|
||
|
m_p2DCamera->Set_Position (Vector3 (0.00F, 0.00F, 1.00F));
|
||
|
m_p2DCamera->Set_Clip_Planes (0.1F, 10.0F);
|
||
|
//m_p2DCamera->Set_Position (Vector3 (0.00F, 0.00F, 1.00F));
|
||
|
//m_p2DCamera->Set_Transform (Matrix3D (1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_p2DScene == NULL) {
|
||
|
|
||
|
// Instantiate a new scene
|
||
|
m_p2DScene = new SimpleSceneClass;
|
||
|
|
||
|
// Allocate a new mesh we can use to represent the mouse
|
||
|
//.cursor while in full screen mode
|
||
|
m_pCursorMesh = new DynamicScreenMeshClass (2, 6);
|
||
|
//m_pCursorMesh->Set_Force_Visible (true);
|
||
|
|
||
|
VertexMaterialClass *vmat = new VertexMaterialClass;
|
||
|
|
||
|
vmat->Set_Emissive (1,1,1);
|
||
|
vmat->Set_Diffuse (0,0,0);
|
||
|
|
||
|
m_pCursorMesh->Set_Vertex_Material (vmat);
|
||
|
MEMBER_RELEASE (vmat);
|
||
|
|
||
|
m_pCursorMesh->Begin_Tri_Strip();
|
||
|
|
||
|
m_pCursorMesh->Set_Vertex_Color (Vector3 (0, 0.384F, 0.5F));
|
||
|
m_pCursorMesh->Vertex (0.0F, 0.0F, 0, 0, 0);
|
||
|
m_pCursorMesh->Set_Vertex_Color (Vector3 (0, 0, 0.5F));
|
||
|
m_pCursorMesh->Vertex (0.026F,0.028F, 0, 0, 0);
|
||
|
m_pCursorMesh->Set_Vertex_Color (Vector3 (0, 0.5F, 1));
|
||
|
m_pCursorMesh->Vertex (0.010F,0.024F, 0, 0, 0);
|
||
|
|
||
|
m_pCursorMesh->End_Tri_Strip();
|
||
|
|
||
|
|
||
|
m_pCursorMesh->Begin_Tri_Strip();
|
||
|
|
||
|
m_pCursorMesh->Set_Vertex_Color (Vector3 (0, 0.5F, 1));
|
||
|
m_pCursorMesh->Vertex (0.010F,0.024F, 0, 0, 0);
|
||
|
m_pCursorMesh->Set_Vertex_Color (Vector3 (0.53F, 0.76F, 1));
|
||
|
m_pCursorMesh->Vertex (0.0F, 0.041F, 0, 0, 0);
|
||
|
m_pCursorMesh->Set_Vertex_Color (Vector3 (0, 0.5F, 1));
|
||
|
m_pCursorMesh->Vertex (0.0F, 0.0F, 0, 0, 0);
|
||
|
|
||
|
m_pCursorMesh->End_Tri_Strip();
|
||
|
|
||
|
// Add the cursor to the 2D scene
|
||
|
m_pCursorMesh->Add (m_p2DScene);
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection (&_CriticalSection);
|
||
|
|
||
|
// Return the TRUE/FALSE result code
|
||
|
return m_bRenderDeviceInitialized;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnSize
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnSize
|
||
|
(
|
||
|
UINT nType,
|
||
|
int cx,
|
||
|
int cy
|
||
|
)
|
||
|
{
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnSize (nType, cx, cy);
|
||
|
|
||
|
int bpp = m_iBitsPerPixel;
|
||
|
if (m_iWindowed == 0) {
|
||
|
|
||
|
// Determine what our aspect ratio should be to
|
||
|
// constrain the mouse to the 'window' while in full screen mode.
|
||
|
m_CursorXRatio = 640 / ((float)cx);
|
||
|
m_CursorYRatio = 480 / ((float)cy);
|
||
|
|
||
|
cx = 640;
|
||
|
cy = 480;
|
||
|
bpp = 16;
|
||
|
}
|
||
|
|
||
|
// update the camera FOV settings
|
||
|
// take the larger of the two dimensions, give it the
|
||
|
// full desired FOV, then give the other dimension an
|
||
|
// FOV proportional to its relative size
|
||
|
m_HorzFOV = 0.0F;
|
||
|
m_VertFOV = 0.0F;
|
||
|
if (cy > cx) {
|
||
|
m_VertFOV = (float)DEG_TO_RAD(45.0f);
|
||
|
m_HorzFOV = (double)cx / (double)cy * m_VertFOV;
|
||
|
}
|
||
|
else {
|
||
|
m_HorzFOV = (float)DEG_TO_RAD(45.0f);
|
||
|
m_VertFOV = (double)cy / (double)cx * m_HorzFOV;
|
||
|
}
|
||
|
|
||
|
if (m_bRenderDeviceInitialized) {
|
||
|
|
||
|
if (m_iWindowed == 1) {
|
||
|
// Change the resolution of the rendering device to
|
||
|
// match that of the view's current dimensions
|
||
|
WW3D::Set_Device_Resolution (cx, cy, bpp, m_iWindowed);
|
||
|
}
|
||
|
|
||
|
// Reset the field of view
|
||
|
m_pCameraMgr->Get_Camera ()->Set_View_Plane (m_HorzFOV, m_VertFOV);
|
||
|
|
||
|
// Force a repaint of the screen
|
||
|
Repaint_View ();
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Allow_Repaint
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
CLevelEditView::Allow_Repaint (bool active)
|
||
|
{
|
||
|
// Either increment or decrement the lock
|
||
|
_iPaintingLock += (active ? -1 : 1);
|
||
|
|
||
|
//
|
||
|
// Refresh the view if necessary
|
||
|
//
|
||
|
if ((_iPaintingLock == 0) && _bNeedsRepaint) {
|
||
|
::Refresh_Main_View ();
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Repaint_View
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
CLevelEditView::Repaint_View (void)
|
||
|
{
|
||
|
CLevelEditDoc *doc = (CLevelEditDoc *)GetDocument ();
|
||
|
|
||
|
//
|
||
|
// Make sure separate threads don't try to render at the same time
|
||
|
//
|
||
|
::EnterCriticalSection (&_CriticalSection);
|
||
|
_bNeedsRepaint = false;
|
||
|
|
||
|
//
|
||
|
// Are we in a valid state?
|
||
|
//
|
||
|
WWASSERT (_iPaintingLock >= 0);
|
||
|
if (m_bRenderDeviceInitialized &&
|
||
|
(_iPaintingLock == 0) &&
|
||
|
(doc != NULL) &&
|
||
|
(doc->Get_Scene () != NULL) &&
|
||
|
(::Is_Silent_Mode () == false))
|
||
|
{
|
||
|
_iPaintingLock ++;
|
||
|
|
||
|
//
|
||
|
// Get access to the scene and current render camera
|
||
|
//
|
||
|
SceneEditorClass *scene = ::Get_Scene_Editor ();
|
||
|
CameraClass *camera = scene->Get_Render_Camera ();
|
||
|
|
||
|
//
|
||
|
// Let the game free up anything it needs
|
||
|
//
|
||
|
NetworkObjectMgrClass::Delete_Pending ();
|
||
|
GameObjObserverManager::Delete_Pending ();
|
||
|
ScriptManager::Destroy_Pending ();
|
||
|
|
||
|
//
|
||
|
// Call updates on some of the subsystems
|
||
|
//
|
||
|
WWAudioClass::Get_Instance ()->On_Frame_Update ();
|
||
|
|
||
|
TimeManager::Update ();
|
||
|
((CMainFrame *)::AfxGetMainWnd ())->Update_Poly_Count ();
|
||
|
((CMainFrame *)::AfxGetMainWnd ())->Update_Texture_Mem ();
|
||
|
|
||
|
//
|
||
|
// Let the camera know to update its animation (if any)
|
||
|
//
|
||
|
::Get_Camera_Mgr ()->On_Frame ();
|
||
|
::Get_Scene_Editor ()->On_Frame ();
|
||
|
::Get_Scene_Editor ()->Update_Selection_Boxes ();
|
||
|
|
||
|
// Update some sub-systems.
|
||
|
BackgroundMgrClass::Update (scene, camera);
|
||
|
SoundEnvironmentClass *sound_environment = CombatManager::Get_Sound_Environment ();
|
||
|
if (sound_environment != NULL) sound_environment->Update (scene, camera);
|
||
|
WeatherMgrClass::Update (scene, camera);
|
||
|
|
||
|
//
|
||
|
// Collect visible objects and such...
|
||
|
//
|
||
|
PhysicsSceneClass::Get_Instance ()->Pre_Render_Processing (*camera);
|
||
|
|
||
|
//
|
||
|
// Set-up the rendering process
|
||
|
//
|
||
|
WW3D::Begin_Render (true, true, BackgroundMgrClass::Get_Clear_Color());
|
||
|
|
||
|
//
|
||
|
// Render the background scene from the game (this will give
|
||
|
// us the sky and stuff).
|
||
|
//
|
||
|
WW3D::Render (CombatManager::Get_Background_Scene(), camera);
|
||
|
|
||
|
//
|
||
|
// Now render the main scene
|
||
|
//
|
||
|
WW3D::Render (scene, camera);
|
||
|
|
||
|
//
|
||
|
// Render any heightfield editing gizmos
|
||
|
//
|
||
|
HeightfieldEditorClass::Render ();
|
||
|
|
||
|
//
|
||
|
// Render the dazzle layer (if necessary)
|
||
|
//
|
||
|
DazzleLayerClass *dazzle_layer = CombatManager::Get_Dazzle_Layer ();
|
||
|
if (dazzle_layer != NULL) {
|
||
|
dazzle_layer->Render (camera);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Finish out the rendering process
|
||
|
//
|
||
|
WW3D::End_Render ();
|
||
|
|
||
|
//
|
||
|
// Cleanup the rendering processing
|
||
|
//
|
||
|
PhysicsSceneClass::Get_Instance ()->Post_Render_Processing ();
|
||
|
|
||
|
_iPaintingLock --;
|
||
|
} else {
|
||
|
_bNeedsRepaint = true;
|
||
|
}
|
||
|
|
||
|
::LeaveCriticalSection (&_CriticalSection);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnFinalRelease
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnFinalRelease (void)
|
||
|
{
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnFinalRelease ();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnInitialUpdate
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnInitialUpdate (void)
|
||
|
{
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnInitialUpdate();
|
||
|
|
||
|
// Initialize the render device before we can update the view
|
||
|
if (m_bRenderDeviceInitialized == false) {
|
||
|
Initialize_Render_Device ();
|
||
|
}
|
||
|
|
||
|
if (m_bRenderDeviceInitialized)
|
||
|
{
|
||
|
Start_Update ();
|
||
|
}
|
||
|
|
||
|
//MainWindow = m_hWnd;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Start_Update
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::Start_Update (bool bstart)
|
||
|
{
|
||
|
if (bstart && (m_TimerID == 0)) {
|
||
|
|
||
|
// Kick off a timer that we can use to update
|
||
|
// the display (kinda like a game loop iterator)
|
||
|
m_TimerID = (UINT)::timeSetEvent (50,
|
||
|
50,
|
||
|
fnTimerCallback,
|
||
|
(DWORD)m_hWnd,
|
||
|
TIME_PERIODIC);
|
||
|
|
||
|
} else if ((bstart == false) && (m_TimerID != 0)) {
|
||
|
|
||
|
// Stop the timer
|
||
|
::timeKillEvent ((UINT)m_TimerID);
|
||
|
|
||
|
// We don't need this anymore
|
||
|
m_TimerID = 0;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// fnMouseHookProc
|
||
|
//
|
||
|
LRESULT CALLBACK
|
||
|
fnMouseHookProc
|
||
|
(
|
||
|
int nCode,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
LRESULT result = 0L;
|
||
|
|
||
|
CLevelEditView *pview = ::Get_Main_View ();
|
||
|
if (pview != NULL) {
|
||
|
MOUSEHOOKSTRUCT *pinfo = (MOUSEHOOKSTRUCT *)lParam;
|
||
|
if (pinfo != NULL) {
|
||
|
|
||
|
bool allow_update = pinfo->hwnd == pview->m_hWnd;
|
||
|
if (!allow_update) {
|
||
|
allow_update = (::GetProp (pinfo->hwnd, "ALLOW_UPDATE") != NULL);
|
||
|
if (!allow_update && ::GetParent (pinfo->hwnd)) {
|
||
|
allow_update = (::GetProp (::GetParent (pinfo->hwnd), "ALLOW_UPDATE") != NULL);
|
||
|
}
|
||
|
|
||
|
if ( ::Get_Mouse_Mgr () &&
|
||
|
::Get_Mouse_Mgr ()->Get_Mouse_Mode () == MouseMgrClass::MODE_CAMERA_WALK) {
|
||
|
allow_update = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Start or stop updating the view
|
||
|
pview->Start_Update (allow_update);
|
||
|
}
|
||
|
|
||
|
// Call the next hook in our chain
|
||
|
result = ::CallNextHookEx (::Get_Main_View ()->Get_Hook (), nCode, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnCreate
|
||
|
//
|
||
|
int
|
||
|
CLevelEditView::OnCreate (LPCREATESTRUCT lpCreateStruct)
|
||
|
{
|
||
|
if (CView::OnCreate(lpCreateStruct) == -1)
|
||
|
return -1;
|
||
|
|
||
|
// Let the main window know we want to be the active view
|
||
|
CMainFrame *pwnd = (CMainFrame *)::AfxGetMainWnd ();
|
||
|
if (pwnd) {
|
||
|
pwnd->SetActiveView (this, FALSE);
|
||
|
}
|
||
|
|
||
|
m_hMouseHook = ::SetWindowsHookEx (WH_MOUSE,
|
||
|
fnMouseHookProc,
|
||
|
::AfxGetInstanceHandle (),
|
||
|
::GetCurrentThreadId ());
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnLButtonDown
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnLButtonDown
|
||
|
(
|
||
|
UINT nFlags,
|
||
|
CPoint point
|
||
|
)
|
||
|
{
|
||
|
// Pass this onto the mouse manager
|
||
|
m_pMouseMgr->Handle_LButton_Down (nFlags, point);
|
||
|
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnLButtonDown(nFlags, point);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnLButtonDown
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnLButtonUp
|
||
|
(
|
||
|
UINT nFlags,
|
||
|
CPoint point
|
||
|
)
|
||
|
{
|
||
|
// Pass this onto the mouse manager
|
||
|
m_pMouseMgr->Handle_LButton_Up (nFlags, point);
|
||
|
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnLButtonUp(nFlags, point);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnLButtonDown
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnRButtonDown
|
||
|
(
|
||
|
UINT nFlags,
|
||
|
CPoint point
|
||
|
)
|
||
|
{
|
||
|
// Pass this onto the mouse manager
|
||
|
m_pMouseMgr->Handle_RButton_Down (nFlags, point);
|
||
|
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnRButtonDown (nFlags, point);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnRButtonUp
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnRButtonUp
|
||
|
(
|
||
|
UINT nFlags,
|
||
|
CPoint point
|
||
|
)
|
||
|
{
|
||
|
// Pass this onto the mouse manager
|
||
|
m_pMouseMgr->Handle_RButton_Up (nFlags, point);
|
||
|
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnRButtonUp (nFlags, point);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnMouseMove
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnMouseMove
|
||
|
(
|
||
|
UINT nFlags,
|
||
|
CPoint point
|
||
|
)
|
||
|
{
|
||
|
// Pass this onto the mouse manager
|
||
|
m_pMouseMgr->Handle_Mouse_Move (nFlags, point);
|
||
|
SetFocus ();
|
||
|
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnMouseMove (nFlags, point);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// WindowProc
|
||
|
//
|
||
|
LRESULT
|
||
|
CLevelEditView::WindowProc
|
||
|
(
|
||
|
UINT message,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
// Is this the repaint message we are expecting?
|
||
|
if (message == WM_USER+101)
|
||
|
{
|
||
|
Repaint_View ();
|
||
|
::RemoveProp (m_hWnd, "WaitingToProcess");
|
||
|
}
|
||
|
|
||
|
// Allow the base class to process this message
|
||
|
return CView::WindowProc(message, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnDestroy
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnDestroy (void)
|
||
|
{
|
||
|
// Kill the timer
|
||
|
Start_Update (false);
|
||
|
|
||
|
if (m_hMouseHook != NULL) {
|
||
|
::UnhookWindowsHookEx (m_hMouseHook);
|
||
|
m_hMouseHook = NULL;
|
||
|
}
|
||
|
|
||
|
::RemoveProp (m_hWnd, "WaitingToProcess");
|
||
|
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnDestroy ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Reset_View
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::Reset_View (void)
|
||
|
{
|
||
|
ASSERT (m_pCameraMgr != NULL);
|
||
|
|
||
|
// Re-initialize the camera
|
||
|
m_pCameraMgr->Init_Camera ();
|
||
|
|
||
|
// Reset the mouse mode
|
||
|
m_pMouseMgr->Set_Mouse_Mode (MouseMgrClass::MODE_OBJECT_MANIPULATE);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// fnTimerCallback
|
||
|
//
|
||
|
void CALLBACK
|
||
|
fnTimerCallback
|
||
|
(
|
||
|
UINT uID,
|
||
|
UINT uMsg,
|
||
|
DWORD dwUser,
|
||
|
DWORD dw1,
|
||
|
DWORD dw2
|
||
|
)
|
||
|
{
|
||
|
HWND hwnd = (HWND)dwUser;
|
||
|
if (hwnd != NULL) {
|
||
|
|
||
|
// Send this event off to the view to process (hackish, but fine for now)
|
||
|
if ((GetProp (hwnd, "WaitingToProcess") == NULL) &&
|
||
|
(CLevelEditView::_iPaintingLock == 0))
|
||
|
{
|
||
|
SetProp (hwnd, "WaitingToProcess", (HANDLE)1);
|
||
|
|
||
|
// Send the message to the view so it will be in the
|
||
|
// same thread (Surrender doesn't seem to be thread-safe)
|
||
|
::PostMessage (hwnd, WM_USER+101, 0, 0L);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// OnLButtonDblClk
|
||
|
//
|
||
|
void
|
||
|
CLevelEditView::OnLButtonDblClk
|
||
|
(
|
||
|
UINT nFlags,
|
||
|
CPoint point
|
||
|
)
|
||
|
{
|
||
|
// Pass this onto the mouse manager
|
||
|
m_pMouseMgr->Handle_LButton_Dblclk (nFlags, point);
|
||
|
|
||
|
// Allow the base class to process this message
|
||
|
CView::OnLButtonDown(nFlags, point);
|
||
|
return ;
|
||
|
}
|