Index: Ca3DE/Client/ClientWorld.cpp
===================================================================
--- Ca3DE/Client/ClientWorld.cpp	(revision 120)
+++ Ca3DE/Client/ClientWorld.cpp	(working copy)
@@ -29,8 +29,11 @@
 #include "../NetConst.hpp"
 #include "../Both/EntityManager.hpp"
 #include "ClipSys/CollisionModel_static.hpp"
+#include "ClipSys/TraceResult.hpp"
 #include "ConsoleCommands/ConVar.hpp"
+#include "MaterialSystem/Material.hpp"
 #include "MaterialSystem/Renderer.hpp"
+#include "Math3D/Angles.hpp"
 #include "Math3D/Matrix.hpp"
 #include "Network/Network.hpp"
 #include "SceneGraph/Node.hpp"
@@ -324,6 +327,66 @@
 
 void CaClientWorldT::Draw(float FrameTime, const EntityStateT* DrawState)
 {
+    // Below are three pre-set variants of a third person camera.
+    // The first is aiming at the player directly. It's the most simple one,
+    // but cannot be used in shooters, since you can't see where you're aiming.
+    // The second one is aiming over the players head, similar to Tomb Raider.
+    // The third is an over-the-shoulder view, as you see it in many current shooters.
+    Vector3dT    ThirdPersonOrigin=DrawState->Origin;
+    const double TO_RAD=cf::math::AnglesdT::PI/32768.0;
+
+    static ConVarT ThirdPersonVariant("cl_3rdPerson", 0, ConVarT::FLAG_MAIN_EXE, "Determines the third person camera mode that should be used (0, 1 or 2).", 0, 2);
+
+    switch (ThirdPersonVariant.GetValueInt())
+    {
+        case 0:
+        {
+            // No shooting.
+            const double CameraDistance=1600.0;
+            const double CameraOffset  = 300.0;
+
+            ThirdPersonOrigin.x -= sin(DrawState->Heading*TO_RAD) * CameraDistance * cos(DrawState->Pitch*TO_RAD);
+            ThirdPersonOrigin.y -= cos(DrawState->Heading*TO_RAD) * CameraDistance * cos(DrawState->Pitch*TO_RAD);
+            ThirdPersonOrigin.z += sin(DrawState->Pitch  *TO_RAD) * CameraDistance;
+            break;
+        }
+
+        case 1:
+        {
+            // Over the head.
+            const double CameraDistance=1600.0;
+            const double CameraOffset  = 300.0;
+
+            ThirdPersonOrigin.x -= sin(DrawState->Heading*TO_RAD) * CameraDistance * cos(DrawState->Pitch*TO_RAD);
+            ThirdPersonOrigin.y -= cos(DrawState->Heading*TO_RAD) * CameraDistance * cos(DrawState->Pitch*TO_RAD);
+            ThirdPersonOrigin.z = (ThirdPersonOrigin.z + CameraOffset) + sin(DrawState->Pitch*TO_RAD) * CameraDistance;
+            break;
+        }
+
+        default:
+        {
+            // Over the shoulder.
+            const double CameraDistance=600.0;
+        	const double CameraOffset  =150.0;
+
+            ThirdPersonOrigin.x -= CameraOffset * sin(DrawState->Heading*TO_RAD - cf::math::AnglesdT::PI/2.0);
+            ThirdPersonOrigin.y -= CameraOffset * cos(DrawState->Heading*TO_RAD - cf::math::AnglesdT::PI/2.0);
+
+            ThirdPersonOrigin.x -= sin(DrawState->Heading*TO_RAD) * CameraDistance * cos(DrawState->Pitch*TO_RAD);
+            ThirdPersonOrigin.y -= cos(DrawState->Heading*TO_RAD) * CameraDistance * cos(DrawState->Pitch*TO_RAD);
+            ThirdPersonOrigin.z += sin(DrawState->Pitch  *TO_RAD) * CameraDistance;
+            break;
+        }
+    }
+
+    // This checks for collision between camera an world, and moves the camera closer to the player if necessary.
+    cf::ClipSys::TraceResultT Result;
+	Ca3DEWorld->CollModel->TraceRay(DrawState->Origin, ThirdPersonOrigin - DrawState->Origin, MaterialT::Clip_AllBlocking, Result);
+
+	Result.Fraction*=0.85;    // Otherwise we would still be able to see through the walls.
+	ThirdPersonOrigin=ThirdPersonOrigin*Result.Fraction + DrawState->Origin*(1.0-Result.Fraction);
+
+
     MatSys::Renderer->SetMatrix(MatSys::RendererI::MODEL_TO_WORLD, MatrixT());
 
     MatSys::Renderer->SetMatrix(MatSys::RendererI::WORLD_TO_VIEW,  MatrixT::GetRotateXMatrix(-90.0f));          // Start with the global Ca3DE coordinate system (not the OpenGL coordinate system).
@@ -336,7 +399,7 @@
 #if SHL_ENABLED
     MoveSHLSun(FrameTime);
 #endif
-    MatSys::Renderer->Translate(MatSys::RendererI::WORLD_TO_VIEW, -float(DrawState->Origin.x), -float(DrawState->Origin.y), -float(DrawState->Origin.z));
+    MatSys::Renderer->Translate(MatSys::RendererI::WORLD_TO_VIEW, -float(ThirdPersonOrigin.x), -float(ThirdPersonOrigin.y), -float(ThirdPersonOrigin.z));
 
 #if 0   // TODO: Move this into the scene graph.
 #ifdef DEBUG
@@ -371,9 +434,9 @@
     const float EyeOffsetZ=200.0f*sinf(TotalTime);
 
     MatSys::Renderer->SetCurrentRenderAction(MatSys::RendererI::AMBIENT);
-    MatSys::Renderer->SetCurrentEyePosition(float(DrawState->Origin.x), float(DrawState->Origin.y), float(DrawState->Origin.z)+EyeOffsetZ);    // Also required in some ambient shaders.
+    MatSys::Renderer->SetCurrentEyePosition(float(ThirdPersonOrigin.x), float(ThirdPersonOrigin.y), float(ThirdPersonOrigin.z)+EyeOffsetZ);    // Also required in some ambient shaders.
 
-    Ca3DEWorld->BspTree->DrawAmbientContrib(DrawState->Origin);
+    Ca3DEWorld->BspTree->DrawAmbientContrib(ThirdPersonOrigin);
 
 
     if (!CurrentFrame.IsValid)
@@ -393,7 +456,7 @@
     }
 
     // Draw the ambient contribution of the entities.
-    EntityManager.DrawEntities(OurEntityID, false, DrawState->Origin, CurrentFrame.EntityIDsInPVS);
+    EntityManager.DrawEntities(OurEntityID, false, ThirdPersonOrigin, CurrentFrame.EntityIDsInPVS);
 
 
 
@@ -446,7 +509,7 @@
                 // Our entity casts shadows, except when the light source is he himself.
                 EntityManager.DrawEntities(OurEntityID==BaseEntity->ID ? OurEntityID : 0xFFFFFFFF /* an ugly, dirty, kaum nachvollziehbarer hack */,
                                            OurEntityID==BaseEntity->ID,
-                                           DrawState->Origin,
+                                           ThirdPersonOrigin,
                                            CurrentFrame.EntityIDsInPVS);
          // }
          // else
@@ -467,7 +530,7 @@
         Ca3DEWorld->BspTree->DrawLightSourceContrib(DrawState->Origin, LightPosition);
         EntityManager.DrawEntities(OurEntityID,
                                    false,
-                                   DrawState->Origin,
+                                   ThirdPersonOrigin,
                                    CurrentFrame.EntityIDsInPVS);
     }
 
@@ -476,7 +539,7 @@
     MatSys::Renderer->SetCurrentRenderAction(MatSys::RendererI::AMBIENT);
 
     // Render translucent nodes back-to-front.
-    Ca3DEWorld->BspTree->DrawTranslucentContrib(DrawState->Origin);
+    Ca3DEWorld->BspTree->DrawTranslucentContrib(ThirdPersonOrigin);
 
     // Zuletzt halbtransparente HUD-Elemente, Fonts usw. zeichnen.
     EntityManager.PostDrawEntities(FrameTime, OurEntityID, CurrentFrame.EntityIDsInPVS);
Index: Games/DeathMatch/Code/HumanPlayer.cpp
===================================================================
--- Games/DeathMatch/Code/HumanPlayer.cpp	(revision 120)
+++ Games/DeathMatch/Code/HumanPlayer.cpp	(working copy)
@@ -951,50 +951,18 @@
     // of the local client, which gets *predicted*. Thus, there is no point in modifying the 'State' member variable.
     // Otherwise however, when 'FirstPersonView==false', this is usually a human player entity
     // of another client, which is *NOT* predicted. Thus, we may modify the 'State' member variable up to a certain extend.
-    if (FirstPersonView)
-    {
-        // Draw "view" model of the weapon
-        if (State.HaveWeapons & (1 << State.ActiveWeaponSlot))     // Only draw the active weapon if we actually "have" it
-        {
-            Vector3fT LgtPos(MatSys::Renderer->GetCurrentLightSourcePosition());
-            Vector3fT EyePos(MatSys::Renderer->GetCurrentEyePosition());
+    if (State.StateOfExistance!=StateOfExistance_Alive && State.StateOfExistance!=StateOfExistance_Dead) return;
 
-            // The translation is not actually required, but gives the weapon a very nice 'shifting' effect when the player looks up/down.
-            // If there ever is a problem with view model distortion, this may be a cause.
-            LgtPos.z+=0.5f;
-            EyePos.z+=0.5f;
-            MatSys::Renderer->Translate(MatSys::RendererI::MODEL_TO_WORLD, 0.0f, 0.0f, -0.5f);
+    const float OffsetZ=(State.StateOfExistance!=StateOfExistance_Dead) ? -32.0f : -32.0f+float(State.Dimensions.Min.z+1728.8)/25.4f;
 
-            const float DegPitch=float(State.Pitch)/8192.0f*45.0f;
+    MatSys::Renderer->GetCurrentLightSourcePosition()[2]-=OffsetZ;
+    MatSys::Renderer->GetCurrentEyePosition        ()[2]-=OffsetZ;
+    MatSys::Renderer->Translate(MatSys::RendererI::MODEL_TO_WORLD, 0.0f, 0.0f, OffsetZ);
 
-            LgtPos=LgtPos.GetRotY(-DegPitch);
-            EyePos=EyePos.GetRotY(-DegPitch);
-            MatSys::Renderer->RotateY(MatSys::RendererI::MODEL_TO_WORLD, DegPitch);
+    // Draw the own player body model and the "_p" (player) model of the active weapon as sub-model of the body.
+    ModelProxyT& PlayerModel=GetModelFromPlayerModelIndex(State.ModelIndex);
 
-            MatSys::Renderer->SetCurrentLightSourcePosition(LgtPos.x, LgtPos.y, LgtPos.z);
-            MatSys::Renderer->SetCurrentEyePosition(EyePos.x, EyePos.y, EyePos.z);
-
-
-            ModelProxyT& WeaponModelView=CarriedWeaponT::GetCarriedWeapon(State.ActiveWeaponSlot)->GetViewWeaponModel();
-
-            WeaponModelView.Draw(State.ActiveWeaponSequNr, State.ActiveWeaponFrameNr, LodDist);
-        }
-    }
-    else
-    {
-        if (State.StateOfExistance!=StateOfExistance_Alive && State.StateOfExistance!=StateOfExistance_Dead) return;
-
-        const float OffsetZ=(State.StateOfExistance!=StateOfExistance_Dead) ? -32.0f : -32.0f+float(State.Dimensions.Min.z+1728.8)/25.4f;
-
-        MatSys::Renderer->GetCurrentLightSourcePosition()[2]-=OffsetZ;
-        MatSys::Renderer->GetCurrentEyePosition        ()[2]-=OffsetZ;
-        MatSys::Renderer->Translate(MatSys::RendererI::MODEL_TO_WORLD, 0.0f, 0.0f, OffsetZ);
-
-        // Draw the own player body model and the "_p" (player) model of the active weapon as sub-model of the body.
-        ModelProxyT& PlayerModel=GetModelFromPlayerModelIndex(State.ModelIndex);
-
-        PlayerModel.Draw(State.ModelSequNr, State.ModelFrameNr, LodDist, (State.HaveWeapons & (1 << State.ActiveWeaponSlot)) ? &CarriedWeaponT::GetCarriedWeapon(State.ActiveWeaponSlot)->GetPlayerWeaponModel() : NULL);
-    }
+    PlayerModel.Draw(State.ModelSequNr, State.ModelFrameNr, LodDist, (State.HaveWeapons & (1 << State.ActiveWeaponSlot)) ? &CarriedWeaponT::GetCarriedWeapon(State.ActiveWeaponSlot)->GetPlayerWeaponModel() : NULL);
 }
 
 

