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