Skip to content

Commit a1d7325

Browse files
authored
fix(view): Improve setup of default camera pitch and angle (#2546)
This adds two new meta events: DEMO_BEGIN_ADJUST_DEFAULTPITCH, DEMO_END_ADJUST_DEFAULTPITCH, which are default mapped to CTRL + MK_COMMA
1 parent cb2fe91 commit a1d7325

18 files changed

Lines changed: 209 additions & 18 deletions

File tree

Core/GameEngine/Include/GameClient/View.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "Common/Snapshot.h"
3535
#include "Lib/BaseType.h"
3636
#include "WW3D2/coltype.h" ///< we don't generally do this, but we need the W3D collision types
37+
#include "WWMath/wwmath.h"
3738

3839
#define DEFAULT_VIEW_WIDTH 640
3940
#define DEFAULT_VIEW_HEIGHT 480
@@ -50,7 +51,9 @@ enum FilterTypes CPP_11(: Int);
5051
enum FilterModes CPP_11(: Int);
5152

5253
// ------------------------------------------------------------------------------------------------
53-
// ------------------------------------------------------------------------------------------------
54+
constexpr const Real ViewDefaultPitchRadians = DEG_TO_RADF(37.5f);
55+
constexpr const Real ViewDefaultYawRadians = DEG_TO_RADF(0.0f);
56+
5457
// ------------------------------------------------------------------------------------------------
5558
enum PickType CPP_11(: Int)
5659
{
@@ -177,8 +180,11 @@ class View : public Snapshot
177180

178181
virtual void setAngle( Real radians ); ///< Rotate the view around the vertical axis to the given angle (yaw)
179182
virtual Real getAngle() { return m_angle; } ///< Return current camera angle
183+
virtual Real getDefaultAngle() { return m_defaultAngle; } ///< Return current default camera angle
180184
virtual void setPitch( Real radians ); ///< Rotate the view around the horizontal axis to the given angle (pitch)
181185
virtual Real getPitch() { return m_pitch; } ///< Return current camera pitch
186+
virtual void setDefaultPitch( Real radians ); ///< Set new default camera pitch. It affects the camera distance to the ground
187+
virtual Real getDefaultPitch() { return m_defaultPitch; } ///< Return current default camera pitch
182188
virtual void setAngleToDefault(); ///< Set the view angle back to default
183189
virtual void setPitchToDefault(); ///< Set the view pitch back to default
184190
void setPosition( const Coord3D *pos ) { m_pos = *pos; }
@@ -199,6 +205,7 @@ class View : public Snapshot
199205
Bool userSetAngle(Real radians) { return doUserAction(&View::setAngle, radians); }
200206
Bool userSetAngleToDefault() { return doUserAction(&View::setAngleToDefault); }
201207
Bool userSetPitch(Real radians) { return doUserAction(&View::setPitch, radians); }
208+
Bool userSetDefaultPitch(Real radians) { return doUserAction(&View::setDefaultPitch, radians); }
202209
Bool userSetPitchToDefault() { return doUserAction(&View::setPitchToDefault); }
203210
Bool userZoom(Real height) { return doUserAction(&View::zoom, height); }
204211
Bool userSetZoom(Real z) { return doUserAction(&View::setZoom, z); }

Core/GameEngine/Source/GameClient/View.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,10 @@ void View::init()
102102
m_minHeightAboveGround = TheGlobalData->m_minCameraHeight;
103103
m_okToAdjustHeight = FALSE;
104104

105-
m_defaultAngle = 0.0f;
106-
m_defaultPitch = 0.0f;
105+
m_defaultAngle = DEG_TO_RADF(TheGlobalData->m_cameraYaw);
106+
m_defaultPitch = DEG_TO_RADF(TheGlobalData->m_cameraPitch);
107+
m_angle = m_defaultAngle;
108+
m_pitch = m_defaultPitch;
107109
}
108110

109111
void View::reset()
@@ -160,13 +162,26 @@ void View::setAngle( Real radians )
160162
m_angle = WWMath::Normalize_Angle(radians);
161163
}
162164

165+
#define CLAMP_VIEW_PITCH 1
163166
/**
164167
* Rotate the view around the horizontal (X) axis to the given angle.
165168
*/
166169
void View::setPitch( Real radians )
167170
{
168-
constexpr Real limit = PI/5.0f;
169-
m_pitch = clamp(-limit, radians, limit);
171+
#if CLAMP_VIEW_PITCH
172+
m_pitch = clamp(DEG_TO_RADF(0.1f), radians, DEG_TO_RADF(89.9f));
173+
#else
174+
m_pitch = WWMath::Normalize_Angle(radians);
175+
#endif
176+
}
177+
178+
void View::setDefaultPitch( Real radians )
179+
{
180+
#if CLAMP_VIEW_PITCH
181+
m_defaultPitch = clamp(DEG_TO_RADF(0.1f), radians, DEG_TO_RADF(89.9f));
182+
#else
183+
m_defaultPitch = WWMath::Normalize_Angle(radians);
184+
#endif
170185
}
171186

172187
/**

Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ class W3DView : public View, public SubsystemInterface
171171

172172
virtual void setAngle( Real radians ) override; ///< Rotate the view around the vertical axis to the given angle (yaw)
173173
virtual void setPitch( Real radians ) override; ///< Rotate the view around the horizontal axis to the given angle (pitch)
174+
virtual void setDefaultPitch( Real radians ) override; ///< Set new default camera pitch. It affects the camera distance to the ground
174175
virtual void setAngleToDefault() override; ///< Set the view angle back to default
175176
virtual void setPitchToDefault() override; ///< Set the view pitch back to default
176177

Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ void W3DView::buildCameraPosition( Vector3& sourcePos, Vector3& targetPos )
264264
// TheSuperHackers @info The default pitch affects the look-at distance to the target.
265265
// This is strange math which would need special attention when changed.
266266
sourcePos.Z = getCameraOffsetZ();
267-
sourcePos.Y = -(sourcePos.Z / tan(TheGlobalData->m_cameraPitch * (PI / 180.0)));
268-
sourcePos.X = -(sourcePos.Y * tan(TheGlobalData->m_cameraYaw * (PI / 180.0)));
267+
sourcePos.Y = -(sourcePos.Z / tan(ViewDefaultPitchRadians));
268+
sourcePos.X = -(sourcePos.Y * tan(ViewDefaultYawRadians));
269269

270270
// set position of camera itself
271271
if (m_useRealZoomCam) //WST 10/10/2002 Real Zoom using FOV
@@ -285,13 +285,15 @@ void W3DView::buildCameraPosition( Vector3& sourcePos, Vector3& targetPos )
285285
targetPos.Y = 0;
286286
targetPos.Z = 0;
287287

288+
// TheSuperHackers @info Scales the source position later by this much
289+
// to achieve the intended camera height. Must not scale before pitching!
288290
const Real heightScale = 1.0f - (groundLevel / sourcePos.Z);
289291

290292
// construct a matrix to rotate around the up vector by the given angle
291-
const Matrix3D angleTransform( Vector3( 0.0f, 0.0f, 1.0f ), angle );
293+
const Matrix3D angleTransform( Vector3( 0.0f, 0.0f, 1.0f ), angle - ViewDefaultYawRadians );
292294

293295
// construct a matrix to rotate around the left vector by the given angle
294-
const Matrix3D pitchTransform( Vector3( -1.0f, 0.0f, 0.0f ), pitch );
296+
const Matrix3D pitchTransform( Vector3( -1.0f, 0.0f, 0.0f ), pitch - ViewDefaultPitchRadians );
295297

296298
// rotate camera position (pitch, then angle)
297299
#ifdef ALLOW_TEMPORARIES
@@ -2067,6 +2069,16 @@ void W3DView::setPitch( Real radians )
20672069
m_recalcCamera = true;
20682070
}
20692071

2072+
//-------------------------------------------------------------------------------------------------
2073+
//-------------------------------------------------------------------------------------------------
2074+
void W3DView::setDefaultPitch( Real radians )
2075+
{
2076+
View::setDefaultPitch( radians );
2077+
2078+
m_cameraAreaConstraintsValid = false;
2079+
m_recalcCamera = true;
2080+
}
2081+
20702082
//-------------------------------------------------------------------------------------------------
20712083
/** Set the view angle back to default */
20722084
//-------------------------------------------------------------------------------------------------
@@ -2098,7 +2110,7 @@ void W3DView::setDefaultView(Real pitch, Real angle, Real maxHeight)
20982110
{
20992111
// MDC - we no longer want to rotate maps (design made all of them right to begin with)
21002112
// m_defaultAngle = angle * M_PI/180.0f;
2101-
m_defaultPitch = pitch;
2113+
setDefaultPitch(pitch);
21022114
m_maxHeightAboveGround = TheGlobalData->m_maxCameraHeight*maxHeight;
21032115
if (m_minHeightAboveGround > m_maxHeightAboveGround)
21042116
m_maxHeightAboveGround = m_minHeightAboveGround;

Generals/Code/GameEngine/Include/Common/MessageStream.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ class GameMessage : public MemoryPoolObject
218218
MSG_META_SELECT_PREV_UNIT, ///< select 'prev' unit
219219
MSG_META_SELECT_NEXT_WORKER, ///< select 'next' worker
220220
MSG_META_SELECT_PREV_WORKER, ///< select 'prev' worker
221-
MSG_META_SELECT_NEXT_IDLE_WORKER, ///< TheSuperHackers @feature L3-M 03/08/2025 select next idle worker
221+
MSG_META_SELECT_NEXT_IDLE_WORKER, ///< TheSuperHackers @feature L3-M 03/08/2025 select next idle worker
222222
MSG_META_VIEW_COMMAND_CENTER, ///< center view on command center
223223
MSG_META_VIEW_LAST_RADAR_EVENT, ///< center view on last radar event
224224
MSG_META_SELECT_HERO, ///< selects player's hero character, if exists...
@@ -319,6 +319,8 @@ class GameMessage : public MemoryPoolObject
319319
MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE6, ///< play specific "Objective" movie
320320
MSG_META_DEMO_BEGIN_ADJUST_PITCH, ///< enter adjust-pitch mode
321321
MSG_META_DEMO_END_ADJUST_PITCH, ///< exit adjust-pitch mode
322+
MSG_META_DEMO_BEGIN_ADJUST_DEFAULTPITCH, ///< TheSuperHackers @feature Enter adjust-default-pitch mode
323+
MSG_META_DEMO_END_ADJUST_DEFAULTPITCH, ///< TheSuperHackers @feature Exit adjust-default-pitch mode
322324
MSG_META_DEMO_BEGIN_ADJUST_FOV, ///< enter adjust-FOV mode
323325
MSG_META_DEMO_END_ADJUST_FOV, ///< exit adjust-FOV mode
324326
MSG_META_DEMO_LOCK_CAMERA_TO_PLANES, ///< lock camera to airborne thingies

Generals/Code/GameEngine/Include/GameClient/LookAtXlat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ class LookAtTranslator : public GameMessageTranslator
7474
Real m_anchorAngle;
7575
Bool m_isScrolling; // set to true if we are in the act of RMB scrolling
7676
Bool m_isRotating; // set to true if we are in the act of MMB rotating
77-
Bool m_isPitching; // set to true if we are in the act of ALT pitch rotation
77+
Bool m_isPitching; // set to true if we are in the act of pitch rotation
78+
Bool m_isPitchingToDefault; // set to true if we are in the act of default pitch rotation
7879
Bool m_isChangingFOV; // set to true if we are in the act of changing the field of view
7980
UnsignedInt m_middleButtonDownTimeMsec; // real-time in milliseconds when middle button goes down
8081
DrawableID m_lastPlaneID;

Generals/Code/GameEngine/Source/Common/MessageStream.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ const char *GameMessage::getCommandTypeAsString(GameMessage::Type t)
326326
CASE_LABEL(MSG_META_SELECT_PREV_UNIT)
327327
CASE_LABEL(MSG_META_SELECT_NEXT_WORKER)
328328
CASE_LABEL(MSG_META_SELECT_PREV_WORKER)
329+
CASE_LABEL(MSG_META_SELECT_NEXT_IDLE_WORKER)
329330
CASE_LABEL(MSG_META_VIEW_COMMAND_CENTER)
330331
CASE_LABEL(MSG_META_VIEW_LAST_RADAR_EVENT)
331332
CASE_LABEL(MSG_META_SELECT_HERO)
@@ -368,8 +369,10 @@ const char *GameMessage::getCommandTypeAsString(GameMessage::Type t)
368369
CASE_LABEL(MSG_META_TOGGLE_ATTACKMOVE)
369370
CASE_LABEL(MSG_META_BEGIN_CAMERA_ROTATE_LEFT)
370371
CASE_LABEL(MSG_META_END_CAMERA_ROTATE_LEFT)
372+
CASE_LABEL(MSG_META_ALT_CAMERA_ROTATE_LEFT)
371373
CASE_LABEL(MSG_META_BEGIN_CAMERA_ROTATE_RIGHT)
372374
CASE_LABEL(MSG_META_END_CAMERA_ROTATE_RIGHT)
375+
CASE_LABEL(MSG_META_ALT_CAMERA_ROTATE_RIGHT)
373376
CASE_LABEL(MSG_META_BEGIN_CAMERA_ZOOM_IN)
374377
CASE_LABEL(MSG_META_END_CAMERA_ZOOM_IN)
375378
CASE_LABEL(MSG_META_BEGIN_CAMERA_ZOOM_OUT)
@@ -419,6 +422,8 @@ const char *GameMessage::getCommandTypeAsString(GameMessage::Type t)
419422
CASE_LABEL(MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE6)
420423
CASE_LABEL(MSG_META_DEMO_BEGIN_ADJUST_PITCH)
421424
CASE_LABEL(MSG_META_DEMO_END_ADJUST_PITCH)
425+
CASE_LABEL(MSG_META_DEMO_BEGIN_ADJUST_DEFAULTPITCH)
426+
CASE_LABEL(MSG_META_DEMO_END_ADJUST_DEFAULTPITCH)
422427
CASE_LABEL(MSG_META_DEMO_BEGIN_ADJUST_FOV)
423428
CASE_LABEL(MSG_META_DEMO_END_ADJUST_FOV)
424429
CASE_LABEL(MSG_META_DEMO_LOCK_CAMERA_TO_PLANES)

Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,10 @@ void InGameUI::init()
13461346
// make the tactical display the full screen width and height
13471347
TheTacticalView->setWidth( TheDisplay->getWidth() );
13481348
TheTacticalView->setHeight( TheDisplay->getHeight() );
1349-
TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f);
1349+
TheTacticalView->setDefaultView(
1350+
DEG_TO_RADF(TheGlobalData->m_cameraPitch),
1351+
DEG_TO_RADF(TheGlobalData->m_cameraYaw),
1352+
1.0f);
13501353
}
13511354

13521355
/** @todo this may be the wrong place to create the sidebar, but for now
@@ -2091,7 +2094,10 @@ void InGameUI::reset()
20912094
// reset the command bar
20922095
TheControlBar->reset();
20932096

2094-
TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f);
2097+
TheTacticalView->setDefaultView(
2098+
DEG_TO_RADF(TheGlobalData->m_cameraPitch),
2099+
DEG_TO_RADF(TheGlobalData->m_cameraYaw),
2100+
1.0f);
20952101

20962102
ResetInGameChat();
20972103

Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ LookAtTranslator::LookAtTranslator() :
136136
m_isScrolling(false),
137137
m_isRotating(false),
138138
m_isPitching(false),
139+
m_isPitchingToDefault(false),
139140
m_isChangingFOV(false),
140141
m_middleButtonDownTimeMsec(0),
141142
m_lastPlaneID(INVALID_DRAWABLE_ID),
@@ -389,6 +390,15 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
389390
}
390391

391392
#if defined(RTS_DEBUG)
393+
if (m_isPitchingToDefault)
394+
{
395+
constexpr const Real Scale = 0.01f;
396+
const Real angle = Scale * (m_currentPos.y - m_anchor.y);
397+
TheTacticalView->userSetDefaultPitch( TheTacticalView->getDefaultPitch() - angle );
398+
TheTacticalView->userSetPitchToDefault();
399+
m_anchor = msg->getArgument( 0 )->pixel;
400+
}
401+
392402
// adjust the field of view
393403
if (m_isChangingFOV)
394404
{
@@ -565,6 +575,29 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
565575
}
566576
#endif // #if defined(RTS_DEBUG)
567577

578+
// ------------------------------------------------------------------------
579+
#if defined(RTS_DEBUG)
580+
case GameMessage::MSG_META_DEMO_BEGIN_ADJUST_DEFAULTPITCH:
581+
{
582+
DEBUG_ASSERTCRASH(!m_isPitchingToDefault, ("hmm, mismatched m_isPitchingToDefault"));
583+
m_isPitchingToDefault = true;
584+
m_anchor = m_currentPos;
585+
disp = DESTROY_MESSAGE;
586+
break;
587+
}
588+
#endif // #if defined(RTS_DEBUG)
589+
590+
// ------------------------------------------------------------------------
591+
#if defined(RTS_DEBUG)
592+
case GameMessage::MSG_META_DEMO_END_ADJUST_DEFAULTPITCH:
593+
{
594+
DEBUG_ASSERTCRASH(m_isPitchingToDefault, ("hmm, mismatched m_isPitchingToDefault"));
595+
m_isPitchingToDefault = false;
596+
disp = DESTROY_MESSAGE;
597+
break;
598+
}
599+
#endif // #if defined(RTS_DEBUG)
600+
568601
// ------------------------------------------------------------------------
569602
#if defined(RTS_DEBUG)
570603
case GameMessage::MSG_META_DEMO_DESHROUD:
@@ -722,5 +755,6 @@ void LookAtTranslator::resetModes()
722755
m_isScrolling = FALSE;
723756
m_isRotating = FALSE;
724757
m_isPitching = FALSE;
758+
m_isPitchingToDefault = FALSE;
725759
m_isChangingFOV = FALSE;
726760
}

Generals/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ static const LookupListRec GameMessageMetaTypeNames[] =
229229
{ "DEMO_PLAY_OBJECTIVE_MOVIE6", GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE6 },
230230
{ "DEMO_BEGIN_ADJUST_PITCH", GameMessage::MSG_META_DEMO_BEGIN_ADJUST_PITCH },
231231
{ "DEMO_END_ADJUST_PITCH", GameMessage::MSG_META_DEMO_END_ADJUST_PITCH },
232+
{ "DEMO_BEGIN_ADJUST_DEFAULTPITCH", GameMessage::MSG_META_DEMO_BEGIN_ADJUST_DEFAULTPITCH },
233+
{ "DEMO_END_ADJUST_DEFAULTPITCH", GameMessage::MSG_META_DEMO_END_ADJUST_DEFAULTPITCH },
232234
{ "DEMO_BEGIN_ADJUST_FOV", GameMessage::MSG_META_DEMO_BEGIN_ADJUST_FOV },
233235
{ "DEMO_END_ADJUST_FOV", GameMessage::MSG_META_DEMO_END_ADJUST_FOV },
234236
{ "DEMO_LOCK_CAMERA_TO_PLANES", GameMessage::MSG_META_DEMO_LOCK_CAMERA_TO_PLANES },
@@ -837,6 +839,28 @@ MetaMapRec *MetaMap::getMetaMapRec(GameMessage::Type t)
837839
map->m_usableIn = COMMANDUSABLE_GAME;
838840
}
839841
}
842+
{
843+
// Is useful for Generals and Zero Hour.
844+
MetaMapRec *map = TheMetaMap->getMetaMapRec(GameMessage::MSG_META_DEMO_BEGIN_ADJUST_DEFAULTPITCH);
845+
if (map->m_key == MK_NONE)
846+
{
847+
map->m_key = MK_COMMA;
848+
map->m_transition = DOWN;
849+
map->m_modState = CTRL;
850+
map->m_usableIn = COMMANDUSABLE_GAME;
851+
}
852+
}
853+
{
854+
// Is useful for Generals and Zero Hour.
855+
MetaMapRec *map = TheMetaMap->getMetaMapRec(GameMessage::MSG_META_DEMO_END_ADJUST_DEFAULTPITCH);
856+
if (map->m_key == MK_NONE)
857+
{
858+
map->m_key = MK_COMMA;
859+
map->m_transition = UP;
860+
map->m_modState = CTRL;
861+
map->m_usableIn = COMMANDUSABLE_GAME;
862+
}
863+
}
840864
#endif // defined(RTS_DEBUG)
841865
}
842866

0 commit comments

Comments
 (0)