From 2ce57fea1aef9da7d0dffcb65acd46774bc05272 Mon Sep 17 00:00:00 2001 From: Jonathan Wilson Date: Tue, 26 Dec 2023 21:56:15 +1000 Subject: [PATCH] Implement parts of W3DView --- src/CMakeLists.txt | 1 + src/game/client/ingameui.h | 3 +- src/game/client/selectioninfo.cpp | 27 + src/game/client/selectioninfo.h | 19 + src/game/client/view.cpp | 50 +- src/game/client/view.h | 79 +-- src/hooker/setuphooks_zh.cpp | 16 + src/platform/w3dengine/client/w3dview.cpp | 766 +++++++++++++++++++++- src/platform/w3dengine/client/w3dview.h | 189 +++++- 9 files changed, 1048 insertions(+), 102 deletions(-) create mode 100644 src/game/client/selectioninfo.cpp create mode 100644 src/game/client/selectioninfo.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7cb4e8a8e..9adc52d1b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -157,6 +157,7 @@ set(GAMEENGINE_SRC game/client/messagestream/selectionxlat.cpp game/client/optionpreferences.cpp game/client/parabolicease.cpp + game/client/selectioninfo.cpp game/client/shader/bwfilter.cpp game/client/shader/cloudshader.cpp game/client/shader/crossfadefilter.cpp diff --git a/src/game/client/ingameui.h b/src/game/client/ingameui.h index d3faedea6..50b6f8aea 100644 --- a/src/game/client/ingameui.h +++ b/src/game/client/ingameui.h @@ -227,6 +227,7 @@ class InGameUI : public SubsystemInterface, public SnapShot bool Get_Unk7() const { return m_unk7; } void Set_Unk6(bool b) { m_unk6 = b; } void Clear_Attack_Move_To_Mode() { m_attackMoveToMode = false; } + bool Is_In_Force_To_Attack_Mode() { return m_forceToAttackMode; } protected: struct MoveHintStruct @@ -344,7 +345,7 @@ class InGameUI : public SubsystemInterface, public SnapShot PopupMessageData *m_popupMessageData; int m_popupMessageColor; bool m_waypointMode; - bool m_unk2; // not 100% identified yet + bool m_forceToAttackMode; // not 100% identified yet bool m_unk3; // not 100% identified yet bool m_attackMoveToMode; // not 100% identified yet bool m_unk5; // not 100% identified yet diff --git a/src/game/client/selectioninfo.cpp b/src/game/client/selectioninfo.cpp new file mode 100644 index 000000000..84465738c --- /dev/null +++ b/src/game/client/selectioninfo.cpp @@ -0,0 +1,27 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Selection Info + * + * @copyright Thyme 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 + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "selectioninfo.h" +#ifdef GAME_DLL +#include "hooker.h" +#endif + +PickType Get_Pick_Types_For_Context(bool force_to_attack) +{ +#ifdef GAME_DLL + return Call_Function(PICK_ADDRESS(0x00723550, 0x0086D346), force_to_attack); +#else + return PICKTYPE_UNK; +#endif +} diff --git a/src/game/client/selectioninfo.h b/src/game/client/selectioninfo.h new file mode 100644 index 000000000..a50db4e63 --- /dev/null +++ b/src/game/client/selectioninfo.h @@ -0,0 +1,19 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Selection Info + * + * @copyright Thyme 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 + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once +#include "always.h" +#include "view.h" + +PickType Get_Pick_Types_For_Context(bool force_to_attack); diff --git a/src/game/client/view.cpp b/src/game/client/view.cpp index 1a62b8dc4..9c1d2da93 100644 --- a/src/game/client/view.cpp +++ b/src/game/client/view.cpp @@ -171,41 +171,41 @@ void View::Scroll_By(Coord2D *pos) m_pos.y += pos->y; } -void View::Move_Camera_To(const Coord3D *o, int i1, int i2, bool b, float f1, float f2) +void View::Move_Camera_To(const Coord3D *o, int frames, int shutter, bool orient, float in, float out) { Look_At(o); } -void View::Move_Camera_Along_Waypoint_Path(Waypoint *w, int i1, int i2, bool b, float f1, float f2) {} +void View::Move_Camera_Along_Waypoint_Path(Waypoint *way, int frames, int stutter, bool orient, float in, float out) {} bool View::Is_Camera_Movement_Finished() { return true; } -void View::Camera_Mod_Final_Zoom(float f1, float f2, float f3) {} +void View::Camera_Mod_Final_Zoom(float final_zoom, float in, float out) {} -void View::Camera_Mod_Rolling_Average(int i) {} +void View::Camera_Mod_Rolling_Average(int frames_to_average) {} -void View::Camera_Mod_Final_Time_Multiplier(int i) {} +void View::Camera_Mod_Final_Time_Multiplier(int final_multiplier) {} -void View::Camera_Mod_Final_Pitch(float f1, float f2, float f3) {} +void View::Camera_Mod_Final_Pitch(float final_pitch, float in, float out) {} void View::Camera_Mod_Freeze_Time() {} void View::Camera_Mod_Freeze_Angle() {} -void View::Camera_Mod_Look_Toward(Coord3D *o) {} +void View::Camera_Mod_Look_Toward(Coord3D *p_loc) {} -void View::Camera_Mod_Final_Look_Toward(Coord3D *o) {} +void View::Camera_Mod_Final_Look_Toward(Coord3D *p_loc) {} -void View::Camera_Mod_Final_Move_To(Coord3D *o) {} +void View::Camera_Mod_Final_Move_To(Coord3D *p_loc) {} -void View::Camera_Enable_Slave_Mode(const Utf8String &s1, const Utf8String &s2) {} +void View::Camera_Enable_Slave_Mode(const Utf8String &thing, const Utf8String &bone) {} void View::Camera_Disable_Slave_Mode() {} -void View::Add_Camera_Shake(const Coord3D &o, float f1, float f2, float f3) {} +void View::Add_Camera_Shake(const Coord3D &position, float radius, float duration, float amplitude) {} FilterModes View::Get_View_Filter_Mode() { @@ -229,17 +229,17 @@ bool View::Set_View_Filter(FilterTypes filter) return false; } -void View::Set_Fade_Parameters(int i1, int i2) {} +void View::Set_Fade_Parameters(int fade_frames, int direction) {} void View::Set_3D_Wireframe_Mode(bool on) {} -void View::Reset_Camera(const Coord3D *o, int i, float f1, float f2) {} +void View::Reset_Camera(const Coord3D *location, int frames, float in, float out) {} -void View::Rotate_Camera(float f1, int i, float f2, float f3) {} +void View::Rotate_Camera(float rotations, int frames, float in, float out) {} -void View::Rotate_Camera_Toward_Object(ObjectID id, int i1, int i2, float f1, float f2) {} +void View::Rotate_Camera_Toward_Object(ObjectID id, int milliseconds, int hold_milliseconds, float in, float out) {} -void View::Rotate_Camera_Toward_Position(const Coord3D *o, int i, float f1, float f2, bool b) {} +void View::Rotate_Camera_Toward_Position(const Coord3D *p_loc, int milliseconds, float in, float out, bool b) {} bool View::Is_Time_Frozen() { @@ -251,13 +251,13 @@ int View::Get_Time_Multiplier() return 1; } -void View::Set_Time_Multiplier(int multiplier) {} +void View::Set_Time_Multiplier(int multiple) {} -void View::Set_Default_View(float f1, float f2, float f3) {} +void View::Set_Default_View(float pitch, float angle, float max_height) {} -void View::Zoom_Camera(float f1, int i, float f2, float f3) {} +void View::Zoom_Camera(float final_zoom, int milliseconds, float in, float out) {} -void View::Pitch_Camera(float f1, int i, float f2, float f3) {} +void View::Pitch_Camera(float final_pitch, int milliseconds, float in, float out) {} void View::Set_Angle(float angle) { @@ -269,9 +269,9 @@ float View::Get_Angle() return m_angle; } -void View::Set_Pitch(float pitch) +void View::Set_Pitch(float angle) { - m_pitchAngle = std::clamp(pitch, DEG_TO_RADF(-36.f), DEG_TO_RADF(36.f)); + m_pitchAngle = std::clamp(angle, DEG_TO_RADF(-36.f), DEG_TO_RADF(36.f)); } float View::Get_Pitch() @@ -295,16 +295,16 @@ float View::Get_Zoom() return m_zoom; } -void View::Set_Zoom(float zoom) {} +void View::Set_Zoom(float z) {} float View::Get_Height_Above_Ground() { return m_heightAboveGround; } -void View::Set_Height_Above_Ground(float height) +void View::Set_Height_Above_Ground(float z) { - m_heightAboveGround = height; + m_heightAboveGround = z; } void View::Zoom_In() diff --git a/src/game/client/view.h b/src/game/client/view.h index a0ea03814..787e64b89 100644 --- a/src/game/client/view.h +++ b/src/game/client/view.h @@ -112,10 +112,11 @@ class View : public SnapShot virtual void Init(); virtual void Reset() { m_zoomLimited = true; }; virtual uint32_t Get_ID(); - virtual void Set_Zoom_Limited(bool b); + virtual void Set_Zoom_Limited(bool limit); virtual bool Is_Zoom_Limited(); - virtual Drawable *Pick_Drawable(const ICoord2D *o, bool b, PickType type) = 0; - virtual int Iterate_Drawables_In_Region(IRegion2D *r, bool (*func)(Drawable *, void *), void *) = 0; + virtual Drawable *Pick_Drawable(const ICoord2D *screen, bool force_attack, PickType type) = 0; + virtual int Iterate_Drawables_In_Region( + IRegion2D *screen_region, bool (*callback)(Drawable *, void *), void *user_data) = 0; virtual void Get_Screen_Corner_World_Points_At_Z( Coord3D *top_left, Coord3D *top_right, Coord3D *bottom_left, Coord3D *bottom_right, float z); virtual void Set_Width(int32_t width) { m_width = width; } @@ -128,38 +129,38 @@ class View : public SnapShot virtual void Look_At(const Coord3D *pos); virtual void Init_Height_For_Map(); virtual void Scroll_By(Coord2D *pos); - virtual void Move_Camera_To(const Coord3D *o, int i1, int i2, bool b, float f1, float f2); - virtual void Move_Camera_Along_Waypoint_Path(Waypoint *w, int i1, int i2, bool b, float f1, float f2); + virtual void Move_Camera_To(const Coord3D *o, int frames, int shutter, bool orient, float in, float out); + virtual void Move_Camera_Along_Waypoint_Path(Waypoint *way, int frames, int stutter, bool orient, float in, float out); virtual bool Is_Camera_Movement_Finished(); - virtual void Camera_Mod_Final_Zoom(float f1, float f2, float f3); - virtual void Camera_Mod_Rolling_Average(int i); - virtual void Camera_Mod_Final_Time_Multiplier(int i); - virtual void Camera_Mod_Final_Pitch(float f1, float f2, float f3); + virtual void Camera_Mod_Final_Zoom(float final_zoom, float in, float out); + virtual void Camera_Mod_Rolling_Average(int frames_to_average); + virtual void Camera_Mod_Final_Time_Multiplier(int final_multiplier); + virtual void Camera_Mod_Final_Pitch(float final_pitch, float in, float out); virtual void Camera_Mod_Freeze_Time(); virtual void Camera_Mod_Freeze_Angle(); - virtual void Camera_Mod_Look_Toward(Coord3D *o); - virtual void Camera_Mod_Final_Look_Toward(Coord3D *o); - virtual void Camera_Mod_Final_Move_To(Coord3D *o); - virtual void Camera_Enable_Slave_Mode(const Utf8String &s1, const Utf8String &s2); + virtual void Camera_Mod_Look_Toward(Coord3D *p_loc); + virtual void Camera_Mod_Final_Look_Toward(Coord3D *p_loc); + virtual void Camera_Mod_Final_Move_To(Coord3D *p_loc); + virtual void Camera_Enable_Slave_Mode(const Utf8String &thing, const Utf8String &bone); virtual void Camera_Disable_Slave_Mode(); - virtual void Add_Camera_Shake(const Coord3D &o, float f1, float f2, float f3); + virtual void Add_Camera_Shake(const Coord3D &position, float radius, float duration, float amplitude); virtual FilterModes Get_View_Filter_Mode(); virtual FilterTypes Get_View_Filter_Type(); virtual bool Set_View_Filter_Mode(FilterModes mode); virtual void Set_View_Filter_Pos(const Coord3D *pos); virtual bool Set_View_Filter(FilterTypes filter); - virtual void Set_Fade_Parameters(int frames, int direction); + virtual void Set_Fade_Parameters(int fade_frames, int direction); virtual void Set_3D_Wireframe_Mode(bool on); - virtual void Reset_Camera(const Coord3D *o, int i, float f1, float f2); - virtual void Rotate_Camera(float f1, int i, float f2, float f3); - virtual void Rotate_Camera_Toward_Object(ObjectID id, int i1, int i2, float f1, float f2); - virtual void Rotate_Camera_Toward_Position(const Coord3D *o, int i, float f1, float f2, bool b); + virtual void Reset_Camera(const Coord3D *location, int frames, float in, float out); + virtual void Rotate_Camera(float rotations, int frames, float in, float out); + virtual void Rotate_Camera_Toward_Object(ObjectID id, int milliseconds, int hold_milliseconds, float in, float out); + virtual void Rotate_Camera_Toward_Position(const Coord3D *p_loc, int milliseconds, float in, float out, bool b); virtual bool Is_Time_Frozen(); virtual int Get_Time_Multiplier(); - virtual void Set_Time_Multiplier(int multiplier); - virtual void Set_Default_View(float f1, float f2, float f3); - virtual void Zoom_Camera(float f1, int i, float f2, float f3); - virtual void Pitch_Camera(float f1, int i, float f2, float f3); + virtual void Set_Time_Multiplier(int multiple); + virtual void Set_Default_View(float pitch, float angle, float max_height); + virtual void Zoom_Camera(float final_zoom, int milliseconds, float in, float out); + virtual void Pitch_Camera(float final_pitch, int milliseconds, float in, float out); virtual void Set_Angle(float angle); virtual float Get_Angle(); virtual void Set_Pitch(float pitch); @@ -168,24 +169,24 @@ class View : public SnapShot virtual void Get_Position(Coord3D *pos); virtual const Coord3D &Get_3D_Camera_Position() = 0; virtual float Get_Zoom(); - virtual void Set_Zoom(float zoom); + virtual void Set_Zoom(float z); virtual float Get_Height_Above_Ground(); - virtual void Set_Height_Above_Ground(float height); + virtual void Set_Height_Above_Ground(float z); virtual void Zoom_In(); virtual void Zoom_Out(); virtual void Set_Zoom_To_Default() {} virtual float Get_Max_Zoom() { return m_maxZoom; } - virtual void Set_Ok_To_Adjust_Height(bool ok) { m_okToAdjustHeight = ok; } + virtual void Set_Ok_To_Adjust_Height(bool val) { m_okToAdjustHeight = val; } virtual float Get_Terrain_Height_Under_Camera() { return m_terrainHeightUnderCamera; } virtual void Set_Terrain_Height_Under_Camera(float height) { m_terrainHeightUnderCamera = height; } virtual float Get_Current_Height_Above_Ground() { return m_currentHeightAboveGround; } virtual void Set_Current_Height_Above_Ground(float height) { m_currentHeightAboveGround = height; } - virtual void Set_Field_Of_View(float fov) { m_FOV = fov; } + virtual void Set_Field_Of_View(float angle) { m_FOV = angle; } virtual float Get_Field_Of_View() { return m_FOV; } - virtual int World_To_Screen_Tri_Return(const Coord3D *o1, ICoord2D *o2) = 0; - virtual void Screen_To_World(const ICoord2D *o1, Coord3D *o2) = 0; - virtual void Screen_To_Terrain(const ICoord2D *o1, Coord3D *o2) = 0; - virtual void Screen_To_World_At_Z(const ICoord2D *o1, Coord3D *o2, float f) = 0; + virtual int World_To_Screen_Tri_Return(const Coord3D *w, ICoord2D *s) = 0; + virtual void Screen_To_World(const ICoord2D *s, Coord3D *w) = 0; + virtual void Screen_To_Terrain(const ICoord2D *screen, Coord3D *world) = 0; + virtual void Screen_To_World_At_Z(const ICoord2D *s, Coord3D *w, float z) = 0; virtual void Get_Location(ViewLocation *location); virtual void Set_Location(const ViewLocation *location); virtual void Draw_View() = 0; @@ -198,10 +199,10 @@ class View : public SnapShot m_lockType = LOCK_FOLLOW; }; virtual void Snap_To_Camera_Lock() { m_snapImmediate = true; } - virtual void Set_Snap_Mode(CameraLockType type, float dist) + virtual void Set_Snap_Mode(CameraLockType lock_type, float lock_dist) { - m_lockType = type; - m_lockDist = dist; + m_lockType = lock_type; + m_lockDist = lock_dist; }; virtual Drawable *Get_Camera_Lock_Drawable() { return m_cameraLockDrawable; } virtual void Set_Camera_Lock_Drawable(Drawable *drawable) @@ -211,19 +212,19 @@ class View : public SnapShot } virtual void Set_Mouse_Lock(bool locked) { m_mouseLocked = locked; } virtual bool Is_Mouse_Locked() { return m_mouseLocked; } - virtual void Shake(const Coord3D *o, CameraShakeType type) {} + virtual void Shake(const Coord3D *epicenter, CameraShakeType shake_type) {} virtual float Get_FX_Pitch() { return 1.0f; } virtual void Force_Camera_Constraint_Recalc() {} - virtual void Set_Guard_Band_Bias(Coord2D *) = 0; - virtual View *Prepend_View_To_List(View *view) + virtual void Set_Guard_Band_Bias(Coord2D *bias) = 0; + virtual View *Prepend_View_To_List(View *list) { - m_next = view; + m_next = list; return this; }; virtual View *Get_Next_View() { return m_next; } Coord3D &Get_Position() { return m_pos; } void Set_Position(const Coord3D *pos) { m_pos = *pos; } - bool World_To_Screen_Tri(const Coord3D *o1, ICoord2D *o2) { return World_To_Screen_Tri_Return(o1, o2) == 0; } + bool World_To_Screen_Tri(const Coord3D *w, ICoord2D *s) { return World_To_Screen_Tri_Return(w, s) == 0; } protected: View *m_next; diff --git a/src/hooker/setuphooks_zh.cpp b/src/hooker/setuphooks_zh.cpp index 9cd4e6b89..feecf1ef9 100644 --- a/src/hooker/setuphooks_zh.cpp +++ b/src/hooker/setuphooks_zh.cpp @@ -1594,6 +1594,22 @@ void Setup_Hooks() // w3dview.h Hook_Any(0x0076E2F0, W3DView::Set_Fade_Parameters); Hook_Any(0x0076E330, W3DView::Set_View_Filter_Pos); + Hook_Any(0x0076D420, W3DView::Init); + Hook_Any(0x0076D600, W3DView::Reset); + Hook_Any(0x0076D200, W3DView::Set_Camera_Transform); + Hook_Any(0x0076CF10, W3DView::Calc_Camera_Constraints); + Hook_Any(0x0076D0C0, W3DView::Get_Pick_Ray); + Hook_Any(0x0076C780, W3DView::Build_Camera_Transform); + Hook_Any(0x0076F5D0, W3DView::Pick_Drawable); + Hook_Any(0x0076F3B0, W3DView::Iterate_Drawables_In_Region); + Hook_Any(0x0076C5B0, W3DView::Set_Width); + Hook_Any(0x0076C4F0, W3DView::Set_Height); + Hook_Any(0x0076C6B0, W3DView::Set_Origin); + Hook_Any(0x0076D680, W3DView::Update_Camera_Movements); + Hook_Any(0x00771B60, W3DView::Zoom_Camera_One_Frame); + Hook_Any(0x007716E0, W3DView::Rotate_Camera_One_Frame); + Hook_Any(0x00771C00, W3DView::Pitch_Camera_One_Frame); + Hook_Any(0x00771CA0, W3DView::Move_Along_Waypoint_Path); // scene.h Hook_Any(0x00832550, SceneClass::Render); diff --git a/src/platform/w3dengine/client/w3dview.cpp b/src/platform/w3dengine/client/w3dview.cpp index 803b3d5a0..9874aef91 100644 --- a/src/platform/w3dengine/client/w3dview.cpp +++ b/src/platform/w3dengine/client/w3dview.cpp @@ -13,7 +13,472 @@ * LICENSE */ #include "w3dview.h" +#include "baseheightmap.h" +#include "camera.h" +#include "camerashakesystem.h" +#include "coltest.h" +#include "drawable.h" +#include "drawmodule.h" +#include "gamewindowmanager.h" +#include "globaldata.h" +#include "ingameui.h" +#include "object.h" +#include "scriptengine.h" +#include "selectioninfo.h" #include "shadermanager.h" +#include "terrainlogic.h" +#include "w3ddisplay.h" +#include "w3dscene.h" +static const int g_theW3DFrameLengthInMsec = 33; + +void W3DView::Init() +{ + View::Init(); + Set_Name("W3DView"); + Coord3D pos; + pos.z = 0.0f; + pos.x = 87.0f * 10.0f; + pos.y = 77.0f * 10.0f; + Set_Position(&pos); + + m_3DCamera = new CameraClass(); + Set_Camera_Transform(); + + m_2DCamera = new CameraClass(); + m_2DCamera->Set_Position(Vector3(0.0f, 0.0f, 1.0f)); + m_2DCamera->Set_View_Plane(Vector2(-1.0f, -0.75f), Vector2(1.0f, 0.75f)); + m_2DCamera->Set_Clip_Planes(0.995f, 2.0f); + m_cameraConstraintValid = false; + m_scrollAmountCutoff = g_theWriteableGlobalData->m_scrollAmountCutoff; +} + +void W3DView::Reset() +{ + View::Reset(); + Set_Time_Multiplier(1); + Coord3D o; + memset(&o, 0, sizeof(o)); + Reset_Camera(&o, 1, 0.0f, 0.0f); + Set_View_Filter(FT_VIEW_SCREEN_DEFAULT_FILTER); + + Coord2D bias; + bias.x = 0.0f; + bias.y = 0.0f; + Set_Guard_Band_Bias(&bias); +} + +void W3DView::Set_Camera_Transform() +{ + m_cameraHasMovedSinceRequest = true; + Matrix3D tm(true); + float znear = 10.0f; + float zfar = 1200.0f; + + if (m_realZoom) { + if (m_FXPitch < 0.95f) { + zfar /= m_FXPitch; + } + } else if ((g_theWriteableGlobalData != nullptr && g_theWriteableGlobalData->m_drawEntireTerrain) || m_FXPitch < 0.95f + || m_zoom > 1.05f) { + zfar *= 10.0f; + } + + m_3DCamera->Set_Clip_Planes(znear, zfar); + +#ifdef GAME_DEBUG_STRUCTS + if (g_theWriteableGlobalData->m_useCameraConstraints) +#endif + { + if (!m_cameraConstraintValid) { + Build_Camera_Transform(&tm); + m_3DCamera->Set_Transform(tm); + Calc_Camera_Constraints(); + } + + if (!m_cameraConstraintValid) { + captainslog_debug("*** cam constraints are not valid!!!"); + } + + if (m_cameraConstraintValid) { + Coord3D pos = Get_Position(); + pos.x = GameMath::Max(m_cameraConstraint.lo.x, pos.x); + pos.x = GameMath::Min(m_cameraConstraint.hi.x, pos.x); + pos.y = GameMath::Max(m_cameraConstraint.lo.y, pos.y); + pos.y = GameMath::Min(m_cameraConstraint.hi.y, pos.y); + Set_Position(&pos); + } + } + + m_3DCamera->Set_View_Plane(m_FOV); + Build_Camera_Transform(&tm); + m_3DCamera->Set_Transform(tm); + + if (g_theTerrainRenderObject != nullptr) { + RefMultiListIterator *it = W3DDisplay::s_3DScene->Create_Lights_Iterator(); + g_theTerrainRenderObject->Update_Center(m_3DCamera, it); + + if (it != nullptr) { + W3DDisplay::s_3DScene->Destroy_Lights_Iterator(it); + } + } +} + +void W3DView::Calc_Camera_Constraints() +{ + if (g_theTerrainLogic != nullptr) { + Region3D extent; + g_theTerrainLogic->Get_Extent(&extent); + + ICoord2D screen; + screen.x = Get_Width() * 0.5f + m_originX; + screen.y = Get_Height() * 0.5f + m_originY; + + Vector3 ray_start; + Vector3 ray_end; + Get_Pick_Ray(&screen, &ray_start, &ray_end); + + Coord3D coord; + coord.x = Vector3::Find_X_At_Z(m_groundLevel, ray_start, ray_end); + coord.y = Vector3::Find_Y_At_Z(m_groundLevel, ray_start, ray_end); + coord.z = m_groundLevel; + + screen.y = Get_Height() * 0.95f + m_originY; + Get_Pick_Ray(&screen, &ray_start, &ray_end); + coord.x -= Vector3::Find_X_At_Z(m_groundLevel, ray_start, ray_end); + coord.y -= Vector3::Find_Y_At_Z(m_groundLevel, ray_start, ray_end); + float len = coord.Length(); + + if (g_theWriteableGlobalData->m_debugAI) { + len = -1000.0f; + } + + m_cameraConstraint.lo.x = extent.lo.x + len; + m_cameraConstraint.hi.x = extent.hi.x - len; + m_cameraConstraint.lo.y = extent.lo.y + len; + m_cameraConstraint.hi.y = extent.hi.y - len; + m_cameraConstraintValid = true; + } +} + +static void Pixel_Screen_To_W3D_Logical_Screen( + int screen_x, int screen_y, float *log_x, float *log_y, int screen_width, int screen_height) +{ + *log_x = ((float)screen_x + (float)screen_x) / (float)screen_width - 1.0f; + *log_y = -(((float)screen_y + (float)screen_y) / (float)screen_height - 1.0f); +} + +void W3DView::Get_Pick_Ray(const ICoord2D *screen, Vector3 *ray_start, Vector3 *ray_end) +{ + float x; + float y; + Pixel_Screen_To_W3D_Logical_Screen(screen->x - m_originX, screen->y - m_originY, &x, &y, Get_Width(), Get_Height()); + *ray_start = m_3DCamera->Get_Position(); + m_3DCamera->Un_Project(*ray_end, Vector2(x, y)); + *ray_end -= *ray_start; + ray_end->Normalize(); + (*ray_end) *= m_3DCamera->Get_Depth(); + *ray_end += *ray_start; +} + +void W3DView::Build_Camera_Transform(Matrix3D *transform) +{ + Vector3 p; + Vector3 t; + float zoom = Get_Zoom(); + float angle = Get_Angle(); + float pitch = Get_Pitch(); + Coord3D pos = Get_Position(); + pos.x += m_shakeOffset.x; + pos.y += m_shakeOffset.y; + + if (m_cameraConstraintValid) { + pos.x = GameMath::Max(m_cameraConstraint.lo.x, pos.x); + pos.x = GameMath::Min(m_cameraConstraint.hi.x, pos.x); + pos.y = GameMath::Max(m_cameraConstraint.lo.y, pos.y); + pos.y = GameMath::Min(m_cameraConstraint.hi.y, pos.y); + } + + if (m_realZoom) { + p.X = m_cameraOffset.x; + p.Y = m_cameraOffset.y; + p.Z = m_cameraOffset.z; + float real_zoom = zoom; + + if (real_zoom > 1.0f) { + real_zoom = 1.0f; + } + + if (real_zoom < 0.5f) { + real_zoom = 0.5f; + } + + m_FOV = 0.87266463f * real_zoom * real_zoom; + } else { + p.X = zoom * m_cameraOffset.x; + p.Y = zoom * m_cameraOffset.y; + p.Z = zoom * m_cameraOffset.z; + } + + memset(&t, 0, sizeof(t)); + float k = 1.0f - m_groundLevel / p.Z; + Matrix3D m1(Vector3(0.0f, 0.0f, 1.0f), angle); + Matrix3D m2(Vector3(1.0f, 0.0f, 0.0f), pitch); + m2.Mul_Vector3(p); + m1.Mul_Vector3(p); + + p *= k; + p.X += pos.x; + p.Y += pos.y; + p.Z += m_groundLevel; + t.X += pos.x; + t.Y += pos.y; + t.Z += m_groundLevel; + + if (m_realZoom) { + float real_zoom = 1.0f; + + if (!g_theDisplay->Is_LetterBoxed()) { + real_zoom = zoom; + + if (real_zoom > 1.0f) { + real_zoom = 1.0f; + } + + if (real_zoom < 0.5f) { + real_zoom = 0.5f; + } + + p.Z *= (real_zoom * 0.5f + 0.5f); + } + + m_FXPitch = (real_zoom * 0.75f + 0.25f) * 1.0f; + } + + if (m_realZoom) { + p.X = (p.X - t.X) / m_FXPitch + t.X; + p.Y = (p.Y - t.Y) / m_FXPitch + t.Y; + } else if (m_FXPitch > 1.0f) { + p.X = (p.X - t.X) / m_FXPitch + t.X; + p.Y = (p.Y - t.Y) / m_FXPitch + t.Y; + } else { + float fxpitch = p.Z - t.Z; + fxpitch *= m_FXPitch; + t.Z = p.Z - fxpitch; + } + + transform->Make_Identity(); + transform->Look_At(p, t, 0.0f); + g_theCameraShakerSystem.Timestep(0.033333335f); + g_theCameraShakerSystem.Update_Camera_Shaker(p, &m_cameraShakeAngles); + transform->Rotate_X(m_cameraShakeAngles.X); + transform->Rotate_Y(m_cameraShakeAngles.Y); + transform->Rotate_Z(m_cameraShakeAngles.Z); + + if (m_cameraSlaveMode) { + Object *obj = g_theScriptEngine->Get_Unit_Named(m_cameraSlaveThing); + + if (obj != nullptr) { + Drawable *drawable = obj->Get_Drawable(); + + if (drawable != nullptr) { + for (DrawModule **modules = drawable->Get_Draw_Modules(); *modules != nullptr; modules++) { + ObjectDrawInterface *draw = (*modules)->Get_Object_Draw_Interface(); + + if (draw != nullptr) { + Matrix3D bone; + draw->Client_Only_Get_Render_Obj_Bone_Transform(m_cameraSlaveBone, &bone); + *transform = bone; + Vector3 translation = transform->Get_Translation(); + m_pos.x = translation.X; + m_pos.y = translation.Y; + m_pos.z = translation.Z; + return; + } + } + } else { + m_cameraSlaveMode = false; + } + } else { + m_cameraSlaveMode = false; + } + } +} + +Drawable *W3DView::Pick_Drawable(const ICoord2D *screen, bool force_attack, PickType type) +{ + RenderObjClass *robj = nullptr; + Drawable *drawable = nullptr; + DrawableInfo *info = nullptr; + + if (screen == nullptr) { + return nullptr; + } + + GameWindow *parent = nullptr; + + if (g_theWindowManager != nullptr) { + parent = g_theWindowManager->Get_Window_Under_Cursor(screen->x, screen->y, false); + } + + while (parent != nullptr) { + if ((parent->Win_Get_Status() & WIN_STATUS_SEE_THRU) == 0) { + return nullptr; + } + + parent = parent->Win_Get_Parent(); + } + + Vector3 ray_start; + Vector3 ray_end; + Get_Pick_Ray(screen, &ray_start, &ray_end); + + LineSegClass ray; + ray.Set(ray_start, ray_end); + CastResultStruct res; + + if (force_attack) { + res.compute_contact_point = true; + } + + RayCollisionTestClass ray_test(ray, &res, COLLISION_TYPE_ALL); + + if (W3DDisplay::s_3DScene->Cast_Ray(ray_test, false, type)) { + robj = ray_test.m_collidedRenderObj; + } + + if (robj != nullptr) { + info = static_cast(robj->Get_User_Data()); + } + + if (info != nullptr) { + return info->drawable; + } + + return drawable; +} + +int W3DView::Iterate_Drawables_In_Region(IRegion2D *screen_region, bool (*callback)(Drawable *, void *), void *user_data) +{ + int count = 0; + Vector3 screen; + Vector3 world; + bool is_point = false; + Region2D normalized_region; + + if (screen_region != nullptr) { + if (screen_region->Height() == 0 && screen_region->Width() == 0) { + is_point = true; + } + + float f1 = screen_region->lo.x - m_originX; + float f2 = Get_Width(); + normalized_region.lo.x = f1 / f2 + f1 / f2 - 1.0f; + + float f3 = screen_region->hi.y - m_originY; + float f4 = Get_Height(); + normalized_region.lo.y = -(f3 / f4 + f3 / f4 - 1.0f); + + float f5 = screen_region->hi.x - m_originX; + float f6 = Get_Width(); + normalized_region.hi.x = f5 / f6 + f5 / f6 - 1.0f; + + float f7 = screen_region->lo.y - m_originY; + float f8 = Get_Height(); + normalized_region.hi.y = -(f7 / f8 + f7 / f8 - 1.0f); + } + + Drawable *drawable = nullptr; + + if (is_point) { + drawable = + Pick_Drawable(&screen_region->lo, true, Get_Pick_Types_For_Context(g_theInGameUI->Is_In_Force_To_Attack_Mode())); + + if (drawable == nullptr) { + return 0; + } + } + + for (Drawable *draw = g_theGameClient->First_Drawable(); draw != nullptr; draw = draw->Get_Next()) { + bool do_callback; + + if (drawable != nullptr) { + draw = drawable; + do_callback = true; + } else { + do_callback = false; + + if (screen_region != nullptr) { + const Coord3D *pos = draw->Get_Position(); + world.X = pos->x; + world.Y = pos->y; + world.Z = pos->z; + + if (m_3DCamera->Project(screen, world) == CameraClass::INSIDE_FRUSTUM && screen.X >= normalized_region.lo.x + && screen.X <= normalized_region.hi.x && screen.Y >= normalized_region.lo.y + && screen.Y <= normalized_region.hi.y) { + do_callback = true; + } + } else { + do_callback = true; + } + } + + if (do_callback) { + if (callback(draw, user_data)) { + count++; + } + } + + if (drawable != nullptr) { + break; + } + } + + return count; +} + +void W3DView::Set_Width(int32_t width) +{ + View::Set_Width(width); + Vector2 min; + Vector2 max; + float f1 = width; + float width_to_height = f1 / Get_Height(); + m_3DCamera->Set_Aspect_Ratio(width_to_height); + m_3DCamera->Get_Viewport(min, max); + float f2 = (float)(width + m_originX); + max.X = f2 / g_theDisplay->Get_Width(); + m_3DCamera->Set_Viewport(min, max); + float f3 = f1 / g_theDisplay->Get_Width() * 0.87266463f; + m_3DCamera->Set_View_Plane(f3); +} + +void W3DView::Set_Height(int32_t height) +{ + View::Set_Height(height); + Vector2 min; + Vector2 max; + float width_to_height = (float)Get_Width() / (float)height; + m_3DCamera->Set_Aspect_Ratio(width_to_height); + m_3DCamera->Get_Viewport(min, max); + float f2 = (float)(height + m_originY); + max.Y = f2 / g_theDisplay->Get_Height(); + m_3DCamera->Set_Viewport(min, max); +} + +void W3DView::Set_Origin(int32_t x, int32_t y) +{ + View::Set_Origin(x, y); + Vector2 min; + Vector2 max; + m_3DCamera->Get_Viewport(min, max); + min.X = (float)x / g_theDisplay->Get_Width(); + min.Y = (float)y / g_theDisplay->Get_Height(); + m_3DCamera->Set_Viewport(min, max); + Set_Width(m_width); + Set_Height(m_height); +} + void W3DView::Set_Fade_Parameters(int frames, int direction) { ScreenBWFilter::Set_Fade_Parameters(frames, direction); @@ -27,9 +492,300 @@ void W3DView::Set_View_Filter_Pos(const Coord3D *pos) bool W3DView::Update_Camera_Movements() { -#ifdef GAME_DLL - return Call_Method(PICK_ADDRESS(0x0076D680, 0x006A5728), this); -#else - return false; -#endif + bool ret = false; + + if (m_doingZoomCamera) { + Zoom_Camera_One_Frame(); + ret = true; + } + + if (m_doingPitchCamera) { + Pitch_Camera_One_Frame(); + ret = true; + } + + if (m_doingRotateCamera) { + m_previousLookAtPosition = Get_Position(); + Rotate_Camera_One_Frame(); + ret = true; + } else if (m_doingMoveCameraOnWaypointPath) { + m_previousLookAtPosition = Get_Position(); + Move_Along_Waypoint_Path(g_theW3DFrameLengthInMsec); + ret = true; + } + + if (m_doingScriptedCameraLock) { + return true; + } + + return ret; +} + +void W3DView::Zoom_Camera_One_Frame() +{ + m_zcInfo.cur_frame++; + + if (g_theWriteableGlobalData->m_disableCameraMovements) { + if (m_zcInfo.cur_frame >= m_zcInfo.num_frames) { + m_doingZoomCamera = false; + } + } else { + if (m_zcInfo.cur_frame <= m_zcInfo.num_frames) { + float param = (float)m_zcInfo.cur_frame / (float)m_zcInfo.num_frames; + float lerp = m_zcInfo.ease(param); + m_zoom = GameMath::Lerp(m_zcInfo.start_zoom, m_zcInfo.end_zoom, lerp); + } + + if (m_zcInfo.cur_frame >= m_zcInfo.num_frames) { + m_doingZoomCamera = false; + m_zoom = m_zcInfo.end_zoom; + } + } +} + +void Norm_Angle(float *angle) +{ + if (*angle < -31.415928f) { + *angle = 0.0f; + } + + if (*angle > 31.415928f) { + *angle = 0.0f; + } + + while (*angle < -3.1415927f) { + *angle -= 6.2831855f; + } + + while (*angle > 3.1415927f) { + *angle -= 6.2831855f; + } +} + +void W3DView::Rotate_Camera_One_Frame() +{ + m_rcInfo.cur_frame++; + + if (g_theWriteableGlobalData->m_disableCameraMovements) { + if (m_rcInfo.cur_frame >= m_rcInfo.num_hold_frames + m_rcInfo.num_frames) { + m_doingRotateCamera = false; + m_freezeTimeForCameraMovement = false; + } + } else { + if (m_rcInfo.track_object) { + if (m_rcInfo.cur_frame <= m_rcInfo.num_hold_frames + m_rcInfo.num_frames) { + Object *obj = g_theGameLogic->Find_Object_By_ID(m_rcInfo.target_object_id); + + if (obj != nullptr) { + m_rcInfo.target_object_pos = *obj->Get_Position(); + } + + Vector2 v(m_rcInfo.target_object_pos.x - m_pos.x, m_rcInfo.target_object_pos.y - m_pos.y); + int len = v.Length(); + + if (len >= 0.1f) { + float angle = GameMath::Acos(v.X / len); + + if (v.Y < 0.0f) { + angle = -angle; + } + + angle -= 1.5707964f; + Norm_Angle(&angle); + + if (m_rcInfo.cur_frame > m_rcInfo.num_frames) { + m_angle = angle; + } else { + float f1 = (float)m_rcInfo.cur_frame / (float)m_rcInfo.num_frames; + float f2 = m_rcInfo.ease(f1); + float f3 = angle - m_angle; + Norm_Angle(&f3); + m_angle = f3 + m_angle; + Norm_Angle(&m_angle); + float f4 = (m_rcInfo.end_time_multiplier - m_rcInfo.start_time_multiplier) * f2 + 0.5f; + m_timeMultiplier = GameMath::Fast_To_Int_Floor(f4) + m_rcInfo.start_time_multiplier; + } + } + } + } else if (m_rcInfo.cur_frame <= m_rcInfo.num_frames) { + float f1 = (float)m_rcInfo.cur_frame / (float)m_rcInfo.num_frames; + float f2 = m_rcInfo.ease(f1); + m_angle = GameMath::Lerp(m_rcInfo.angle, m_rcInfo.angle2, f2); + Norm_Angle(&m_angle); + float f3 = (m_rcInfo.end_time_multiplier - m_rcInfo.start_time_multiplier) * f2 + 0.5f; + m_timeMultiplier = GameMath::Fast_To_Int_Floor(f3) + m_rcInfo.start_time_multiplier; + } + + if (m_rcInfo.cur_frame >= m_rcInfo.num_hold_frames + m_rcInfo.num_frames) { + m_doingRotateCamera = false; + m_freezeTimeForCameraMovement = false; + + if (!m_rcInfo.track_object) { + m_angle = m_rcInfo.angle2; + } + } + } +} + +void W3DView::Pitch_Camera_One_Frame() +{ + m_pcInfo.cur_frame++; + + if (g_theWriteableGlobalData->m_disableCameraMovements) { + if (m_pcInfo.cur_frame >= m_pcInfo.num_frames) { + m_doingPitchCamera = false; + } + } else { + if (m_pcInfo.cur_frame <= m_pcInfo.num_frames) { + float f1 = (float)m_pcInfo.cur_frame / (float)m_pcInfo.num_frames; + float f2 = m_pcInfo.ease(f1); + m_FXPitch = GameMath::Lerp(m_pcInfo.start_pitch, m_pcInfo.end_pitch, f2); + } + + if (m_pcInfo.cur_frame >= m_pcInfo.num_frames) { + m_doingPitchCamera = false; + m_FXPitch = m_pcInfo.end_pitch; + } + } +} + +void W3DView::Move_Along_Waypoint_Path(int milliseconds) +{ + m_mcwpInfo.elapsed_time_milliseconds += milliseconds; + + if (g_theWriteableGlobalData->m_disableCameraMovements) { + if (m_mcwpInfo.elapsed_time_milliseconds > m_mcwpInfo.total_time_milliseconds) { + m_doingMoveCameraOnWaypointPath = false; + m_freezeTimeForCameraMovement = false; + } + } else if (m_mcwpInfo.elapsed_time_milliseconds <= m_mcwpInfo.total_time_milliseconds) { + float f1 = (float)m_mcwpInfo.total_time_milliseconds; + float f2 = m_mcwpInfo.elapsed_time_milliseconds / f1; + float f3 = m_mcwpInfo.ease(f2); + float f4 = (m_mcwpInfo.elapsed_time_milliseconds - milliseconds) / f1; + float f5 = f3 - m_mcwpInfo.ease(f4); + m_mcwpInfo.cur_seg_distance += f5 * m_mcwpInfo.total_distance; + + while (m_mcwpInfo.cur_seg_distance >= m_mcwpInfo.way_seg_length[m_mcwpInfo.cur_segment]) { + if (m_doingMoveCameraOnWaypointPath) { + m_doingMoveCameraAlongWaypointPath = true; + } + + m_mcwpInfo.cur_seg_distance -= m_mcwpInfo.way_seg_length[m_mcwpInfo.cur_segment]; + m_mcwpInfo.cur_segment++; + + if (m_mcwpInfo.cur_segment >= m_mcwpInfo.num_waypoints) { + m_mcwpInfo.total_time_milliseconds = 0; + return; + } + } + + float f6 = 1.0f / m_mcwpInfo.rolling_average_frames; + m_mcwpInfo.cur_shutter--; + + if (m_mcwpInfo.cur_shutter <= 0) { + m_mcwpInfo.cur_shutter = m_mcwpInfo.shutter; + float f7 = m_mcwpInfo.cur_seg_distance / m_mcwpInfo.way_seg_length[m_mcwpInfo.cur_segment]; + + if (m_mcwpInfo.cur_segment == m_mcwpInfo.num_waypoints - 1) { + f6 = f6 + (1.0f - f6) * f7; + } + + float f8 = 1.0f - f7; + float f9 = 1.0f - f8; + float f10 = m_mcwpInfo.camera_angle[m_mcwpInfo.cur_segment]; + float f11 = m_mcwpInfo.camera_angle[m_mcwpInfo.cur_segment + 1]; + + if (f11 - f10 > GAMEMATH_PI) { + f10 += GAMEMATH_PI2; + } + + if (f11 - f10 < -GAMEMATH_PI) { + f10 -= GAMEMATH_PI2; + } + + float f12 = f10 * f8 + f11 * f9; + Norm_Angle(&f12); + float f13 = f12 - m_angle; + Norm_Angle(&f13); + + if (GameMath::Fabs(f13) > 0.3141592741012573f) { + captainslog_debug("Huh."); + } + + m_angle += f6 * f13; + Norm_Angle(&m_angle); + float f14 = m_mcwpInfo.time_multiplier[m_mcwpInfo.cur_segment] * f8 + + m_mcwpInfo.time_multiplier[m_mcwpInfo.cur_segment + 1] * f9; + m_timeMultiplier = GameMath::Fast_To_Int_Floor(f14 + 0.5f); + m_groundLevel = f8 * m_mcwpInfo.ground_height[m_mcwpInfo.cur_segment] + + f9 * m_mcwpInfo.ground_height[m_mcwpInfo.cur_segment + 1]; + m_cameraOffset.y = + -(m_cameraOffset.z / GameMath::Tan(g_theWriteableGlobalData->m_cameraPitch * 0.01745329300562541f)); + m_cameraOffset.x = + -(GameMath::Tan(g_theWriteableGlobalData->m_cameraYaw * 0.01745329300562541f) * m_cameraOffset.y); + + Coord3D wp; + Coord3D wp2; + Coord3D wp3; + if (f7 < 0.5f) { + wp = m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment - 1]; + wp.x += m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment].x; + wp.y += m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment].y; + wp.x /= 2.0f; + wp.y /= 2.0f; + wp2 = m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment]; + wp3 = m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment]; + wp3.x += m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment + 1].x; + wp3.y += m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment + 1].y; + wp3.x /= 2.0f; + wp3.y /= 2.0f; + f7 += 0.5f; + } else { + wp = m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment]; + wp.x += m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment + 1].x; + wp.y += m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment + 1].y; + wp.x /= 2.0f; + wp.y /= 2.0f; + wp2 = m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment + 1]; + wp3 = m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment + 1]; + wp3.x += m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment + 2].x; + wp3.y += m_mcwpInfo.waypoints[m_mcwpInfo.cur_segment + 2].y; + wp3.x /= 2.0f; + wp3.y /= 2.0f; + f7 -= 0.5f; + } + + Coord3D pos; + pos.x = (wp3.x - wp.x) * f7 + wp.x; + pos.y = (wp3.y - wp.y) * f7 + wp.y; + pos.x = (1.0f - f7) * f7 * (wp2.x - wp3.x + wp2.x - wp.x) + pos.x; + pos.y = (1.0f - f7) * f7 * (wp2.y - wp3.y + wp2.y - wp.y) + pos.y; + pos.z = 0.0f; + Set_Position(&pos); + m_cameraConstraint.lo.x = GameMath::Min(m_cameraConstraint.lo.x, pos.x); + m_cameraConstraint.hi.x = GameMath::Max(m_cameraConstraint.hi.x, pos.x); + m_cameraConstraint.lo.y = GameMath::Min(m_cameraConstraint.lo.y, pos.y); + m_cameraConstraint.hi.y = GameMath::Max(m_cameraConstraint.hi.y, pos.y); + } + } else { + m_doingMoveCameraOnWaypointPath = false; + m_doingMoveCameraAlongWaypointPath = false; + m_freezeTimeForCameraMovement = false; + m_angle = m_mcwpInfo.camera_angle[m_mcwpInfo.num_waypoints]; + m_groundLevel = m_mcwpInfo.ground_height[m_mcwpInfo.num_waypoints]; + m_cameraOffset.y = + -(m_cameraOffset.z / GameMath::Tan(g_theWriteableGlobalData->m_cameraPitch * 0.01745329300562541f)); + m_cameraOffset.x = -(GameMath::Tan(g_theWriteableGlobalData->m_cameraYaw * 0.01745329300562541f) * m_cameraOffset.y); + + Coord3D pos; + pos.x = m_mcwpInfo.waypoints[m_mcwpInfo.num_waypoints].x; + pos.y = m_mcwpInfo.waypoints[m_mcwpInfo.num_waypoints].y; + pos.z = 0.0f; + Set_Position(&pos); + m_cameraConstraint.lo.x = GameMath::Min(m_cameraConstraint.lo.x, pos.x); + m_cameraConstraint.hi.x = GameMath::Max(m_cameraConstraint.hi.x, pos.x); + m_cameraConstraint.lo.y = GameMath::Min(m_cameraConstraint.lo.y, pos.y); + m_cameraConstraint.hi.y = GameMath::Max(m_cameraConstraint.hi.y, pos.y); + } } diff --git a/src/platform/w3dengine/client/w3dview.h b/src/platform/w3dengine/client/w3dview.h index d8dc099ef..f64b04b4b 100644 --- a/src/platform/w3dengine/client/w3dview.h +++ b/src/platform/w3dengine/client/w3dview.h @@ -14,17 +14,89 @@ */ #pragma once #include "always.h" +#include "parabolicease.h" +#include "vector3.h" #include "view.h" + class CameraClass; +class Matrix3D; + +struct TRotateCameraInfo +{ + int num_frames; + int cur_frame; + int start_time_multiplier; + int end_time_multiplier; + int num_hold_frames; + ParabolicEase ease; + bool track_object; + union + { + struct + { + float angle; + float angle2; + }; + struct + { + ObjectID target_object_id; + Coord3D target_object_pos; + }; + }; +}; + +struct TPitchCameraInfo +{ + int num_frames; + int cur_frame; + int angle; + float start_pitch; + float end_pitch; + int start_time_multiplier; + int end_time_multiplier; + ParabolicEase ease; +}; + +struct TZoomCameraInfo +{ + int num_frames; + int cur_frame; + float start_zoom; + float end_zoom; + int start_time_multiplier; + int end_time_multiplier; + ParabolicEase ease; +}; + +struct TMoveAlongWaypointPathInfo +{ + int num_waypoints; + Coord3D waypoints[27]; + float way_seg_length[27]; + float camera_angle[27]; + int time_multiplier[27]; + float ground_height[26]; + int total_time_milliseconds; + int elapsed_time_milliseconds; + float total_distance; + float cur_seg_distance; + int shutter; + int cur_segment; + int cur_shutter; + int rolling_average_frames; + ParabolicEase ease; +}; class W3DView : public View, public SubsystemInterface { public: + W3DView(); virtual ~W3DView() override; virtual void Init() override; virtual void Reset() override; - virtual Drawable *Pick_Drawable(const ICoord2D *o, bool b, PickType type) override; - virtual int Iterate_Drawables_In_Region(IRegion2D *r, bool (*func)(Drawable *, void *), void *) override; + virtual Drawable *Pick_Drawable(const ICoord2D *screen, bool force_attack, PickType type) override; + virtual int Iterate_Drawables_In_Region( + IRegion2D *screen_region, bool (*callback)(Drawable *, void *), void *user_data) override; virtual void Set_Width(int32_t width) override; virtual void Set_Height(int32_t height) override; virtual void Set_Origin(int32_t x, int32_t y) override; @@ -32,64 +104,117 @@ class W3DView : public View, public SubsystemInterface virtual void Look_At(const Coord3D *pos) override; virtual void Init_Height_For_Map() override; virtual void Scroll_By(Coord2D *pos) override; - virtual void Move_Camera_To(const Coord3D *o, int i1, int i2, bool b, float f1, float f2) override; - virtual void Move_Camera_Along_Waypoint_Path(Waypoint *w, int i1, int i2, bool b, float f1, float f2) override; + virtual void Move_Camera_To(const Coord3D *o, int frames, int shutter, bool orient, float in, float out) override; + virtual void Move_Camera_Along_Waypoint_Path( + Waypoint *way, int frames, int stutter, bool orient, float in, float out) override; virtual bool Is_Camera_Movement_Finished() override; - virtual void Camera_Mod_Final_Zoom(float f1, float f2, float f3) override; - virtual void Camera_Mod_Rolling_Average(int i) override; - virtual void Camera_Mod_Final_Time_Multiplier(int i) override; - virtual void Camera_Mod_Final_Pitch(float f1, float f2, float f3) override; + virtual void Camera_Mod_Final_Zoom(float final_zoom, float in, float out) override; + virtual void Camera_Mod_Rolling_Average(int frames_to_average) override; + virtual void Camera_Mod_Final_Time_Multiplier(int final_multiplier) override; + virtual void Camera_Mod_Final_Pitch(float final_pitch, float in, float out) override; virtual void Camera_Mod_Freeze_Time() override; virtual void Camera_Mod_Freeze_Angle() override; - virtual void Camera_Mod_Look_Toward(Coord3D *o) override; - virtual void Camera_Mod_Final_Look_Toward(Coord3D *o) override; - virtual void Camera_Mod_Final_Move_To(Coord3D *o) override; - virtual void Camera_Enable_Slave_Mode(const Utf8String &s1, const Utf8String &s2) override; + virtual void Camera_Mod_Look_Toward(Coord3D *p_loc) override; + virtual void Camera_Mod_Final_Look_Toward(Coord3D *p_loc) override; + virtual void Camera_Mod_Final_Move_To(Coord3D *p_loc) override; + virtual void Camera_Enable_Slave_Mode(const Utf8String &thing, const Utf8String &bone) override; virtual void Camera_Disable_Slave_Mode() override; - virtual void Add_Camera_Shake(const Coord3D &o, float f1, float f2, float f3) override; + virtual void Add_Camera_Shake(const Coord3D &position, float radius, float duration, float amplitude) override; virtual FilterModes Get_View_Filter_Mode() override; virtual FilterTypes Get_View_Filter_Type() override; virtual bool Set_View_Filter_Mode(FilterModes mode) override; virtual void Set_View_Filter_Pos(const Coord3D *pos) override; virtual bool Set_View_Filter(FilterTypes filter) override; - virtual void Set_Fade_Parameters(int frames, int direction) override; + virtual void Set_Fade_Parameters(int fade_frames, int direction) override; virtual void Set_3D_Wireframe_Mode(bool on) override; - virtual void Reset_Camera(const Coord3D *o, int i, float f1, float f2) override; - virtual void Rotate_Camera(float f1, int i, float f2, float f3) override; - virtual void Rotate_Camera_Toward_Object(ObjectID id, int i1, int i2, float f1, float f2) override; - virtual void Rotate_Camera_Toward_Position(const Coord3D *o, int i, float f1, float f2, bool b) override; + virtual void Reset_Camera(const Coord3D *location, int frames, float in, float out) override; + virtual void Rotate_Camera(float rotations, int frames, float in, float out) override; + virtual void Rotate_Camera_Toward_Object( + ObjectID id, int milliseconds, int hold_milliseconds, float in, float out) override; + virtual void Rotate_Camera_Toward_Position(const Coord3D *p_loc, int milliseconds, float in, float out, bool b) override; virtual bool Is_Time_Frozen() override; virtual int Get_Time_Multiplier() override; - virtual void Set_Time_Multiplier(int multiplier) override; - virtual void Set_Default_View(float f1, float f2, float f3) override; - virtual void Zoom_Camera(float f1, int i, float f2, float f3) override; - virtual void Pitch_Camera(float f1, int i, float f2, float f3) override; + virtual void Set_Time_Multiplier(int multiple) override; + virtual void Set_Default_View(float pitch, float angle, float max_height) override; + virtual void Zoom_Camera(float final_zoom, int milliseconds, float in, float out) override; + virtual void Pitch_Camera(float final_pitch, int milliseconds, float in, float out) override; virtual void Set_Angle(float angle) override; virtual void Set_Pitch(float pitch) override; virtual void Set_Angle_And_Pitch_To_Default() override; virtual const Coord3D &Get_3D_Camera_Position() override; - virtual void Set_Zoom(float zoom) override; - virtual void Set_Height_Above_Ground(float height) override; + virtual void Set_Zoom(float z) override; + virtual void Set_Height_Above_Ground(float z) override; virtual void Set_Zoom_To_Default() override; - virtual void Set_Field_Of_View(float fov) override; - virtual int World_To_Screen_Tri_Return(const Coord3D *o1, ICoord2D *o2) override; - virtual void Screen_To_World(const ICoord2D *o1, Coord3D *o2) override; - virtual void Screen_To_Terrain(const ICoord2D *o1, Coord3D *o2) override; - virtual void Screen_To_World_At_Z(const ICoord2D *o1, Coord3D *o2, float f) override; + virtual void Set_Field_Of_View(float angle) override; + virtual int World_To_Screen_Tri_Return(const Coord3D *w, ICoord2D *s) override; + virtual void Screen_To_World(const ICoord2D *s, Coord3D *w) override; + virtual void Screen_To_Terrain(const ICoord2D *screen, Coord3D *world) override; + virtual void Screen_To_World_At_Z(const ICoord2D *s, Coord3D *w, float z) override; virtual void Draw_View() override; virtual void Update_View() override; virtual void Set_Camera_Lock(ObjectID id) override; - virtual void Set_Snap_Mode(CameraLockType type, float dist) override; - virtual void Shake(const Coord3D *o, CameraShakeType type) override; + virtual void Set_Snap_Mode(CameraLockType lock_type, float lock_dist) override; + virtual void Shake(const Coord3D *epicenter, CameraShakeType shake_type) override; virtual float Get_FX_Pitch() override; virtual void Force_Camera_Constraint_Recalc() override; - virtual void Set_Guard_Band_Bias(Coord2D *) override; + virtual void Set_Guard_Band_Bias(Coord2D *bias) override; virtual bool Is_Camera_Movement_At_Waypoint_Along_Path(); virtual void Camera_Enable_Real_Zoom_Mode(); virtual void Camera_Disable_Real_Zoom_Mode(); + virtual void Update() override; + virtual void Draw() override; + bool Update_Camera_Movements(); CameraClass *Get_3D_Camera() { return m_3DCamera; } private: + void Build_Camera_Transform(Matrix3D *transform); + void Calc_Camera_Constraints(); + void Get_Pick_Ray(const ICoord2D *screen, Vector3 *ray_start, Vector3 *ray_end); + void Set_Camera_Transform(); + void Get_Axis_Aligned_View_Region(Region3D &axis_aligned_region); + void Calc_Delta_Scroll(Coord2D &screen_delta); + void Setup_Waypoint_Path(bool b); + void Rotate_Camera_One_Frame(); + void Zoom_Camera_One_Frame(); + void Pitch_Camera_One_Frame(); + void Move_Along_Waypoint_Path(int milliseconds); + CameraClass *m_3DCamera; + CameraClass *m_2DCamera; + FilterModes m_viewFilterMode; + FilterTypes m_viewFilter; + bool m_extraPass; + bool m_wireframeMode; + Coord2D m_shakeOffset; + float m_shakeAngleCos; + float m_shakeAngleSin; + float m_shakeIntensity; + Vector3 m_cameraShakeAngles; + TRotateCameraInfo m_rcInfo; + bool m_doingRotateCamera; + TPitchCameraInfo m_pcInfo; + bool m_doingPitchCamera; + TZoomCameraInfo m_zcInfo; + bool m_doingZoomCamera; + bool m_doingScriptedCameraLock; + float m_FXPitch; + TMoveAlongWaypointPathInfo m_mcwpInfo; + bool m_doingMoveCameraOnWaypointPath; + bool m_doingMoveCameraAlongWaypointPath; + bool m_freezeTimeForCameraMovement; + int m_timeMultiplier; + bool m_cameraHasMovedSinceRequest; + std::vector> m_locationRequests; + Coord3D m_cameraOffset; + Coord3D m_previousLookAtPosition; + Coord2D m_scrollAmount; + float m_scrollAmountCutoff; + float m_groundLevel; + Region2D m_cameraConstraint; + bool m_cameraConstraintValid; + bool m_cameraSlaveMode; + bool m_realZoom; + Utf8String m_cameraSlaveThing; + Utf8String m_cameraSlaveBone; };