LCOV - code coverage report
Current view: top level - source/tools/atlas/GameInterface/Handlers - CameraCtrlHandlers.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 0 110 0.0 %
Date: 2023-01-19 00:18:29 Functions: 0 16 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2017 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "MessageHandler.h"
      21             : #include "../GameLoop.h"
      22             : #include "../View.h"
      23             : 
      24             : #include "maths/MathUtil.h"
      25             : #include "maths/Vector3D.h"
      26             : #include "maths/Quaternion.h"
      27             : #include "ps/Game.h"
      28             : #include "renderer/Renderer.h"
      29             : #include "graphics/GameView.h"
      30             : #include "graphics/CinemaManager.h"
      31             : 
      32             : #include "ps/World.h"
      33             : #include "graphics/Terrain.h"
      34             : 
      35             : #include <assert.h>
      36             : 
      37             : namespace AtlasMessage {
      38             : 
      39           0 : MESSAGEHANDLER(CameraReset)
      40             : {
      41           0 :     if (!g_Game || g_Game->GetView()->GetCinema()->IsEnabled())
      42           0 :         return;
      43             : 
      44           0 :     CVector3D focus = g_Game->GetView()->GetCamera()->GetFocus();
      45             : 
      46           0 :     CVector3D target;
      47           0 :     if (!g_Game->GetWorld()->GetTerrain()->IsOnMap(focus.X, focus.Z))
      48             :     {
      49           0 :         target = CVector3D(
      50           0 :             g_Game->GetWorld()->GetTerrain()->GetMaxX()/2.f,
      51             :             focus.Y,
      52           0 :             g_Game->GetWorld()->GetTerrain()->GetMaxZ()/2.f);
      53             :     }
      54             :     else
      55             :     {
      56           0 :         target = focus;
      57             :     }
      58             : 
      59           0 :     g_Game->GetView()->ResetCameraTarget(target);
      60             : 
      61             :     UNUSED2(msg);
      62             : }
      63             : 
      64           0 : MESSAGEHANDLER(ScrollConstant)
      65             : {
      66           0 :     if (!g_Game || g_Game->GetView()->GetCinema()->IsEnabled())
      67           0 :         return;
      68             : 
      69           0 :     if (msg->dir < 0 || msg->dir > 5)
      70             :     {
      71           0 :         debug_warn(L"ScrollConstant: invalid direction");
      72             :     }
      73             :     else
      74             :     {
      75           0 :         g_AtlasGameLoop->input.scrollSpeed[msg->dir] = msg->speed;
      76             :     }
      77             : }
      78             : 
      79             : // TODO: change all these g_Game->...GetCamera() bits to use the current AtlasView's
      80             : // camera instead.
      81             : 
      82           0 : MESSAGEHANDLER(Scroll)
      83             : {
      84           0 :     if (!g_Game || g_Game->GetView()->GetCinema()->IsEnabled()) // TODO: do this better (probably a separate AtlasView class for cinematics)
      85           0 :         return;
      86             : 
      87           0 :     static CVector3D targetPos;
      88             :     static float targetDistance = 0.f;
      89             : 
      90           0 :     CMatrix3D& camera = g_Game->GetView()->GetCamera()->m_Orientation;
      91             : 
      92           0 :     static CVector3D lastCameraPos = camera.GetTranslation();
      93             : 
      94             :     // Ensure roughly correct motion when dragging is combined with other
      95             :     // movements.
      96           0 :     if (lastCameraPos != camera.GetTranslation())
      97           0 :         targetPos += camera.GetTranslation() - lastCameraPos;
      98             : 
      99             :     // General operation:
     100             :     //
     101             :     // When selecting a target point to drag, remember targetPos (a world-space
     102             :     // point on the terrain, underneath the mouse) and targetDistance (from the
     103             :     // camera to the target point).
     104             :     //
     105             :     // When dragging to a different position, the target point should remain
     106             :     // under the moved mouse; so calculate the ray through the camera and mouse,
     107             :     // multiply by targetDistance and add to targetPos, resulting in the required
     108             :     // camera position.
     109             : 
     110           0 :     if (msg->type == eScrollType::FROM)
     111             :     {
     112           0 :         targetPos = msg->pos->GetWorldSpace();
     113           0 :         targetDistance = (targetPos - camera.GetTranslation()).Length();
     114             :     }
     115           0 :     else if (msg->type == eScrollType::TO)
     116             :     {
     117           0 :         CVector3D origin, dir;
     118             :         float x, y;
     119           0 :         msg->pos->GetScreenSpace(x, y);
     120           0 :         g_Game->GetView()->GetCamera()->BuildCameraRay((int)x, (int)y, origin, dir);
     121           0 :         dir *= targetDistance;
     122           0 :         camera.Translate(targetPos - dir - origin);
     123           0 :         g_Game->GetView()->GetCamera()->UpdateFrustum();
     124             :     }
     125             :     else
     126             :     {
     127           0 :         debug_warn(L"Scroll: Invalid type");
     128             :     }
     129           0 :     lastCameraPos = camera.GetTranslation();
     130             : }
     131             : 
     132           0 : MESSAGEHANDLER(SmoothZoom)
     133             : {
     134           0 :     if (!g_Game || g_Game->GetView()->GetCinema()->IsEnabled())
     135           0 :         return;
     136             : 
     137           0 :     g_AtlasGameLoop->input.zoomDelta += msg->amount;
     138             : }
     139             : 
     140           0 : MESSAGEHANDLER(RotateAround)
     141             : {
     142           0 :     if (!g_Game || g_Game->GetView()->GetCinema()->IsEnabled())
     143           0 :         return;
     144             : 
     145           0 :     static CVector3D focusPos;
     146             :     static float lastX = 0.f, lastY = 0.f;
     147             : 
     148           0 :     CMatrix3D& camera = g_Game->GetView()->GetCamera()->m_Orientation;
     149             : 
     150           0 :     if (msg->type == eRotateAroundType::FROM)
     151             :     {
     152           0 :         msg->pos->GetScreenSpace(lastX, lastY); // get mouse position
     153           0 :         focusPos = msg->pos->GetWorldSpace(); // get point on terrain under mouse
     154             :     }
     155           0 :     else if (msg->type == eRotateAroundType::TO)
     156             :     {
     157             :         float x, y;
     158           0 :         msg->pos->GetScreenSpace(x, y); // get mouse position
     159             : 
     160             :         // Rotate around X and Y axes by amounts depending on the mouse delta
     161           0 :         float rotX = 6.f * (y-lastY) / g_Renderer.GetHeight();
     162           0 :         float rotY = 6.f * (x-lastX) / g_Renderer.GetWidth();
     163             : 
     164           0 :         CQuaternion q0, q1;
     165           0 :         q0.FromAxisAngle(camera.GetLeft(), -rotX);
     166           0 :         q1.FromAxisAngle(CVector3D(0.f, 1.f, 0.f), rotY);
     167           0 :         CQuaternion q = q0*q1;
     168             : 
     169           0 :         CVector3D origin = camera.GetTranslation();
     170           0 :         CVector3D offset = q.Rotate(origin - focusPos);
     171             : 
     172           0 :         q *= camera.GetRotation();
     173           0 :         q.Normalize(); // to avoid things blowing up when turning upside-down, for some reason I don't understand
     174           0 :         q.ToMatrix(camera);
     175             : 
     176             :         // Make sure up is still pointing up, regardless of any rounding errors.
     177             :         // (Maybe this distorts the camera in other ways, but at least the errors
     178             :         // are far less noticeable to me.)
     179           0 :         camera._21 = 0.f; // (_21 = Y component returned by GetLeft())
     180             : 
     181           0 :         camera.Translate(focusPos + offset);
     182           0 :         g_Game->GetView()->GetCamera()->UpdateFrustum();
     183             : 
     184           0 :         lastX = x;
     185           0 :         lastY = y;
     186             :     }
     187             :     else
     188             :     {
     189           0 :         debug_warn(L"RotateAround: Invalid type");
     190             :     }
     191             : }
     192             : 
     193           0 : MESSAGEHANDLER(LookAt)
     194             : {
     195             :     // TODO: different camera depending on msg->view
     196           0 :     CCamera& camera = AtlasView::GetView_Actor()->GetCamera();
     197             : 
     198           0 :     CVector3D tgt = msg->target->GetWorldSpace();
     199           0 :     CVector3D eye = msg->pos->GetWorldSpace();
     200           0 :     tgt.Y = -tgt.Y; // ??? why is this needed?
     201           0 :     eye.Y = -eye.Y; // ???
     202             : 
     203             :     // Based on http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/lookat.html
     204           0 :     CVector3D f = tgt - eye;
     205           0 :     f.Normalize();
     206           0 :     CVector3D s = f.Cross(CVector3D(0, 1, 0));
     207           0 :     CVector3D u = s.Cross(f);
     208           0 :     s.Normalize(); // (not in that man page, but necessary for correctness, and done by Mesa)
     209           0 :     u.Normalize();
     210             :     CMatrix3D M (
     211           0 :         s[0], s[1], s[2], 0,
     212           0 :         u[0], u[1], u[2], 0,
     213           0 :         -f[0], -f[1], -f[2], 0,
     214             :         0, 0, 0, 1
     215           0 :     );
     216             : 
     217           0 :     camera.m_Orientation = M.GetTranspose();
     218           0 :     camera.m_Orientation.Translate(-eye);
     219             : 
     220           0 :     camera.UpdateFrustum();
     221           0 : }
     222             : 
     223           0 : QUERYHANDLER(GetView)
     224             : {
     225           0 :     if (!g_Game)
     226           0 :         return;
     227             : 
     228           0 :     CVector3D focus = g_Game->GetView()->GetCamera()->GetFocus();
     229           0 :     sCameraInfo info;
     230             : 
     231           0 :     info.pX = focus.X;
     232           0 :     info.pY = focus.Y;
     233           0 :     info.pZ = focus.Z;
     234             : 
     235           0 :     CQuaternion quatRot = g_Game->GetView()->GetCamera()->GetOrientation().GetRotation();
     236           0 :     quatRot.Normalize();
     237           0 :     CVector3D rotation = quatRot.ToEulerAngles();
     238             : 
     239           0 :     info.rX = RADTODEG(rotation.X);
     240           0 :     info.rY = RADTODEG(rotation.Y);
     241           0 :     info.rZ = RADTODEG(rotation.Z);
     242             : 
     243           0 :     msg->info = info;
     244             : }
     245             : 
     246           0 : MESSAGEHANDLER(SetView)
     247             : {
     248           0 :     if (!g_Game || g_Game->GetView()->GetCinema()->IsEnabled())
     249           0 :         return;
     250             : 
     251           0 :     CGameView* view = g_Game->GetView();
     252           0 :     view->ResetCameraTarget(view->GetCamera()->GetFocus());
     253             : 
     254           0 :     sCameraInfo cam = msg->info;
     255             : 
     256           0 :     view->ResetCameraTarget(CVector3D(cam.pX, cam.pY, cam.pZ));
     257             : 
     258             :     // TODO: Rotation
     259             : }
     260             : 
     261             : }

Generated by: LCOV version 1.13