Index: ps/trunk/source/graphics/Camera.cpp
===================================================================
--- ps/trunk/source/graphics/Camera.cpp (revision 22032)
+++ ps/trunk/source/graphics/Camera.cpp (revision 22033)
@@ -1,430 +1,424 @@
-/* Copyright (C) 2017 Wildfire Games.
+/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
/*
* CCamera holds a view and a projection matrix. It also has a frustum
* which can be used to cull objects for rendering.
*/
#include "precompiled.h"
#include "Camera.h"
#include "graphics/HFTracer.h"
#include "graphics/Terrain.h"
#include "lib/ogl.h"
#include "maths/MathUtil.h"
#include "maths/Vector4D.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
CCamera::CCamera()
{
// set viewport to something anything should handle, but should be initialised
// to window size before use
m_ViewPort.m_X = 0;
m_ViewPort.m_Y = 0;
m_ViewPort.m_Width = 800;
m_ViewPort.m_Height = 600;
}
-CCamera::~CCamera()
-{
-}
+CCamera::~CCamera() = default;
void CCamera::SetProjection(float nearp, float farp, float fov)
{
m_NearPlane = nearp;
m_FarPlane = farp;
m_FOV = fov;
const float aspect = static_cast(m_ViewPort.m_Width) / static_cast(m_ViewPort.m_Height);
m_ProjMat.SetPerspective(m_FOV, aspect, m_NearPlane, m_FarPlane);
}
void CCamera::SetProjectionTile(int tiles, int tile_x, int tile_y)
{
const float aspect = static_cast(m_ViewPort.m_Width) / static_cast(m_ViewPort.m_Height);
- const float f = 1.f / tanf(m_FOV / 2.f);
- m_ProjMat._11 = tiles * f / aspect;
- m_ProjMat._22 = tiles * f;
- m_ProjMat._13 = -(1 - tiles + 2 * tile_x);
- m_ProjMat._23 = -(1 - tiles + 2 * tile_y);
+ m_ProjMat.SetPerspectiveTile(m_FOV, aspect, m_NearPlane, m_FarPlane, tiles, tile_x, tile_y);
}
-//Updates the frustum planes. Should be called
-//everytime the view or projection matrices are
-//altered.
+// Updates the frustum planes. Should be called
+// everytime the view or projection matrices are
+// altered.
void CCamera::UpdateFrustum(const CBoundingBoxAligned& scissor)
{
CMatrix3D MatFinal;
CMatrix3D MatView;
m_Orientation.GetInverse(MatView);
MatFinal = m_ProjMat * MatView;
m_ViewFrustum.SetNumPlanes(6);
// get the RIGHT plane
m_ViewFrustum.m_aPlanes[0].m_Norm.X = scissor[1].X*MatFinal._41 - MatFinal._11;
m_ViewFrustum.m_aPlanes[0].m_Norm.Y = scissor[1].X*MatFinal._42 - MatFinal._12;
m_ViewFrustum.m_aPlanes[0].m_Norm.Z = scissor[1].X*MatFinal._43 - MatFinal._13;
m_ViewFrustum.m_aPlanes[0].m_Dist = scissor[1].X*MatFinal._44 - MatFinal._14;
// get the LEFT plane
m_ViewFrustum.m_aPlanes[1].m_Norm.X = -scissor[0].X*MatFinal._41 + MatFinal._11;
m_ViewFrustum.m_aPlanes[1].m_Norm.Y = -scissor[0].X*MatFinal._42 + MatFinal._12;
m_ViewFrustum.m_aPlanes[1].m_Norm.Z = -scissor[0].X*MatFinal._43 + MatFinal._13;
m_ViewFrustum.m_aPlanes[1].m_Dist = -scissor[0].X*MatFinal._44 + MatFinal._14;
// get the BOTTOM plane
m_ViewFrustum.m_aPlanes[2].m_Norm.X = -scissor[0].Y*MatFinal._41 + MatFinal._21;
m_ViewFrustum.m_aPlanes[2].m_Norm.Y = -scissor[0].Y*MatFinal._42 + MatFinal._22;
m_ViewFrustum.m_aPlanes[2].m_Norm.Z = -scissor[0].Y*MatFinal._43 + MatFinal._23;
m_ViewFrustum.m_aPlanes[2].m_Dist = -scissor[0].Y*MatFinal._44 + MatFinal._24;
// get the TOP plane
m_ViewFrustum.m_aPlanes[3].m_Norm.X = scissor[1].Y*MatFinal._41 - MatFinal._21;
m_ViewFrustum.m_aPlanes[3].m_Norm.Y = scissor[1].Y*MatFinal._42 - MatFinal._22;
m_ViewFrustum.m_aPlanes[3].m_Norm.Z = scissor[1].Y*MatFinal._43 - MatFinal._23;
m_ViewFrustum.m_aPlanes[3].m_Dist = scissor[1].Y*MatFinal._44 - MatFinal._24;
// get the FAR plane
m_ViewFrustum.m_aPlanes[4].m_Norm.X = scissor[1].Z*MatFinal._41 - MatFinal._31;
m_ViewFrustum.m_aPlanes[4].m_Norm.Y = scissor[1].Z*MatFinal._42 - MatFinal._32;
m_ViewFrustum.m_aPlanes[4].m_Norm.Z = scissor[1].Z*MatFinal._43 - MatFinal._33;
m_ViewFrustum.m_aPlanes[4].m_Dist = scissor[1].Z*MatFinal._44 - MatFinal._34;
// get the NEAR plane
m_ViewFrustum.m_aPlanes[5].m_Norm.X = -scissor[0].Z*MatFinal._41 + MatFinal._31;
m_ViewFrustum.m_aPlanes[5].m_Norm.Y = -scissor[0].Z*MatFinal._42 + MatFinal._32;
m_ViewFrustum.m_aPlanes[5].m_Norm.Z = -scissor[0].Z*MatFinal._43 + MatFinal._33;
m_ViewFrustum.m_aPlanes[5].m_Dist = -scissor[0].Z*MatFinal._44 + MatFinal._34;
for (size_t i = 0; i < 6; ++i)
m_ViewFrustum.m_aPlanes[i].Normalize();
}
void CCamera::ClipFrustum(const CPlane& clipPlane)
{
CPlane normClipPlane = clipPlane;
normClipPlane.Normalize();
m_ViewFrustum.AddPlane(normClipPlane);
}
void CCamera::SetViewPort(const SViewPort& viewport)
{
m_ViewPort.m_X = viewport.m_X;
m_ViewPort.m_Y = viewport.m_Y;
m_ViewPort.m_Width = viewport.m_Width;
m_ViewPort.m_Height = viewport.m_Height;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GetCameraPlanePoints: return four points in camera space at given distance from camera
void CCamera::GetCameraPlanePoints(float dist, CVector3D pts[4]) const
{
float aspect = float(m_ViewPort.m_Width)/float(m_ViewPort.m_Height);
float x = dist*aspect*tanf(m_FOV*0.5f);
float y = dist*tanf(m_FOV*0.5f);
pts[0].X = -x;
pts[0].Y = -y;
pts[0].Z = dist;
pts[1].X = x;
pts[1].Y = -y;
pts[1].Z = dist;
pts[2].X = x;
pts[2].Y = y;
pts[2].Z = dist;
pts[3].X = -x;
pts[3].Y = y;
pts[3].Z = dist;
}
void CCamera::BuildCameraRay(int px, int py, CVector3D& origin, CVector3D& dir) const
{
CVector3D cPts[4];
GetCameraPlanePoints(m_FarPlane, cPts);
// transform to world space
CVector3D wPts[4];
for (int i = 0; i < 4; i++)
wPts[i] = m_Orientation.Transform(cPts[i]);
// get world space position of mouse point
float dx = (float)px / (float)g_Renderer.GetWidth();
float dz = 1 - (float)py / (float)g_Renderer.GetHeight();
CVector3D vdx = wPts[1] - wPts[0];
CVector3D vdz = wPts[3] - wPts[0];
CVector3D pt = wPts[0] + (vdx * dx) + (vdz * dz);
// copy origin
origin = m_Orientation.GetTranslation();
// build direction
dir = pt - origin;
dir.Normalize();
}
void CCamera::GetScreenCoordinates(const CVector3D& world, float& x, float& y) const
{
CMatrix3D transform = m_ProjMat * m_Orientation.GetInverse();
CVector4D screenspace = transform.Transform(CVector4D(world.X, world.Y, world.Z, 1.0f));
x = screenspace.X / screenspace.W;
y = screenspace.Y / screenspace.W;
x = (x + 1) * 0.5f * g_Renderer.GetWidth();
y = (1 - y) * 0.5f * g_Renderer.GetHeight();
}
CVector3D CCamera::GetWorldCoordinates(int px, int py, bool aboveWater) const
{
CHFTracer tracer(g_Game->GetWorld()->GetTerrain());
int x, z;
CVector3D origin, dir, delta, terrainPoint, waterPoint;
BuildCameraRay(px, py, origin, dir);
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 );
// Clamp the water intersection to within the map's bounds, so that
// we'll always return a valid position on the map
ssize_t mapSize = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide();
if (gotWater)
{
waterPoint.X = clamp(waterPoint.X, 0.f, (float)((mapSize-1)*TERRAIN_TILE_SIZE));
waterPoint.Z = clamp(waterPoint.Z, 0.f, (float)((mapSize-1)*TERRAIN_TILE_SIZE));
}
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);
}
}
}
CVector3D CCamera::GetWorldCoordinates(int px, int py, float h) const
{
CPlane plane;
plane.Set(CVector3D(0.f, 1.f, 0.f), CVector3D(0.f, h, 0.f)); // upwards normal, passes through h
CVector3D origin, dir, delta, currentTarget;
BuildCameraRay(px, py, origin, dir);
if (plane.FindRayIntersection(origin, dir, ¤tTarget))
return currentTarget;
// No intersection with the infinite plane - nothing sensible can be returned,
// so just choose an arbitrary point on the plane
return CVector3D(0.f, h, 0.f);
}
CVector3D CCamera::GetFocus() const
{
// Basically the same as GetWorldCoordinates
CHFTracer tracer(g_Game->GetWorld()->GetTerrain());
int x, z;
CVector3D origin, dir, delta, terrainPoint, waterPoint;
origin = m_Orientation.GetTranslation();
dir = m_Orientation.GetIn();
bool gotTerrain = tracer.RayIntersect(origin, dir, x, z, terrainPoint);
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 );
// Clamp the water intersection to within the map's bounds, so that
// we'll always return a valid position on the map
ssize_t mapSize = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide();
if (gotWater)
{
waterPoint.X = clamp(waterPoint.X, 0.f, (float)((mapSize-1)*TERRAIN_TILE_SIZE));
waterPoint.Z = clamp(waterPoint.Z, 0.f, (float)((mapSize-1)*TERRAIN_TILE_SIZE));
}
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);
}
}
}
void CCamera::LookAt(const CVector3D& camera, const CVector3D& target, const CVector3D& up)
{
CVector3D delta = target - camera;
LookAlong(camera, delta, up);
}
void CCamera::LookAlong(const CVector3D& camera, CVector3D orientation, CVector3D up)
{
orientation.Normalize();
up.Normalize();
CVector3D s = orientation.Cross(up);
m_Orientation._11 = -s.X; m_Orientation._12 = up.X; m_Orientation._13 = orientation.X; m_Orientation._14 = camera.X;
m_Orientation._21 = -s.Y; m_Orientation._22 = up.Y; m_Orientation._23 = orientation.Y; m_Orientation._24 = camera.Y;
m_Orientation._31 = -s.Z; m_Orientation._32 = up.Z; m_Orientation._33 = orientation.Z; m_Orientation._34 = camera.Z;
m_Orientation._41 = 0.0f; m_Orientation._42 = 0.0f; m_Orientation._43 = 0.0f; m_Orientation._44 = 1.0f;
}
///////////////////////////////////////////////////////////////////////////////////
// Render the camera's frustum
void CCamera::Render(int intermediates) const
{
#if CONFIG2_GLES
#warning TODO: implement camera frustum for GLES
#else
CVector3D nearPoints[4];
CVector3D farPoints[4];
GetCameraPlanePoints(m_NearPlane, nearPoints);
GetCameraPlanePoints(m_FarPlane, farPoints);
for(int i = 0; i < 4; i++)
{
nearPoints[i] = m_Orientation.Transform(nearPoints[i]);
farPoints[i] = m_Orientation.Transform(farPoints[i]);
}
// near plane
glBegin(GL_POLYGON);
glVertex3fv(&nearPoints[0].X);
glVertex3fv(&nearPoints[1].X);
glVertex3fv(&nearPoints[2].X);
glVertex3fv(&nearPoints[3].X);
glEnd();
// far plane
glBegin(GL_POLYGON);
glVertex3fv(&farPoints[0].X);
glVertex3fv(&farPoints[1].X);
glVertex3fv(&farPoints[2].X);
glVertex3fv(&farPoints[3].X);
glEnd();
// connection lines
glBegin(GL_QUAD_STRIP);
glVertex3fv(&nearPoints[0].X);
glVertex3fv(&farPoints[0].X);
glVertex3fv(&nearPoints[1].X);
glVertex3fv(&farPoints[1].X);
glVertex3fv(&nearPoints[2].X);
glVertex3fv(&farPoints[2].X);
glVertex3fv(&nearPoints[3].X);
glVertex3fv(&farPoints[3].X);
glVertex3fv(&nearPoints[0].X);
glVertex3fv(&farPoints[0].X);
glEnd();
// intermediate planes
CVector3D intermediatePoints[4];
for(int i = 0; i < intermediates; ++i)
{
float t = (i+1.0)/(intermediates+1.0);
for(int j = 0; j < 4; ++j)
intermediatePoints[j] = nearPoints[j]*t + farPoints[j]*(1.0-t);
glBegin(GL_POLYGON);
glVertex3fv(&intermediatePoints[0].X);
glVertex3fv(&intermediatePoints[1].X);
glVertex3fv(&intermediatePoints[2].X);
glVertex3fv(&intermediatePoints[3].X);
glEnd();
}
#endif
}
Index: ps/trunk/source/graphics/Camera.h
===================================================================
--- ps/trunk/source/graphics/Camera.h (revision 22032)
+++ ps/trunk/source/graphics/Camera.h (revision 22033)
@@ -1,126 +1,125 @@
-/* Copyright (C) 2017 Wildfire Games.
+/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
/*
* CCamera holds a view and a projection matrix. It also has a frustum
* which can be used to cull objects for rendering.
*/
#ifndef INCLUDED_CAMERA
#define INCLUDED_CAMERA
#include "Frustum.h"
#include "maths/BoundingBoxAligned.h"
#include "maths/Matrix3D.h"
// view port
struct SViewPort
{
int m_X;
int m_Y;
int m_Width;
int m_Height;
};
class CCamera
{
public:
CCamera();
~CCamera();
// Methods for projection
void SetProjection(float nearp, float farp, float fov);
void SetProjection(const CMatrix3D& matrix) { m_ProjMat = matrix; }
void SetProjectionTile(int tiles, int tile_x, int tile_y);
CMatrix3D& GetProjection() { return m_ProjMat; }
const CMatrix3D& GetProjection() const { return m_ProjMat; }
CMatrix3D& GetOrientation() { return m_Orientation; }
const CMatrix3D& GetOrientation() const { return m_Orientation; }
CMatrix3D GetViewProjection() const { return m_ProjMat * m_Orientation.GetInverse(); }
// Updates the frustum planes. Should be called
// everytime the view or projection matrices are
// altered.
void UpdateFrustum(const CBoundingBoxAligned& scissor = CBoundingBoxAligned(CVector3D(-1.0f, -1.0f, -1.0f), CVector3D(1.0f, 1.0f, 1.0f)));
void ClipFrustum(const CPlane& clipPlane);
const CFrustum& GetFrustum() const { return m_ViewFrustum; }
void SetViewPort(const SViewPort& viewport);
const SViewPort& GetViewPort() const { return m_ViewPort; }
- // getters
float GetNearPlane() const { return m_NearPlane; }
float GetFarPlane() const { return m_FarPlane; }
float GetFOV() const { return m_FOV; }
- // return four points in camera space at given distance from camera
- void GetCameraPlanePoints(float dist,CVector3D pts[4]) const;
+ // Returns four points in camera space at given distance from camera
+ void GetCameraPlanePoints(float dist, CVector3D pts[4]) const;
// Build a ray passing through the screen coordinate (px, py) and the camera
/////////////////////////////////////////////////////////////////////////////////////////
// BuildCameraRay: calculate origin and ray direction of a ray through
// the pixel (px,py) on the screen
void BuildCameraRay(int px, int py, CVector3D& origin, CVector3D& dir) const;
// General helpers that seem to fit here
// Get the screen-space coordinates corresponding to a given world-space position
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)
// 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) const;
// Get the point on the plane at height h corresponding to pixel (px,py)
CVector3D GetWorldCoordinates(int px, int py, float h) const;
// Get the point on the terrain (or water plane) the camera is pointing towards
CVector3D GetFocus() const;
// Build an orientation matrix from camera position, camera focus point, and up-vector
void LookAt(const CVector3D& camera, const CVector3D& orientation, const CVector3D& up);
// Build an orientation matrix from camera position, camera orientation, and up-vector
void LookAlong(const CVector3D& camera, CVector3D focus, CVector3D up);
/**
* Render: Renders the camera's frustum in world space.
* The caller should set the color using glColorXy before calling Render.
*
* @param intermediates determines how many intermediate distance planes should
* be hinted at between the near and far planes
*/
void Render(int intermediates = 0) const;
public:
// This is the orientation matrix. The inverse of this
// is the view matrix
CMatrix3D m_Orientation;
// Should not be tweaked externally if possible
CMatrix3D m_ProjMat;
private:
float m_NearPlane;
float m_FarPlane;
float m_FOV;
SViewPort m_ViewPort;
CFrustum m_ViewFrustum;
};
-#endif
+#endif // INCLUDED_CAMERA
Index: ps/trunk/source/maths/Matrix3D.cpp
===================================================================
--- ps/trunk/source/maths/Matrix3D.cpp (revision 22032)
+++ ps/trunk/source/maths/Matrix3D.cpp (revision 22033)
@@ -1,433 +1,444 @@
-/* Copyright (C) 2017 Wildfire Games.
+/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
/*
* A Matrix class used for holding and manipulating transformation
* info.
*/
#include "precompiled.h"
#include "Matrix3D.h"
#include "Quaternion.h"
#include "Vector4D.h"
//Sets the identity matrix
void CMatrix3D::SetIdentity ()
{
_11=1.0f; _12=0.0f; _13=0.0f; _14=0.0f;
_21=0.0f; _22=1.0f; _23=0.0f; _24=0.0f;
_31=0.0f; _32=0.0f; _33=1.0f; _34=0.0f;
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
}
//Sets the zero matrix
void CMatrix3D::SetZero()
{
_11=0.0f; _12=0.0f; _13=0.0f; _14=0.0f;
_21=0.0f; _22=0.0f; _23=0.0f; _24=0.0f;
_31=0.0f; _32=0.0f; _33=0.0f; _34=0.0f;
_41=0.0f; _42=0.0f; _43=0.0f; _44=0.0f;
}
void CMatrix3D::SetOrtho(float left, float right, float bottom, float top, float near, float far)
{
// Based on OpenGL spec
SetZero();
_11 = 2 / (right - left);
_22 = 2 / (top - bottom);
_33 = -2 / (far - near);
_44 = 1;
_14 = -(right + left) / (right - left);
_24 = -(top + bottom) / (top - bottom);
_34 = -(far + near) / (far - near);
}
void CMatrix3D::SetPerspective(float fov, float aspect, float near, float far)
{
const float f = 1.f / tanf(fov / 2.f);
SetZero();
_11 = f / aspect;
_22 = f;
_33 = -(far + near) / (near - far);
_34 = 2 * far * near / (near - far);
_43 = 1;
}
+void CMatrix3D::SetPerspectiveTile(float fov, float aspect, float near, float far, int tiles, int tile_x, int tile_y)
+{
+ const float f = 1.f / tanf(fov / 2.f);
+
+ SetPerspective(fov, aspect, near, far);
+ _11 = tiles * f / aspect;
+ _22 = tiles * f;
+ _13 = -(1 - tiles + 2 * tile_x);
+ _23 = -(1 - tiles + 2 * tile_y);
+}
+
//The following clear the matrix and set the
//rotation of each of the 3 axes
void CMatrix3D::SetXRotation (float angle)
{
const float Cos = cosf (angle);
const float Sin = sinf (angle);
_11=1.0f; _12=0.0f; _13=0.0f; _14=0.0f;
_21=0.0f; _22=Cos; _23=-Sin; _24=0.0f;
_31=0.0f; _32=Sin; _33=Cos; _34=0.0f;
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
}
void CMatrix3D::SetYRotation (float angle)
{
const float Cos = cosf (angle);
const float Sin = sinf (angle);
_11=Cos; _12=0.0f; _13=Sin; _14=0.0f;
_21=0.0f; _22=1.0f; _23=0.0f; _24=0.0f;
_31=-Sin; _32=0.0f; _33=Cos; _34=0.0f;
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
}
void CMatrix3D::SetZRotation (float angle)
{
const float Cos = cosf (angle);
const float Sin = sinf (angle);
_11=Cos; _12=-Sin; _13=0.0f; _14=0.0f;
_21=Sin; _22=Cos; _23=0.0f; _24=0.0f;
_31=0.0f; _32=0.0f; _33=1.0f; _34=0.0f;
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
}
//The following apply a rotation to the matrix
//about each of the axes;
void CMatrix3D::RotateX (float angle)
{
const float Cos = cosf (angle);
const float Sin = sinf (angle);
const float tmp_21 = _21;
const float tmp_22 = _22;
const float tmp_23 = _23;
const float tmp_24 = _24;
_21 = Cos * _21 - Sin * _31;
_22 = Cos * _22 - Sin * _32;
_23 = Cos * _23 - Sin * _33;
_24 = Cos * _24 - Sin * _34;
_31 = Sin * tmp_21 + Cos * _31;
_32 = Sin * tmp_22 + Cos * _32;
_33 = Sin * tmp_23 + Cos * _33;
_34 = Sin * tmp_24 + Cos * _34;
}
void CMatrix3D::RotateY (float angle)
{
const float Cos = cosf (angle);
const float Sin = sinf (angle);
const float tmp_11 = _11;
const float tmp_12 = _12;
const float tmp_13 = _13;
const float tmp_14 = _14;
_11 = Cos * _11 + Sin * _31;
_12 = Cos * _12 + Sin * _32;
_13 = Cos * _13 + Sin * _33;
_14 = Cos * _14 + Sin * _34;
_31 = -Sin * tmp_11 + Cos * _31;
_32 = -Sin * tmp_12 + Cos * _32;
_33 = -Sin * tmp_13 + Cos * _33;
_34 = -Sin * tmp_14 + Cos * _34;
}
void CMatrix3D::RotateZ (float angle)
{
const float Cos = cosf (angle);
const float Sin = sinf (angle);
const float tmp_11 = _11;
const float tmp_12 = _12;
const float tmp_13 = _13;
const float tmp_14 = _14;
_11 = Cos * _11 - Sin * _21;
_12 = Cos * _12 - Sin * _22;
_13 = Cos * _13 - Sin * _23;
_14 = Cos * _14 - Sin * _24;
_21 = Sin * tmp_11 + Cos * _21;
_22 = Sin * tmp_12 + Cos * _22;
_23 = Sin * tmp_13 + Cos * _23;
_24 = Sin * tmp_14 + Cos * _24;
}
//Sets the translation of the matrix
void CMatrix3D::SetTranslation (float x, float y, float z)
{
_11=1.0f; _12=0.0f; _13=0.0f; _14=x;
_21=0.0f; _22=1.0f; _23=0.0f; _24=y;
_31=0.0f; _32=0.0f; _33=1.0f; _34=z;
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
}
void CMatrix3D::SetTranslation(const CVector3D& vector)
{
SetTranslation(vector.X, vector.Y, vector.Z);
}
//Applies a translation to the matrix
void CMatrix3D::Translate(float x, float y, float z)
{
_14 += x;
_24 += y;
_34 += z;
}
void CMatrix3D::Translate(const CVector3D &vector)
{
_14 += vector.X;
_24 += vector.Y;
_34 += vector.Z;
}
void CMatrix3D::PostTranslate(float x, float y, float z)
{
// Equivalent to "m.SetTranslation(x, y, z); *this = *this * m;"
_14 += _11*x + _12*y + _13*z;
_24 += _21*x + _22*y + _23*z;
_34 += _31*x + _32*y + _33*z;
_44 += _41*x + _42*y + _43*z;
}
CVector3D CMatrix3D::GetTranslation() const
{
return CVector3D(_14, _24, _34);
}
//Clears and sets the scaling of the matrix
void CMatrix3D::SetScaling (float x_scale, float y_scale, float z_scale)
{
_11=x_scale; _12=0.0f; _13=0.0f; _14=0.0f;
_21=0.0f; _22=y_scale; _23=0.0f; _24=0.0f;
_31=0.0f; _32=0.0f; _33=z_scale; _34=0.0f;
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
}
//Scales the matrix
void CMatrix3D::Scale (float x_scale, float y_scale, float z_scale)
{
_11 *= x_scale;
_12 *= x_scale;
_13 *= x_scale;
_14 *= x_scale;
_21 *= y_scale;
_22 *= y_scale;
_23 *= y_scale;
_24 *= y_scale;
_31 *= z_scale;
_32 *= z_scale;
_33 *= z_scale;
_34 *= z_scale;
}
//Returns the transpose of the matrix. For orthonormal
//matrices, this is the same is the inverse matrix
CMatrix3D CMatrix3D::GetTranspose() const
{
return CMatrix3D(
_11, _21, _31, _41,
_12, _22, _32, _42,
_13, _23, _33, _43,
_14, _24, _34, _44);
}
//Get a vector which points to the left of the matrix
CVector3D CMatrix3D::GetLeft() const
{
return CVector3D(-_11, -_21, -_31);
}
//Get a vector which points up from the matrix
CVector3D CMatrix3D::GetUp() const
{
return CVector3D(_12, _22, _32);
}
//Get a vector which points to front of the matrix
CVector3D CMatrix3D::GetIn() const
{
return CVector3D(_13, _23, _33);
}
///////////////////////////////////////////////////////////////////////////////
// RotateTransposed: rotate a vector by the transpose of this matrix
CVector3D CMatrix3D::RotateTransposed(const CVector3D& vector) const
{
CVector3D result;
RotateTransposed(vector,result);
return result;
}
///////////////////////////////////////////////////////////////////////////////
// RotateTransposed: rotate a vector by the transpose of this matrix
void CMatrix3D::RotateTransposed(const CVector3D& vector,CVector3D& result) const
{
result.X = _11*vector.X + _21*vector.Y + _31*vector.Z;
result.Y = _12*vector.X + _22*vector.Y + _32*vector.Z;
result.Z = _13*vector.X + _23*vector.Y + _33*vector.Z;
}
void CMatrix3D::GetInverse(CMatrix3D& dst) const
{
float tmp[12]; // temp array for pairs
float src[16]; // array of transpose source matrix
float det; // determinant
// transpose matrix
for (int i = 0; i < 4; ++i) {
src[i] = _data[i*4];
src[i + 4] = _data[i*4 + 1];
src[i + 8] = _data[i*4 + 2];
src[i + 12] = _data[i*4 + 3];
}
// calculate pairs for first 8 elements (cofactors)
tmp[0] = src[10] * src[15];
tmp[1] = src[11] * src[14];
tmp[2] = src[9] * src[15];
tmp[3] = src[11] * src[13];
tmp[4] = src[9] * src[14];
tmp[5] = src[10] * src[13];
tmp[6] = src[8] * src[15];
tmp[7] = src[11] * src[12];
tmp[8] = src[8] * src[14];
tmp[9] = src[10] * src[12];
tmp[10] = src[8] * src[13];
tmp[11] = src[9] * src[12];
// calculate first 8 elements (cofactors)
dst._data[0] = (tmp[0]-tmp[1])*src[5] + (tmp[3]-tmp[2])*src[6] + (tmp[4]-tmp[5])*src[7];
dst._data[1] = (tmp[1]-tmp[0])*src[4] + (tmp[6]-tmp[7])*src[6] + (tmp[9]-tmp[8])*src[7];
dst._data[2] = (tmp[2]-tmp[3])*src[4] + (tmp[7]-tmp[6])*src[5] + (tmp[10]-tmp[11])*src[7];
dst._data[3] = (tmp[5]-tmp[4])*src[4] + (tmp[8]-tmp[9])*src[5] + (tmp[11]-tmp[10])*src[6];
dst._data[4] = (tmp[1]-tmp[0])*src[1] + (tmp[2]-tmp[3])*src[2] + (tmp[5]-tmp[4])*src[3];
dst._data[5] = (tmp[0]-tmp[1])*src[0] + (tmp[7]-tmp[6])*src[2] + (tmp[8]-tmp[9])*src[3];
dst._data[6] = (tmp[3]-tmp[2])*src[0] + (tmp[6]-tmp[7])*src[1] + (tmp[11]-tmp[10])*src[3];
dst._data[7] = (tmp[4]-tmp[5])*src[0] + (tmp[9]-tmp[8])*src[1] + (tmp[10]-tmp[11])*src[2];
// calculate pairs for second 8 elements (cofactors)
tmp[0] = src[2]*src[7];
tmp[1] = src[3]*src[6];
tmp[2] = src[1]*src[7];
tmp[3] = src[3]*src[5];
tmp[4] = src[1]*src[6];
tmp[5] = src[2]*src[5];
tmp[6] = src[0]*src[7];
tmp[7] = src[3]*src[4];
tmp[8] = src[0]*src[6];
tmp[9] = src[2]*src[4];
tmp[10] = src[0]*src[5];
tmp[11] = src[1]*src[4];
// calculate second 8 elements (cofactors)
dst._data[8] = (tmp[0]-tmp[1])*src[13] + (tmp[3]-tmp[2])*src[14] + (tmp[4]-tmp[5])*src[15];
dst._data[9] = (tmp[1]-tmp[0])*src[12] + (tmp[6]-tmp[7])*src[14] + (tmp[9]-tmp[8])*src[15];
dst._data[10] = (tmp[2]-tmp[3])*src[12] + (tmp[7]-tmp[6])*src[13] + (tmp[10]-tmp[11])*src[15];
dst._data[11] = (tmp[5]-tmp[4])*src[12] + (tmp[8]-tmp[9])*src[13] + (tmp[11]-tmp[10])*src[14];
dst._data[12] = (tmp[2]-tmp[3])*src[10] + (tmp[5]-tmp[4])*src[11] + (tmp[1]-tmp[0])*src[9];
dst._data[13] = (tmp[7]-tmp[6])*src[10] + (tmp[8]-tmp[9])*src[11] + (tmp[0]-tmp[1])*src[8];
dst._data[14] = (tmp[6]-tmp[7])*src[9] + (tmp[11]-tmp[10])*src[11] + (tmp[3]-tmp[2])*src[8];
dst._data[15] = (tmp[10]-tmp[11])*src[10] + (tmp[4]-tmp[5])*src[8] + (tmp[9]-tmp[8])*src[9];
// calculate matrix inverse
det=src[0]*dst._data[0]+src[1]*dst._data[1]+src[2]*dst._data[2]+src[3]*dst._data[3];
det = 1/det;
for ( int j = 0; j < 16; j++) {
dst._data[j] *= det;
}
}
CMatrix3D CMatrix3D::GetInverse() const
{
CMatrix3D r;
GetInverse(r);
return r;
}
void CMatrix3D::Rotate(const CQuaternion& quat)
{
CMatrix3D rotationMatrix=quat.ToMatrix();
Concatenate(rotationMatrix);
}
CQuaternion CMatrix3D::GetRotation() const
{
float tr = _data2d[0][0] + _data2d[1][1] + _data2d[2][2];
int next[] = { 1, 2, 0 };
float quat[4];
if (tr > 0.f)
{
float s = sqrtf(tr + 1.f);
quat[3] = s * 0.5f;
s = 0.5f / s;
quat[0] = (_data2d[1][2] - _data2d[2][1]) * s;
quat[1] = (_data2d[2][0] - _data2d[0][2]) * s;
quat[2] = (_data2d[0][1] - _data2d[1][0]) * s;
}
else
{
int i = 0;
if (_data2d[1][1] > _data2d[0][0]) i = 1;
if (_data2d[2][2] > _data2d[i][i]) i = 2;
int j = next[i];
int k = next[j];
float s = sqrtf((_data2d[i][i] - (_data2d[j][j] + _data2d[k][k])) + 1.f);
quat[i] = s * 0.5f;
if (s != 0.f) s = 0.5f / s;
quat[3] = (_data2d[j][k] - _data2d[k][j]) * s;
quat[j] = (_data2d[i][j] + _data2d[j][i]) * s;
quat[k] = (_data2d[i][k] + _data2d[k][i]) * s;
}
return CQuaternion(quat[0], quat[1], quat[2], quat[3]);
}
void CMatrix3D::SetRotation(const CQuaternion& quat)
{
quat.ToMatrix(*this);
}
float CMatrix3D::GetYRotation() const
{
// Project the X axis vector onto the XZ plane
CVector3D axis = -GetLeft();
axis.Y = 0;
// Normalise projected vector
float len = axis.Length();
if (len < 0.0001f)
return 0.f;
axis *= 1.0f/len;
// Negate the return angle to match the SetYRotation convention
return -atan2(axis.Z, axis.X);
}
Index: ps/trunk/source/maths/Matrix3D.h
===================================================================
--- ps/trunk/source/maths/Matrix3D.h (revision 22032)
+++ ps/trunk/source/maths/Matrix3D.h (revision 22033)
@@ -1,324 +1,325 @@
-/* Copyright (C) 2017 Wildfire Games.
+/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
/*
* A Matrix class used for holding and manipulating transformation
* info.
*/
#ifndef INCLUDED_MATRIX3D
#define INCLUDED_MATRIX3D
#include "maths/Vector3D.h"
#include "maths/Vector4D.h"
class CQuaternion;
/////////////////////////////////////////////////////////////////////////
// CMatrix3D: a 4x4 matrix class for common operations in 3D
class CMatrix3D
{
public:
// the matrix data itself - accessible as either longhand names
// or via a flat or 2d array
// NOTE: _xy means row x, column y in the mathematical notation of this matrix, so don't be
// fooled by the way they're listed below
union {
struct {
float _11, _21, _31, _41;
float _12, _22, _32, _42;
float _13, _23, _33, _43;
float _14, _24, _34, _44;
};
float _data[16];
float _data2d[4][4];
// (Be aware that m(0,2) == _data2d[2][0] == _13, etc. This is to be considered a feature.)
};
public:
// constructors
CMatrix3D ()
{
}
CMatrix3D(
float a11, float a12, float a13, float a14,
float a21, float a22, float a23, float a24,
float a31, float a32, float a33, float a34,
float a41, float a42, float a43, float a44) :
_11(a11), _12(a12), _13(a13), _14(a14),
_21(a21), _22(a22), _23(a23), _24(a24),
_31(a31), _32(a32), _33(a33), _34(a34),
_41(a41), _42(a42), _43(a43), _44(a44)
{
}
CMatrix3D(float data[]) :
_11(data[0]), _21(data[1]), _31(data[2]), _41(data[3]),
_12(data[4]), _22(data[5]), _32(data[6]), _42(data[7]),
_13(data[8]), _23(data[9]), _33(data[10]), _43(data[11]),
_14(data[12]), _24(data[13]), _34(data[14]), _44(data[15])
{
}
// accessors to individual elements of matrix
// NOTE: in this function definition, 'col' and 'row' represent the column and row into the
// internal element matrix which is the transposed of the mathematical notation, so the first
// and second arguments here are actually the row and column into the mathematical notation.
float& operator()(int col, int row)
{
return _data[row*4+col];
}
const float& operator()(int col, int row) const
{
return _data[row*4+col];
}
float& operator[](int idx)
{
return _data[idx];
}
const float& operator[](int idx) const
{
return _data[idx];
}
// matrix multiplication
CMatrix3D operator*(const CMatrix3D &matrix) const
{
return CMatrix3D(
_11*matrix._11 + _12*matrix._21 + _13*matrix._31 + _14*matrix._41,
_11*matrix._12 + _12*matrix._22 + _13*matrix._32 + _14*matrix._42,
_11*matrix._13 + _12*matrix._23 + _13*matrix._33 + _14*matrix._43,
_11*matrix._14 + _12*matrix._24 + _13*matrix._34 + _14*matrix._44,
_21*matrix._11 + _22*matrix._21 + _23*matrix._31 + _24*matrix._41,
_21*matrix._12 + _22*matrix._22 + _23*matrix._32 + _24*matrix._42,
_21*matrix._13 + _22*matrix._23 + _23*matrix._33 + _24*matrix._43,
_21*matrix._14 + _22*matrix._24 + _23*matrix._34 + _24*matrix._44,
_31*matrix._11 + _32*matrix._21 + _33*matrix._31 + _34*matrix._41,
_31*matrix._12 + _32*matrix._22 + _33*matrix._32 + _34*matrix._42,
_31*matrix._13 + _32*matrix._23 + _33*matrix._33 + _34*matrix._43,
_31*matrix._14 + _32*matrix._24 + _33*matrix._34 + _34*matrix._44,
_41*matrix._11 + _42*matrix._21 + _43*matrix._31 + _44*matrix._41,
_41*matrix._12 + _42*matrix._22 + _43*matrix._32 + _44*matrix._42,
_41*matrix._13 + _42*matrix._23 + _43*matrix._33 + _44*matrix._43,
_41*matrix._14 + _42*matrix._24 + _43*matrix._34 + _44*matrix._44
);
}
// matrix multiplication/assignment
CMatrix3D& operator*=(const CMatrix3D &matrix)
{
Concatenate(matrix);
return *this;
}
// matrix scaling
CMatrix3D operator*(float f) const
{
return CMatrix3D(
_11*f, _12*f, _13*f, _14*f,
_21*f, _22*f, _23*f, _24*f,
_31*f, _32*f, _33*f, _34*f,
_41*f, _42*f, _43*f, _44*f
);
}
// matrix addition
CMatrix3D operator+(const CMatrix3D &m) const
{
return CMatrix3D(
_11+m._11, _12+m._12, _13+m._13, _14+m._14,
_21+m._21, _22+m._22, _23+m._23, _24+m._24,
_31+m._31, _32+m._32, _33+m._33, _34+m._34,
_41+m._41, _42+m._42, _43+m._43, _44+m._44
);
}
// matrix addition/assignment
CMatrix3D& operator+=(const CMatrix3D &m)
{
_11 += m._11; _21 += m._21; _31 += m._31; _41 += m._41;
_12 += m._12; _22 += m._22; _32 += m._32; _42 += m._42;
_13 += m._13; _23 += m._23; _33 += m._33; _43 += m._43;
_14 += m._14; _24 += m._24; _34 += m._34; _44 += m._44;
return *this;
}
// equality
bool operator==(const CMatrix3D &m) const
{
return _11 == m._11 && _21 == m._21 && _31 == m._31 && _41 == m._41 &&
_12 == m._12 && _22 == m._22 && _32 == m._32 && _42 == m._42 &&
_13 == m._13 && _23 == m._23 && _33 == m._33 && _43 == m._43 &&
_14 == m._14 && _24 == m._24 && _34 == m._34 && _44 == m._44;
}
// inequality
bool operator!=(const CMatrix3D& m) const
{
return !(*this == m);
}
// set this matrix to the identity matrix
void SetIdentity();
// set this matrix to the zero matrix
void SetZero();
// set this matrix to the orthogonal projection matrix (as with glOrtho)
void SetOrtho(float left, float right, float bottom, float top, float near, float far);
// set this matrix to the perspective projection matrix
void SetPerspective(float fov, float aspect, float near, float far);
+ void SetPerspectiveTile(float fov, float aspect, float near, float far, int tiles, int tile_x, int tile_y);
// concatenate arbitrary matrix onto this matrix
void Concatenate(const CMatrix3D& m)
{
(*this) = m * (*this);
}
// blend matrix using only 4x3 subset
void Blend(const CMatrix3D& m, float f)
{
_11 = m._11*f; _21 = m._21*f; _31 = m._31*f;
_12 = m._12*f; _22 = m._22*f; _32 = m._32*f;
_13 = m._13*f; _23 = m._23*f; _33 = m._33*f;
_14 = m._14*f; _24 = m._24*f; _34 = m._34*f;
}
// blend matrix using only 4x3 and add onto existing blend
void AddBlend(const CMatrix3D& m, float f)
{
_11 += m._11*f; _21 += m._21*f; _31 += m._31*f;
_12 += m._12*f; _22 += m._22*f; _32 += m._32*f;
_13 += m._13*f; _23 += m._23*f; _33 += m._33*f;
_14 += m._14*f; _24 += m._24*f; _34 += m._34*f;
}
// set this matrix to a rotation matrix for a rotation about X axis of given angle
void SetXRotation(float angle);
// set this matrix to a rotation matrix for a rotation about Y axis of given angle
void SetYRotation(float angle);
// set this matrix to a rotation matrix for a rotation about Z axis of given angle
void SetZRotation(float angle);
// set this matrix to a rotation described by given quaternion
void SetRotation(const CQuaternion& quat);
// concatenate a rotation about the X axis onto this matrix
void RotateX(float angle);
// concatenate a rotation about the Y axis onto this matrix
void RotateY(float angle);
// concatenate a rotation about the Z axis onto this matrix
void RotateZ(float angle);
// concatenate a rotation described by given quaternion
void Rotate(const CQuaternion& quat);
// sets this matrix to the given translation matrix (any existing transformation will be overwritten)
void SetTranslation(float x, float y, float z);
void SetTranslation(const CVector3D& vector);
// concatenate given translation onto this matrix. Assumes the current
// matrix is an affine transformation (i.e. the bottom row is [0,0,0,1])
// as an optimisation.
void Translate(float x, float y, float z);
void Translate(const CVector3D& vector);
// apply translation after this matrix (M = M * T)
void PostTranslate(float x, float y, float z);
// set this matrix to the given scaling matrix
void SetScaling(float x_scale, float y_scale, float z_scale);
// concatenate given scaling matrix onto this matrix
void Scale(float x_scale, float y_scale, float z_scale);
// calculate the inverse of this matrix, store in dst
void GetInverse(CMatrix3D& dst) const;
// return the inverse of this matrix
CMatrix3D GetInverse() const;
// calculate the transpose of this matrix, store in dst
CMatrix3D GetTranspose() const;
// return the translation component of this matrix
CVector3D GetTranslation() const;
// return left vector, derived from rotation
CVector3D GetLeft() const;
// return up vector, derived from rotation
CVector3D GetUp() const;
// return forward vector, derived from rotation
CVector3D GetIn() const;
// return a quaternion representing the matrix's rotation
CQuaternion GetRotation() const;
// return the angle of rotation around the Y axis in range [-pi,pi]
// (based on projecting the X axis onto the XZ plane)
float GetYRotation() const;
// transform a 3D vector by this matrix
CVector3D Transform(const CVector3D &vector) const
{
CVector3D result;
Transform(vector, result);
return result;
}
void Transform(const CVector3D& vector, CVector3D& result) const
{
result.X = _11*vector.X + _12*vector.Y + _13*vector.Z + _14;
result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z + _24;
result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z + _34;
}
// transform a 4D vector by this matrix
CVector4D Transform(const CVector4D &vector) const
{
CVector4D result;
Transform(vector, result);
return result;
}
void Transform(const CVector4D& vector, CVector4D& result) const
{
result.X = _11*vector.X + _12*vector.Y + _13*vector.Z + _14*vector.W;
result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z + _24*vector.W;
result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z + _34*vector.W;
result.W = _41*vector.X + _42*vector.Y + _43*vector.Z + _44*vector.W;
}
// rotate a vector by this matrix
CVector3D Rotate(const CVector3D& vector) const
{
CVector3D result;
Rotate(vector, result);
return result;
}
void Rotate(const CVector3D& vector, CVector3D& result) const
{
result.X = _11*vector.X + _12*vector.Y + _13*vector.Z;
result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z;
result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z;
}
// rotate a vector by the transpose of this matrix
void RotateTransposed(const CVector3D& vector,CVector3D& result) const;
CVector3D RotateTransposed(const CVector3D& vector) const;
};
-#endif
+#endif // INCLUDED_MATRIX3D