1 /**
2 Copyright: Copyright (c) 2014-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module voxelman.graphics.fpscamera;
8 
9 import voxelman.log;
10 import voxelman.math;
11 
12 struct FpsCamera
13 {
14 	void move(Vector3f vec)
15 	{
16 		if (isUpdated == false) update();
17 		position += vec;
18 		isUpdated = false;
19 	}
20 
21 	void moveAxis(vec3 vec)
22 	{
23 		if (isUpdated == false) update();
24 
25 		// Strafe
26 		vec3 right = rotationQuatHor.rotate(vec3(1,0,0));
27 		position += right * vec.x;
28 
29 		// Move up/down
30 		position.y += vec.y;
31 
32 		// Move forward
33 		vec3 target = rotationQuatHor.rotate(vec3(0,0,-1));
34 		position += target * vec.z;
35 
36 		isUpdated = false;
37 	}
38 
39 	void rotate(vec2 angles)
40 	{
41 		heading += angles * sensivity;
42 		clampHeading();
43 		isUpdated = false;
44 	}
45 
46 	void setHeading(vec2 heading)
47 	{
48 		this.heading = heading;
49 		clampHeading();
50 		isUpdated = false;
51 	}
52 
53 	void clampHeading()
54 	{
55 		heading.x %= 360;
56 		heading.y = clamp!float(heading.y, ANGLE_VERT_MIN, ANGLE_VERT_MAX);
57 	}
58 
59 	void update()
60 	{
61 		rotationQuatHor = rotationQuaternion!float(vec3(0,1,0), degtorad!float(heading.x));
62 		rotationQuatVert = rotationQuaternion!float(vec3(1,0,0), degtorad!float(heading.y));
63 
64 		rotationQuat = rotationQuatHor * rotationQuatVert;
65 		rotationQuat.normalize();
66 		calcVectors();
67 
68 		Matrix4f rotation = rotationQuat.toMatrix4x4.inverse;
69 		Matrix4f translation = translationMatrix(-position);
70 
71 		cameraToClipMatrix = rotation * translation;
72 		isUpdated = true;
73 	}
74 
75 	ref Matrix4f cameraMatrix()
76 	{
77 		if(!isUpdated) update();
78 		return cameraToClipMatrix;
79 	}
80 
81 	void printVectors()
82 	{
83 		infof("camera pos\t%s\ttarget\t%s\tup\t%s\tright\t%s",
84 			position, target, up, right);
85 	}
86 
87 	private void calcVectors()
88 	{
89 		target = rotationQuat.rotate(vec3(0,0,-1));
90 		up = rotationQuat.rotate(vec3(0,1,0));
91 		right = rotationQuat.rotate(vec3(1,0,0));
92 	}
93 
94 	Matrix4f perspective()
95 	{
96 		return perspectiveMatrix(fov, aspect, near, far);
97 	}
98 
99 	float sensivity = 1.0f;
100 	float fov = 60; // field of view
101 	float aspect = 1; // window width/height
102 	float near = 0.01;
103 	float far = 4000;
104 
105 	vec3 position = vec3(0, 0, 0);
106 	vec2 heading = vec2(0, 0); // hor, vert
107 
108 	vec3 target = vec3(0, 0, -1);
109 	vec3 up	= vec3(0, 1, 0);
110 	vec3 right	= vec3(1, 0, 0);
111 
112 	enum ANGLE_VERT_MIN = -90.0f;	//minimum pitch
113 	enum ANGLE_VERT_MAX =  90.0f;	//maximal pitch
114 
115 	Matrix4f cameraToClipMatrix;
116 
117 	Quaternionf rotationQuat;
118 	Quaternionf rotationQuatHor;
119 	Quaternionf rotationQuatVert;
120 
121 	bool isUpdated = false;
122 }