| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- // GraphicView.cpp : implementation of the CGraphicView class
- //
- #include "stdafx.h"
- #include "PhysTest.h"
- #include "PhysTestDoc.h"
- #include "GraphicView.h"
- #include "MainFrm.h"
- #include "mmsystem.h"
- #include "pscene.h"
- #include "ww3d.h"
- #include "camera.h"
- #include "quat.h"
- #include "rcfile.h"
- #include "assetmgr.h"
- #include "rbody.h"
- #include "chunkio.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- #define ORTHO_CAMERA 0
- #define ORTHO_WIDTH 20
- ////////////////////////////////////////////////////////////////////////////
- //
- // CHUNK ID's used by GraphicView
- //
- enum
- {
- GRAPHICVIEW_CHUNK_VARIABLES = 0x00789931,
- GRAPHICVIEW_VARIABLE_CAMERAMODE = 0x00,
- GRAPHICVIEW_VARIABLE_DISPLAYBOXES,
- GRAPHICVIEW_VARIABLE_RUNSIMULATION,
- GRAPHICVIEW_VARIABLE_CAMERATM,
- };
- const float PIP_VIEW = 0.2f; // size of the pip viewport
- ////////////////////////////////////////////////////////////////////////////
- //
- // TimerCallback
- //
- void CALLBACK TimerCallback
- (
- UINT uID,
- UINT uMsg,
- DWORD dwUser,
- DWORD dw1,
- DWORD dw2
- )
- {
- HWND hwnd = (HWND)dwUser;
- if (IsWindow(hwnd)) {
- // Send this event off to the view to process (hackish, but fine for now)
- if ((GetProp (hwnd, "WaitingToProcess") == NULL) &&
- (GetProp (hwnd, "Inactive") == NULL)) {
- SetProp (hwnd, "WaitingToProcess", (HANDLE)1);
- // Send the message to the view
- ::PostMessage (hwnd, WM_USER + 101, 0, 0L);
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////
- //
- // WindowProc
- //
- LRESULT CGraphicView::WindowProc
- (
- UINT message,
- WPARAM wParam,
- LPARAM lParam
- )
- {
- // Is this the repaint message we are expecting?
- if (message == WM_USER+101) {
- Timestep();
- Repaint_View();
- RemoveProp(m_hWnd,"WaitingToProcess");
- }
- // Allow the base class to process this message
- return CView::WindowProc(message, wParam, lParam);
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGraphicView
- IMPLEMENT_DYNCREATE(CGraphicView, CView)
- BEGIN_MESSAGE_MAP(CGraphicView, CView)
- //{{AFX_MSG_MAP(CGraphicView)
- ON_WM_SIZE()
- ON_WM_DESTROY()
- ON_WM_LBUTTONDOWN()
- ON_WM_LBUTTONUP()
- ON_WM_RBUTTONDOWN()
- ON_WM_RBUTTONUP()
- ON_WM_MOUSEMOVE()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- /////////////////////////////////////////////////////////////////////////////
- // CGraphicView construction/destruction
- CGraphicView::CGraphicView() :
- Initialized(false),
- Active(true),
- RunSimulation(false),
- DisplayBoxes(false),
- CameraMode(CAMERA_FLY),
- Camera(NULL),
- TimerID(0),
- LMouseDown(false),
- RMouseDown(false),
- LastPoint(0,0),
- PipCamera(NULL),
- PipScene(NULL),
- Axes(NULL)
- {
- }
- CGraphicView::~CGraphicView()
- {
- REF_PTR_RELEASE(Camera);
- REF_PTR_RELEASE(PipCamera);
- REF_PTR_RELEASE(PipScene);
- REF_PTR_RELEASE(Axes);
- }
- BOOL CGraphicView::PreCreateWindow(CREATESTRUCT& cs)
- {
- // TODO: Modify the Window class or styles here by modifying
- // the CREATESTRUCT cs
- return CView::PreCreateWindow(cs);
- }
- BOOL CGraphicView::Initialize_WW3D(int device,int bits)
- {
- // Assume failure
- BOOL ok = FALSE;
- if (device < 0) {
- return 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;
- WW3DErrorType err = WW3D_ERROR_GENERIC;
- while (err != WW3D_ERROR_OK) {
- err = WW3D::Set_Render_Device(device,cx,cy,bits,true);
- if (err != WW3D_ERROR_OK) {
- device = (device + 1) % WW3D::Get_Render_Device_Count();
- }
- }
- // Load some models that we're going to need into the asset manager
- ResourceFileClass point_file(NULL, "Point.w3d");
- WW3DAssetManager::Get_Instance()->Load_3D_Assets(point_file);
- ResourceFileClass axes_file(NULL, "Axes.w3d");
- WW3DAssetManager::Get_Instance()->Load_3D_Assets(axes_file);
- if (Camera == NULL) {
- Camera = NEW_REF(CameraClass,());
- ASSERT(Camera);
- // Init the camera
- Matrix3D transform;
- transform.Look_At(Vector3(0.0f,-15.0f,5.0f),Vector3(0,0,0),0);
- Camera->Set_Transform(transform);
- // update the camera FOV settings
- // take the larger of the two dimensions, give it the
- // full desired FOV, then give the other dimension an
- // FOV proportional to its relative size
- double hfov,vfov;
- if (cy > cx) {
- vfov = (float)DEG_TO_RAD(45.0f);
- hfov = (double)cx / (double)cy * vfov;
- } else {
- hfov = (float)DEG_TO_RAD(45.0f);
- vfov = (double)cy / (double)cx * hfov;
- }
- // Reset the field of view
- Camera->Set_View_Plane(hfov,vfov);
- #if ORTHO_CAMERA
- Camera->Set_Projection_Type(CameraClass::ORTHO);
- Camera->Set_View_Plane(Vector2(-ORTHO_WIDTH,-ORTHO_WIDTH),Vector2(ORTHO_WIDTH,ORTHO_WIDTH));
- #endif
- }
- if (PipCamera == NULL) {
- PipCamera = NEW_REF(CameraClass,());
- ASSERT(PipCamera);
- PipCamera->Set_Viewport(Vector2(0.0f,1.0f - PIP_VIEW),Vector2(PIP_VIEW,1.0f));
- PipCamera->Set_View_Plane(Camera->Get_Horizontal_FOV(),Camera->Get_Vertical_FOV());
- Update_Pip_Camera();
- }
- if (PipScene == NULL) {
- PipScene = NEW_REF(SimpleSceneClass,());
- PipScene->Set_Ambient_Light(Vector3(1,1,1));
- ASSERT(PipScene);
- }
- if (Axes == NULL) {
- Axes = WW3DAssetManager::Get_Instance()->Create_Render_Obj("Axes");
- ASSERT(Axes);
- Axes->Set_Transform(Matrix3D(1));
- PipScene->Add_Render_Object(Axes);
- }
- // Kick off a timer that we can use to update
- // the display (kinda like a game loop iterator)
- if (TimerID == 0) {
- #if 0
- TimerID = (UINT)::timeSetEvent( 50,
- 50,
- TimerCallback,
- (DWORD)m_hWnd,
- TIME_PERIODIC);
- #else
- TimerID = (UINT)::timeSetEvent( 66, // only update 15 times a second
- 50,
- TimerCallback,
- (DWORD)m_hWnd,
- TIME_PERIODIC);
- #endif
- }
- Initialized = true;
- // Return the TRUE/FALSE result code
- return TRUE;
- }
- void CGraphicView::Save(ChunkSaveClass & csave)
- {
- Matrix3D cameratm = Camera->Get_Transform();
- csave.Begin_Chunk(GRAPHICVIEW_CHUNK_VARIABLES);
- WRITE_MICRO_CHUNK(csave,GRAPHICVIEW_VARIABLE_CAMERAMODE,CameraMode);
- WRITE_MICRO_CHUNK(csave,GRAPHICVIEW_VARIABLE_DISPLAYBOXES,DisplayBoxes);
- WRITE_MICRO_CHUNK(csave,GRAPHICVIEW_VARIABLE_RUNSIMULATION,RunSimulation);
- WRITE_MICRO_CHUNK(csave,GRAPHICVIEW_VARIABLE_CAMERATM,cameratm);
- csave.End_Chunk();
- }
- void CGraphicView::Load(ChunkLoadClass & cload)
- {
- Matrix3D cameratm(1);
- while (cload.Open_Chunk()) {
- switch(cload.Cur_Chunk_ID()) {
- case GRAPHICVIEW_CHUNK_VARIABLES:
- while(cload.Open_Micro_Chunk()) {
- switch(cload.Cur_Micro_Chunk_ID()) {
- READ_MICRO_CHUNK(cload,GRAPHICVIEW_VARIABLE_CAMERAMODE,CameraMode);
- READ_MICRO_CHUNK(cload,GRAPHICVIEW_VARIABLE_DISPLAYBOXES,DisplayBoxes);
- READ_MICRO_CHUNK(cload,GRAPHICVIEW_VARIABLE_RUNSIMULATION,RunSimulation);
- READ_MICRO_CHUNK(cload,GRAPHICVIEW_VARIABLE_CAMERATM,cameratm);
- }
- cload.Close_Micro_Chunk();
- }
- break;
- default:
- WWDEBUG_SAY(("Unhandled chunk: %d File: %s Line: %d\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
- }
- cload.Close_Chunk();
- }
- Camera->Set_Transform(cameratm);
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGraphicView drawing
- void CGraphicView::OnDraw(CDC* pDC)
- {
- Repaint_View();
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGraphicView diagnostics
- #ifdef _DEBUG
- void CGraphicView::AssertValid() const
- {
- CView::AssertValid();
- }
- void CGraphicView::Dump(CDumpContext& dc) const
- {
- CView::Dump(dc);
- }
- CPhysTestDoc* CGraphicView::GetDocument() // non-debug version is inline
- {
- ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPhysTestDoc)));
- return (CPhysTestDoc*)m_pDocument;
- }
- #endif //_DEBUG
- /////////////////////////////////////////////////////////////////////////////
- // CGraphicView message handlers
- void CGraphicView::OnSize(UINT nType, int cx, int cy)
- {
- CView::OnSize(nType, cx, cy);
-
- if (Initialized)
- {
- // Change the resolution of the rendering device to
- // match that of the view's current dimensions
- WW3D::Set_Resolution (cx, cy, -1, true);
-
- // update the camera FOV settings
- // take the larger of the two dimensions, give it the
- // full desired FOV, then give the other dimension an
- // FOV proportional to its relative size
- double hfov,vfov;
- if (cy > cx) {
- vfov = (float)DEG_TO_RAD(45.0f);
- hfov = (double)cx / (double)cy * vfov;
- } else {
- hfov = (float)DEG_TO_RAD(45.0f);
- vfov = (double)cy / (double)cx * hfov;
- }
- // Reset the field of view
- ASSERT(Camera);
- Camera->Set_View_Plane(hfov, vfov);
- #if ORTHO_CAMERA
- Camera->Set_View_Plane(Vector2(-ORTHO_WIDTH,-ORTHO_WIDTH),Vector2(ORTHO_WIDTH,ORTHO_WIDTH));
- #endif
- PipCamera->Set_View_Plane(hfov,vfov);
- // Force a repaint of the screen
- Repaint_View();
- }
- }
- void CGraphicView::OnInitialUpdate()
- {
- CView::OnInitialUpdate();
-
- CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
- if (doc) {
- // tell the document to create the scene
- doc->Init_Scene();
- }
- }
- void CGraphicView::Timestep(void)
- {
- const float FLY_VELOCITY = 10.0f;
- // Compute the amount of time elapsed for this frame.
- CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
- DWORD curtime = ::GetTickCount();
- DWORD elapsedtime = curtime - doc->LastTime;
- if (elapsedtime > 100) {
- elapsedtime = 100;
- }
- float dt = (float)elapsedtime / 1000.0f;
- doc->LastTime = curtime;
- // fly forward when control is held
- if (::GetAsyncKeyState('A') & 0x8000) {
- Matrix3D transform = Camera->Get_Transform();
- transform.Translate(Vector3(0,0,-FLY_VELOCITY * dt));
- Camera->Set_Transform(transform);
- }
- if (::GetAsyncKeyState('Z') & 0x8000) {
- Matrix3D transform = Camera->Get_Transform();
- transform.Translate(Vector3(0,0,FLY_VELOCITY * dt));
- Camera->Set_Transform(transform);
- }
- // if mode == follow and we have an object selected, look at it
- if (CameraMode == CAMERA_FOLLOW) {
- CMainFrame * wnd = (CMainFrame *)::AfxGetMainWnd();
- PhysClass * obj = wnd->Peek_Selected_Object();
- if (obj) {
- Vector3 target;
- obj->Get_Transform().Get_Translation(&target);
- Vector3 pos;
- Camera->Get_Transform().Get_Translation(&pos);
- Matrix3D tm;
- tm.Look_At(pos,target,0.0f);
- Camera->Set_Transform(tm);
- }
- }
- // if mode == tether and we have an object selected, tie the camera to it
- if ((CameraMode == CAMERA_TETHER) || (CameraMode == CAMERA_RIGID_TETHER)) {
- CMainFrame * wnd = (CMainFrame *)::AfxGetMainWnd();
- PhysClass * obj = wnd->Peek_Selected_Object();
- if (obj) {
- const float TETHER_DIST = 15.0f;
- const float TETHER_ANGLE = DEG_TO_RADF(-20.0f);
- Vector3 pos;
- float zrot = obj->Get_Transform().Get_Z_Rotation();
- obj->Get_Transform().Get_Translation(&pos);
-
- Matrix3D tm(1);
-
- if (CameraMode == CAMERA_RIGID_TETHER) {
- tm = obj->Get_Transform();
- } else {
- tm.Translate(pos);
- tm.Rotate_Z(zrot);
- }
-
- tm.Rotate_Y(DEG_TO_RADF(-90.0f));
- tm.Rotate_Z(DEG_TO_RADF(-90.0f));
- tm.Rotate_X(TETHER_ANGLE);
- tm.Translate(Vector3(0,0,TETHER_DIST));
- Camera->Set_Transform(tm);
- }
- }
-
- // update the PIP camera transform
- Update_Pip_Camera();
- // Allow the world to simulate (if enabled)
- if (RunSimulation) {
- doc->Scene->Update(1.0f/15.0f , 0); // 0.05f,0); //dt,0);
- }
- // DEBUG, print the contact point coordinates
- #if 0
- Vector3 pt = _LastContactPoint;
- CString string;
- string.Format("Contact Point: %10.5f %10.5f %10.5f StartBad: %d",pt.X,pt.Y,pt.Z,_StartBad);
- ((CMainFrame *)::AfxGetMainWnd())->Set_Status_Bar_Text(string);
- #endif
- }
- void CGraphicView::Repaint_View(void)
- {
- static bool _already_painting = false;
- if (_already_painting) return;
- _already_painting = true;
- // Get the document to display
- CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
- // Are we in a valid state?
- if (Initialized && doc->Scene) {
- // Update the W3D frame times according to our elapsed tick count
- //WW3D::Sync(WW3D::Get_Sync_Time() + (ticks_elapsed * m_animationSpeed));
- // Render the scenes
- WW3D::Begin_Render(TRUE, TRUE, Vector3(0,0,0));
- WW3D::Render(doc->Scene,Camera,FALSE,FALSE);
- WW3D::Render(PipScene,PipCamera,FALSE,TRUE);
- WW3D::End_Render();
- }
- _already_painting = false;
- }
- void CGraphicView::Set_Active(bool onoff)
- {
- Active = onoff;
- if (!Active) {
- ::SetProp(m_hWnd,"Inactive",(HANDLE)1);
- } else {
- RemoveProp(m_hWnd,"Inactive");
- CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
- doc->LastTime = ::GetTickCount();
- }
- }
- bool CGraphicView::Is_Collision_Box_Display_Enabled(void)
- {
- return DisplayBoxes;
- }
- void CGraphicView::Enable_Collision_Box_Display(bool onoff)
- {
- DisplayBoxes = onoff;
- if (DisplayBoxes) {
- WW3D::Set_Collision_Box_Display_Mask(COLLISION_TYPE_PHYSICAL);
- } else {
- WW3D::Set_Collision_Box_Display_Mask(0);
- }
- }
- void CGraphicView::OnDestroy()
- {
- // remove our properties
- ::RemoveProp(m_hWnd,"Inactive");
- ::RemoveProp(m_hWnd,"WaitingToProcess");
- CView::OnDestroy();
-
- // Free the camera object
- REF_PTR_RELEASE(Camera);
- REF_PTR_RELEASE(PipScene);
- REF_PTR_RELEASE(PipCamera);
- REF_PTR_RELEASE(Axes);
- // Is there an update thread running?
- if (TimerID == 0) {
- // Stop the timer
- ::timeKillEvent((UINT)TimerID);
- TimerID = 0;
- }
- Initialized = FALSE;
- }
- void CGraphicView::OnLButtonDown(UINT nFlags, CPoint point)
- {
- // Capture all mouse messages
- SetCapture();
- // Left mouse button is down
- LMouseDown = TRUE;
- LastPoint = point;
- // Allow the base class to process this message
- CView::OnLButtonDown(nFlags, point);
- }
- void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
- {
- // if both buttons are now up, release the mouse
- if (!RMouseDown) {
- ReleaseCapture();
- }
- // Left mouse button is now up
- LMouseDown = false;
- CView::OnLButtonUp(nFlags, point);
- }
- void CGraphicView::OnRButtonDown(UINT nFlags, CPoint point)
- {
- // Capture all mouse messages
- SetCapture();
- // Right mouse button is down
- RMouseDown = TRUE;
- LastPoint = point;
-
- CView::OnRButtonDown(nFlags, point);
- }
- void CGraphicView::OnRButtonUp(UINT nFlags, CPoint point)
- {
- // if both buttons are now up, release the mouse
- if (!LMouseDown) {
- ReleaseCapture();
- }
- // Right mouse button is now up
- RMouseDown = false;
-
- CView::OnRButtonUp(nFlags, point);
- }
- void CGraphicView::OnMouseMove(UINT nFlags, CPoint point)
- {
- // Get the document to display
- CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
- WWASSERT(doc);
- #if 0
- PhysicsSceneClass * scene = doc->Scene;
- WWASSERT(scene);
- #endif
- // When Only the Left mouse button is down, we "look-around" with
- // vertical locking (rotate about Z until Y points up)
- if ((LMouseDown) && (!RMouseDown)) {
- // Are we in a valid state?
- if (Initialized && doc->Scene) {
-
- RECT rect;
- GetClientRect (&rect);
- float mid_point_x = float(rect.right >> 1);
- float mid_point_y = float(rect.bottom >> 1);
- float last_point_x = ((float)LastPoint.x - mid_point_x) / mid_point_x;
- float last_point_y = (mid_point_y - (float)LastPoint.y) / mid_point_y;
- float point_x = ((float)point.x - mid_point_x) / mid_point_x;
- float point_y = (mid_point_y - (float)point.y) / mid_point_y;
- // invert the axes (being lazy here...)
- point_x = -point_x;
- point_y = -point_y;
- last_point_x = -last_point_x;
- last_point_y = -last_point_y;
- // Rotate around the object (orbit) using a 0.00F - 1.00F percentage of
- // the mouse coordinates
- Quaternion rotation = ::Trackball (last_point_x,last_point_y,point_x,point_y, 0.8F);
- // If we're not in CAMERA_FOLLOW mode, just rotate our view
- if (CameraMode != CAMERA_FOLLOW) {
-
- // Apply the rotation to the camera
- Matrix3D transform = Camera->Get_Transform ();
- Matrix3D::Multiply(transform,Build_Matrix3D(rotation),&transform);
- // Straighten out the Y axis
- Vector3 pos = transform.Get_Translation();
- Vector3 target = transform * Vector3(0,0,-1);
- transform.Look_At(pos,target,0.0f);
- // Rotate and translate the camera
- Camera->Set_Transform (transform);
-
- } else {
- // We're in camera follow mode, this means the camera is always going
- // to point right at the object. We want to orbit the camera's position
- // around the object.
- Matrix3D camera_tm = Camera->Get_Transform();
- Vector3 relative_obj_pos(0,0,-10);
- CMainFrame * wnd = (CMainFrame *)::AfxGetMainWnd();
- PhysClass * obj = wnd->Peek_Selected_Object();
- if (obj) {
- Vector3 obj_pos;
- obj->Get_Transform().Get_Translation(&obj_pos);
- Matrix3D::Inverse_Transform_Vector(camera_tm,obj_pos,&relative_obj_pos);
-
- }
- camera_tm.Translate(relative_obj_pos);
- Matrix3D rotation_tm;
- Build_Matrix3D(rotation).Get_Orthogonal_Inverse(rotation_tm);
- Matrix3D::Multiply(camera_tm,rotation_tm,&camera_tm);
- camera_tm.Translate(-relative_obj_pos);
- Camera->Set_Transform(camera_tm);
- }
- }
- }
- LastPoint = point;
- Update_Pip_Camera();
- CView::OnMouseMove(nFlags, point);
- }
- void CGraphicView::Update_Pip_Camera(void)
- {
- if (PipCamera && Camera) {
- Matrix3D transform = Camera->Get_Transform();
- transform.Set_Translation(Vector3(0,0,0));
- transform.Translate(Vector3(0,0,4));
- PipCamera->Set_Transform(transform);
- }
- }
|