From aa6ca7d1e8576eab4b393c6380006212a2730a7b Mon Sep 17 00:00:00 2001 From: Matei Date: Sun, 10 Sep 2006 20:38:39 +0000 Subject: [PATCH] Modified world intersection so that you can also intersect with the water plane, which is useful for making ships move around as expected when you rightclick a spot on the water. This was SVN commit r4319. --- source/graphics/Camera.cpp | 57 ++++++++++++++++++--- source/graphics/Camera.h | 6 ++- source/graphics/GameView.cpp | 2 +- source/ps/Interact.cpp | 2 +- source/simulation/EntityScriptInterface.cpp | 2 +- 5 files changed, 57 insertions(+), 12 deletions(-) diff --git a/source/graphics/Camera.cpp b/source/graphics/Camera.cpp index 61459a2d20..671df75d6c 100644 --- a/source/graphics/Camera.cpp +++ b/source/graphics/Camera.cpp @@ -14,6 +14,7 @@ #include "Camera.h" #include "renderer/Renderer.h" +#include "renderer/WaterManager.h" #include "HFTracer.h" #include "ps/Game.h" #include "lib/ogl.h" @@ -201,21 +202,63 @@ void CCamera::GetScreenCoordinates( const CVector3D& world, float& x, float& y ) y = ( 1 - y ) * 0.5f * g_Renderer.GetHeight(); } -CVector3D CCamera::GetWorldCoordinates( int px, int py ) +CVector3D CCamera::GetWorldCoordinates( int px, int py, bool aboveWater ) { CHFTracer tracer( g_Game->GetWorld()->GetTerrain() ); int x, z; - CVector3D origin, dir, delta, currentTarget; + CVector3D origin, dir, delta, terrainPoint, waterPoint; BuildCameraRay( px, py, origin, dir ); - if( tracer.RayIntersect( origin, dir, x, z, currentTarget ) ) - return( currentTarget ); - // Off the edge of the world? - // Work out where it /would/ hit, if the map were extended out to infinity with average height. + bool gotTerrain = tracer.RayIntersect( origin, dir, x, z, terrainPoint ); + + if( !aboveWater ) + { + if( gotTerrain ) + return terrainPoint; + + // Off the edge of the world? + // Work out where it /would/ hit, if the map were extended out to infinity with average height. + return GetWorldCoordinates( px, py, 50.0f ); + } + + CPlane plane; + plane.Set(CVector3D(0.f, 1.f, 0.f), // upwards normal + CVector3D(0.f, g_Renderer.GetWaterManager()->m_WaterHeight, 0.f)); // passes through water plane + + bool gotWater = plane.FindRayIntersection( origin, dir, &waterPoint ); + + if( gotTerrain ) + { + if( gotWater ) + { + // Intersecting both heightmap and water plane; choose the closest of those + if( (origin - terrainPoint).LengthSquared() < (origin - waterPoint).LengthSquared() ) + return terrainPoint; + else + return waterPoint; + } + else + { + // Intersecting heightmap but parallel to water plane + return terrainPoint; + } + } + else + { + if( gotWater ) + { + // Only intersecting water plane + return waterPoint; + } + else + { + // Not intersecting terrain or water; just return 0,0,0. + return CVector3D(0.f, 0.f, 0.f); + } + } - return( origin + dir * ( ( 50.0f - origin.Y ) / dir.Y ) ); } CVector3D CCamera::GetWorldCoordinates(int px, int py, float h) diff --git a/source/graphics/Camera.h b/source/graphics/Camera.h index 7df6602e70..eda8c0c208 100644 --- a/source/graphics/Camera.h +++ b/source/graphics/Camera.h @@ -77,8 +77,10 @@ class CCamera void GetScreenCoordinates(const CVector3D& world, float& x, float& y) const; // Get the point on the terrain corresponding to pixel (px,py) (or the mouse coordinates) - CVector3D GetWorldCoordinates(int px, int py); - CVector3D GetWorldCoordinates() { return GetWorldCoordinates(g_mouse_x, g_mouse_y); } + // The aboveWater parameter determines whether we want to stop at the water plane or also get underwater points + CVector3D GetWorldCoordinates(int px, int py, bool aboveWater=false); + CVector3D GetWorldCoordinates(bool aboveWater=false) + { return GetWorldCoordinates(g_mouse_x, g_mouse_y, aboveWater); } // Get the point on the plane at height h corresponding to pixel (px,py) CVector3D GetWorldCoordinates(int px, int py, float h); // Get the point on the terrain the camera is pointing towards diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 92e6321feb..4357fe7361 100644 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -373,7 +373,7 @@ void CGameView::ResetCameraOrientation() void CGameView::RotateAboutTarget() { - m_CameraPivot = m_ViewCamera.GetWorldCoordinates(); + m_CameraPivot = m_ViewCamera.GetWorldCoordinates(true); } void CGameView::Update(float DeltaTime) diff --git a/source/ps/Interact.cpp b/source/ps/Interact.cpp index 47734f776c..444823e373 100644 --- a/source/ps/Interact.cpp +++ b/source/ps/Interact.cpp @@ -646,7 +646,7 @@ void CMouseoverEntities::update( float timestep ) CUnit* hit = g_UnitMan.PickUnit( origin, dir ); - m_worldposition = pCamera->GetWorldCoordinates(); + m_worldposition = pCamera->GetWorldCoordinates(true); if( hit && hit->GetEntity() && hit->GetEntity()->m_extant ) { diff --git a/source/simulation/EntityScriptInterface.cpp b/source/simulation/EntityScriptInterface.cpp index 6b41603d1d..e548a6663d 100644 --- a/source/simulation/EntityScriptInterface.cpp +++ b/source/simulation/EntityScriptInterface.cpp @@ -847,7 +847,7 @@ jsval CEntity::GetRallyPoint( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* jsval CEntity::SetRallyPoint( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) ) { entf_set(ENTF_HAS_RALLY_POINT); - m_rallyPoint = g_Game->GetView()->GetCamera()->GetWorldCoordinates(); + m_rallyPoint = g_Game->GetView()->GetCamera()->GetWorldCoordinates(true); return JS_TRUE; }