From b5d9da29c18db6a4ce4c2a93201767bd07114ee0 Mon Sep 17 00:00:00 2001 From: pyrolink Date: Sat, 22 Apr 2006 05:52:23 +0000 Subject: [PATCH] #When appropriate (i.e. wheeled units), units will align with the slope of the terrain. *JS documentation *added CTerrain::getSlopeAngle[Face]() which returns the angle in radians of the slope of the terrain. getSlopeAngleFace should be used for entities because it takes into account which way the entity is facing, which allows for negative angles. *the max and min graphical rotation for the slope is under traits.pitch. This is used so that you can have certain units such as infantry that don't rotate very far go down steep slopes but not rotate too much. *JS documentation in docs/JSReg.rtf -- I put in most of the relevant global functions; still needs entity functions. This was SVN commit r3794. --- docs/JSReg.rtf | Bin 0 -> 6541 bytes source/graphics/CinemaTrack.h | 2 - source/graphics/GameView.cpp | 2 - source/graphics/Terrain.cpp | 160 +++++++++++++++++++- source/graphics/Terrain.h | 4 +- source/simulation/BaseEntity.cpp | 2 + source/simulation/BaseEntity.h | 3 + source/simulation/Entity.cpp | 64 ++++---- source/simulation/Entity.h | 7 + source/simulation/EntityStateProcessing.cpp | 8 +- 10 files changed, 212 insertions(+), 40 deletions(-) create mode 100644 docs/JSReg.rtf diff --git a/docs/JSReg.rtf b/docs/JSReg.rtf new file mode 100644 index 0000000000000000000000000000000000000000..78847fb341320640251b42ad6ea40352796a5dd3 GIT binary patch literal 6541 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 literal 0 HcmV?d00001 diff --git a/source/graphics/CinemaTrack.h b/source/graphics/CinemaTrack.h index 62d0a404d5..66da50f633 100644 --- a/source/graphics/CinemaTrack.h +++ b/source/graphics/CinemaTrack.h @@ -19,8 +19,6 @@ #include "CStr.h" #include "NUSpline.h" -#include -#include /* Andrew (aka pyrolink) diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 66e70820ab..a375ff4a25 100755 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -390,8 +390,6 @@ void CGameView::CameraLock(float x, float y, float z, bool smooth) m_ViewCamera.m_Orientation.Translate(x, y, z); m_ViewCamera.m_Orientation._24=height; } - - } } diff --git a/source/graphics/Terrain.cpp b/source/graphics/Terrain.cpp index 515b9ac465..c7dfd396b4 100755 --- a/source/graphics/Terrain.cpp +++ b/source/graphics/Terrain.cpp @@ -53,8 +53,6 @@ bool CTerrain::Initialize(u32 size,const u16* data) // store terrain size m_MapSize=(size*PATCH_SIZE)+1; m_MapSizePatches=size; -// WaterManager *WaterMgr = g_Renderer.GetWaterManager(); -// WaterMgr->InitWave(); // allocate data for new terrain m_Heightmap=new u16[m_MapSize*m_MapSize]; m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches]; @@ -204,10 +202,166 @@ float CTerrain::getSlope(float x, float z) const float h01 = m_Heightmap[zi*m_MapSize + xi + m_MapSize]; float h10 = m_Heightmap[zi*m_MapSize + xi + 1]; float h11 = m_Heightmap[zi*m_MapSize + xi + m_MapSize + 1]; - + + //Difference of highest point from lowest point return MAX(MAX(h00, h01), MAX(h10, h11)) - MIN(MIN(h00, h01), MIN(h10, h11)); } +float CTerrain::getSlopeAngle( float x, float y ) const +{ + float fCell = (float)CELL_SIZE; + x /= fCell; + y /= fCell; + int xi = (int)floor(x); + int yi = (int)floor(y); + + //Keep it in bounds + if (xi < 0) + xi = 0; + else if (xi >= (int)m_MapSize-1) + xi = m_MapSize - 2; + if (yi < 0) + yi = 0; + else if (yi >= (int)m_MapSize-1) + yi = m_MapSize - 2; + + float h00 = m_Heightmap[yi*m_MapSize + xi] * HEIGHT_SCALE; + float h01 = m_Heightmap[yi*m_MapSize + xi + m_MapSize] * HEIGHT_SCALE; + float h10 = m_Heightmap[yi*m_MapSize + xi + 1] * HEIGHT_SCALE; + float h11 = m_Heightmap[yi*m_MapSize + xi + m_MapSize + 1] * HEIGHT_SCALE; + + CVector3D flat, elevated; + float low, high; + + if ( h00 < h01 && h00 < h10 && h00 < h11 ) + low = h00; + else if ( h01 < h10 && h01 < h11 ) + low = h01; + else if ( h10 < h11 ) + low = h10; + else + low = h11; + + //Find correct vector representing the flat version of the vector from low to high points + if ( h00 > h01 && h00 > h10 && h00 > h11 ) + { + high = h00; + if ( low == h10 ) + flat = CVector3D( fCell, 0.0f, 0.0f ); + else if ( low == h01 ) + flat = CVector3D( 0.0f, 0.0f, fCell ); + else if ( low == h11 ) + flat = CVector3D( fCell, 0.0f, fCell ); + } + else if ( h01 > h10 && h01 > h11 ) + { + high = h01; + if ( low == h00 ) + flat = CVector3D( 0.0f, 0.0f, fCell ); + else if ( low == h01 ) + flat = CVector3D( fCell, 0.0f, fCell ); + else if ( low == h11 ) + flat = CVector3D( fCell, 0.0f, 0.0f ); + } + else if ( h10 > h11 ) + { + high = h10; + if ( low == h00 ) + flat = CVector3D( fCell, 0.0f, 0.0f ); + else if ( low == h01 ) + flat = CVector3D( fCell, 0.0f, fCell ); + else if ( low == h11 ) + flat = CVector3D( 0.0f, 0.0f, fCell ); + } + else + { + high = h11; + if ( low == h10 ) + flat = CVector3D( 0.0f, 0.0f, fCell ); + else if ( low == h01 ) + flat = CVector3D( fCell, 0.0f, 0.0f ); + else if ( low == h00 ) + flat = CVector3D( fCell, 0.0f, fCell ); + } + elevated = flat; + elevated.Y = high - low; + elevated.Normalize(); + flat.Normalize(); + return acosf( flat.Dot( elevated ) ); +} +float CTerrain::getSlopeAngleFace(float x, float y, float orientation) const +{ + bool right; //true means use 0,0 and 1,1; false means use 1,0 and 0,1 + bool invert; + float top, bottom; + x /= (float)CELL_SIZE; + y /= (float)CELL_SIZE; + int xi = (int)floor(x); + int yi = (int)floor(y); + CVector3D flat( (float)CELL_SIZE, 0.0f, (float)CELL_SIZE ); + CVector3D elevated=flat; + + float a0 = DEGTORAD(0.0f); + float a90 = DEGTORAD(90.0f); + float a180 = DEGTORAD(180.0f); + float neg = DEGTORAD(-90.0f); + float a45 = DEGTORAD(45.0f); + float a135 = DEGTORAD(135.0f); + + //Find which side it's facing; use that and the opposite + if ( orientation > 0.0f && orientation < DEGTORAD(90.0f) ) + right = true; + else if ( orientation > DEGTORAD(90.0f) && orientation < DEGTORAD(180.0f) ) + right = false; + else if ( orientation < DEGTORAD(-180.0f) && orientation > DEGTORAD(-90.0f) ) + right = true; + else + right = false; + + //Keep it in bounds + if (xi < 0) + xi = 0; + else if (xi >= (int)m_MapSize-1) + xi = m_MapSize - 2; + if (yi < 0) + yi = 0; + else if (yi >= (int)m_MapSize-1) + yi = m_MapSize - 2; + + if ( right ) + { + bottom = m_Heightmap[yi*m_MapSize + xi]*HEIGHT_SCALE; + top = m_Heightmap[yi*m_MapSize+m_MapSize + xi + 1]*HEIGHT_SCALE; + if ( (orientation > DEGTORAD(-45.0f) && orientation < 0.0f) || + (orientation < DEGTORAD(135.0f) && orientation > 0.0f) ) + elevated.Y = top-bottom; + else + elevated.Y = bottom-top; + } + else + { + bottom = m_Heightmap[yi*m_MapSize + xi + 1]*HEIGHT_SCALE; + top = m_Heightmap[yi*m_MapSize+m_MapSize + xi]*HEIGHT_SCALE; + if ( (orientation > DEGTORAD(-135.0f) && orientation < 0.0f) || + (orientation < DEGTORAD(45.0f) && orientation > 0.0f) ) + elevated.Y = top-bottom; + else + elevated.Y = bottom-top; + } + if ( elevated.Y > 0.0f ) + invert=false; + else + invert=true; + elevated.Y = fabs(elevated.Y); + elevated.Normalize(); + flat.Normalize(); + float ret = elevated.Dot(flat); + + if (invert) + return -acosf(ret); + return acosf(ret); + +} float CTerrain::getExactGroundLevel(float x, float z) const { diff --git a/source/graphics/Terrain.h b/source/graphics/Terrain.h index 4c71fd8d17..34bef90890 100755 --- a/source/graphics/Terrain.h +++ b/source/graphics/Terrain.h @@ -45,7 +45,9 @@ public: inline float getExactGroundLevel(const CVector2D& v) const { return getExactGroundLevel(v.x, v.y); } float getSlope(float x, float z) const ; - + float getSlopeAngle( float x, float y) const; //In radians + //Same as above, but picks the two vertices that the unit is facing (front+back) for slope + float getSlopeAngleFace(float x, float y, float orientation) const; // resize this terrain such that each side has given number of patches void Resize(u32 size); diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index 4429db6505..106cba9296 100755 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -49,6 +49,8 @@ CBaseEntity::CBaseEntity() AddProperty( L"traits.stamina.border_name", &m_staminaBorderName ); AddProperty( L"traits.angle_penalty.sectors", &m_sectorDivs ); AddProperty( L"traits.angle_penalty.value", &m_sectorPenalty ); + AddProperty( L"traits.pitch.max_actor", &m_maxActorPitch ); + AddProperty( L"traits.pitch.min_actor", &m_minActorPitch ); AddProperty( L"traits.rank.width", &m_rankWidth ); AddProperty( L"traits.rank.height", &m_rankHeight ); AddProperty( L"traits.rank.name", &m_rankName ); diff --git a/source/simulation/BaseEntity.h b/source/simulation/BaseEntity.h index 9b3ebfa1e2..e1dbdf3737 100755 --- a/source/simulation/BaseEntity.h +++ b/source/simulation/BaseEntity.h @@ -113,6 +113,9 @@ public: int m_sectorDivs; float m_sectorPenalty; + float m_maxActorPitch; + float m_minActorPitch; + float m_turningRadius; CScriptObject m_EventHandlers[EVENT_LAST]; diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index dd76e07d4f..652e574f92 100755 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -79,6 +79,8 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons AddProperty( L"traits.stamina.border_name", &m_staminaBorderName ); AddProperty( L"traits.angle_penalty.sectors", &m_sectorDivs); AddProperty( L"traits.angle_penalty.value", &m_sectorPenalty ); + AddProperty( L"traits.pitch.max_actor", &m_maxActorPitch ); + AddProperty( L"traits.pitch.min_actor", &m_minActorPitch ); AddProperty( L"traits.rank.width", &m_rankWidth ); AddProperty( L"traits.rank.height", &m_rankHeight ); AddProperty( L"traits.rank.name", &m_rankName ); @@ -101,10 +103,6 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons AddHandler( t, &m_EventHandlers[t] ); } -// FIXME: janwas: this was uninitialized, which leads to disaster if -// its value happens to be positive. -// setting to what seems to be a reasonable default. - m_sectorDivs = 4; if ( m_sectorDivs >= 0 ) { m_sectorAngles.resize(m_sectorDivs); @@ -143,6 +141,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons m_graphics_orientation = m_orientation; m_actor_transform_valid = false; + m_pitchOrientation = m_pitchOrientation_previous = m_graphics_pitchOrientation = 0.0f; m_destroyed = false; m_selected = false; @@ -158,7 +157,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons m_currentRequest = 0; m_destroyNotifiers = true; - m_formationSlot = -1; + m_formationSlot = -1; m_formation = -1; m_grouped = -1; @@ -277,29 +276,22 @@ void CEntity::SetPlayer(CPlayer *pPlayer) void CEntity::updateActorTransforms() { CMatrix3D m; + CMatrix3D mX; + float Cos = cosf( m_graphics_orientation ); + float Sin = sinf( m_graphics_orientation ); - float s = sin( m_graphics_orientation ); - float c = cos( m_graphics_orientation ); - - m._11 = -c; - m._12 = 0.0f; - m._13 = -s; - m._14 = m_graphics_position.X; - m._21 = 0.0f; - m._22 = 1.0f; - m._23 = 0.0f; - m._24 = m_graphics_position.Y; - m._31 = s; - m._32 = 0.0f; - m._33 = -c; - m._34 = m_graphics_position.Z; - m._41 = 0.0f; - m._42 = 0.0f; - m._43 = 0.0f; - m._44 = 1.0f; + m._11=-Cos; m._12=0.0f; m._13=-Sin; m._14=0.0f; + m._21=0.0f; m._22=1.0f; m._23=0.0f; m._24=0.0f; + m._31=Sin; m._32=0.0f; m._33=-Cos; m._34=0.0f; + m._41=0.0f; m._42=0.0f; m._43=0.0f; m._44=1.0f; + + mX.SetXRotation( m_graphics_pitchOrientation ); + mX = m*mX; + mX.Translate(m_graphics_position); + //m.RotateX(m_graphics_pitchOrientation); if( m_actor ) - m_actor->GetModel()->SetTransform( m ); + m_actor->GetModel()->SetTransform( mX ); } void CEntity::snapToGround() @@ -382,7 +374,8 @@ void CEntity::update( size_t timestep ) { m_position_previous = m_position; m_orientation_previous = m_orientation; - + m_pitchOrientation_previous = m_pitchOrientation; + CalculateRun( timestep ); CalculateHealth( timestep ); @@ -809,6 +802,7 @@ void CEntity::repath() void CEntity::reorient() { m_orientation = m_graphics_orientation; + m_pitchOrientation = m_graphics_pitchOrientation; m_ahead.x = sin( m_orientation ); m_ahead.y = cos( m_orientation ); if( m_bounds->m_type == CBoundingObject::BOUND_OABB ) @@ -855,7 +849,8 @@ void CEntity::interpolate( float relativeoffset ) { CVector3D old_graphics_position = m_graphics_position; float old_graphics_orientation = m_graphics_orientation; - + float old_graphics_pitchOrientation = m_graphics_pitchOrientation; + m_graphics_position = Interpolate( m_position_previous, m_position, relativeoffset ); // Avoid wraparound glitches for interpolating angles. @@ -864,7 +859,13 @@ void CEntity::interpolate( float relativeoffset ) while( m_orientation > m_orientation_previous + PI ) m_orientation_previous += 2 * PI; + while( m_pitchOrientation < m_pitchOrientation_previous - PI ) + m_pitchOrientation_previous -= 2 * PI; + while( m_pitchOrientation > m_pitchOrientation_previous + PI ) + m_pitchOrientation_previous += 2 * PI; + m_graphics_orientation = Interpolate( m_orientation_previous, m_orientation, relativeoffset ); + m_graphics_pitchOrientation = Interpolate( m_pitchOrientation_previous, m_pitchOrientation, relativeoffset ); // Mark the actor transform data as invalid if the entity has moved since // the last call to 'interpolate'. @@ -872,10 +873,13 @@ void CEntity::interpolate( float relativeoffset ) // calling snapToGround, which is slow. TODO: This may need to be adjusted to // handle flying units or moving terrain. if( m_graphics_orientation != old_graphics_orientation || - m_graphics_position.X != old_graphics_position.X || - m_graphics_position.Z != old_graphics_position.Z ) + m_graphics_position.X != old_graphics_position.X || + m_graphics_position.Z != old_graphics_position.Z || + m_graphics_pitchOrientation != old_graphics_pitchOrientation + ) + { m_actor_transform_valid = false; - + } // Update the actor transform data when necessary. if( !m_actor_transform_valid ) { diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index f3a6dcc2fc..5f4308cec3 100755 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -79,6 +79,9 @@ public: float m_runRegenRate; float m_runDecayRate; + float m_maxActorPitch; + float m_minActorPitch; + float m_healthRegenRate; float m_healthRegenStart; float m_healthDecayRate; @@ -168,6 +171,10 @@ public: float m_orientation; float m_orientation_previous; float m_graphics_orientation; + + float m_pitchOrientation; + float m_pitchOrientation_previous; + float m_graphics_pitchOrientation; // If the actor's current transform data is valid (i.e. the entity hasn't // moved since it was last calculated, and the terrain hasn't been changed). diff --git a/source/simulation/EntityStateProcessing.cpp b/source/simulation/EntityStateProcessing.cpp index efb5df8a31..be68eb1534 100755 --- a/source/simulation/EntityStateProcessing.cpp +++ b/source/simulation/EntityStateProcessing.cpp @@ -89,13 +89,11 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis, float scale = processChooseMovement( len ) * timestep; - // Note: Easy optimization: flag somewhere that this unit // is already pointing the way, and don't do this // trig every time.right m_targetorientation = atan2( delta.x, delta.y ); - float deltatheta = m_targetorientation - (float)m_orientation; while( deltatheta > PI ) deltatheta -= 2 * PI; while( deltatheta < -PI ) deltatheta += 2 * PI; @@ -136,6 +134,12 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis, m_ahead = delta / len; m_orientation = m_targetorientation; } + + float targetpitch = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace( m_position.X, m_position.Z, m_orientation ); + while( targetpitch > PI ) targetpitch -= 2 * PI; + while( targetpitch < -PI ) targetpitch += 2 * PI; + m_pitchOrientation = clamp( targetpitch, m_minActorPitch, m_maxActorPitch ); + if( m_bounds && m_bounds->m_type == CBoundingObject::BOUND_OABB ) ((CBoundingBox*)m_bounds)->setOrientation( m_ahead );