1 /************************************************************************************
2 
3 	AstroMenace
4 	Hardcore 3D space scroll-shooter with spaceship upgrade possibilities.
5 	Copyright (c) 2006-2019 Mikhail Kurinnoi, Viewizard
6 
7 
8 	AstroMenace is free software: you can redistribute it and/or modify
9 	it under the terms of the GNU General Public License as published by
10 	the Free Software Foundation, either version 3 of the License, or
11 	(at your option) any later version.
12 
13 	AstroMenace is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 	GNU General Public License for more details.
17 
18 	You should have received a copy of the GNU General Public License
19 	along with AstroMenace. If not, see <https://www.gnu.org/licenses/>.
20 
21 
22 	Website: https://viewizard.com/
23 	Project: https://github.com/viewizard/astromenace
24 	E-mail: viewizard@viewizard.com
25 
26 *************************************************************************************/
27 
28 #include "../graphics/graphics.h"
29 #include "../math/math.h"
30 #include "../audio/audio.h"
31 #include "camera.h"
32 
33 namespace viewizard {
34 
35 namespace {
36 
37 // Camera update flag (need for frustum calculation on camera update).
38 bool CameraUpdated{true};
39 // Camera location.
40 sVECTOR3D CameraLocation{0.0f, 0.0f, 0.0f};
41 // Camera rotation angles.
42 sVECTOR3D CameraRotation{0.0f, 0.0f, 0.0f};
43 // Camera deviation (need for camera shake effect).
44 sVECTOR3D CameraDeviation{0.0f, 0.0f, 0.0f};
45 // Camera focus point (anchor).
46 sVECTOR3D CameraFocusPoint{0.0f, 0.0f, 0.0f};
47 
48 } // unnamed namespace
49 
50 
51 /*
52  * Update listener position and orientation.
53  */
UpdateAudioListenerPosition()54 static void UpdateAudioListenerPosition()
55 {
56 	if (!vw_GetAudioStatus())
57 		return;
58 
59 	float ListenerPosition[3]{CameraLocation.x, CameraLocation.y, CameraLocation.z};
60 	float ListenerVelocity[3]{0.0f, 0.0f, 0.0f};
61 
62 	// orientation expressed as "at" and "up" vectors
63 	sVECTOR3D ListenerOrientationAT(0.0f, 0.0f, -1.0f);
64 	vw_RotatePoint(ListenerOrientationAT, CameraRotation);
65 	sVECTOR3D ListenerOrientationUP(0.0f, 1.0f, 0.0f);
66 	vw_RotatePoint(ListenerOrientationUP, CameraRotation);
67 	float ListenerOrientation[6]{ListenerOrientationAT.x, ListenerOrientationAT.y, ListenerOrientationAT.z,
68 				     ListenerOrientationUP.x, ListenerOrientationUP.y, ListenerOrientationUP.z};
69 
70 	vw_Listener(ListenerPosition, ListenerVelocity, ListenerOrientation);
71 }
72 
73 /*
74  * Set camera location.
75  */
vw_SetCameraLocation(const sVECTOR3D & NewLocation)76 void vw_SetCameraLocation(const sVECTOR3D &NewLocation)
77 {
78 	CameraLocation = NewLocation;
79 	CameraUpdated = true;
80 
81 	UpdateAudioListenerPosition();
82 }
83 
84 /*
85  * Increment camera location by vector.
86  */
vw_IncCameraLocation(const sVECTOR3D & IncLocation)87 void vw_IncCameraLocation(const sVECTOR3D &IncLocation)
88 {
89 	CameraLocation += IncLocation;
90 	CameraFocusPoint += IncLocation;
91 	CameraUpdated = true;
92 
93 	UpdateAudioListenerPosition();
94 }
95 
96 /*
97  * Get camera location.
98  */
vw_GetCameraLocation(sVECTOR3D * CurrentLocation)99 sVECTOR3D vw_GetCameraLocation(sVECTOR3D *CurrentLocation)
100 {
101 	if (CurrentLocation)
102 		*CurrentLocation = CameraLocation;
103 	return CameraLocation;
104 }
105 
106 /*
107  * Get camera rotation angles.
108  */
vw_GetCameraRotation(sVECTOR3D * CurrentRotation)109 sVECTOR3D vw_GetCameraRotation(sVECTOR3D *CurrentRotation)
110 {
111 	if (CurrentRotation)
112 		*CurrentRotation = CameraRotation;
113 	return CameraRotation;
114 }
115 
116 /*
117  * Get camera focus point (anchor).
118  */
vw_GetCameraFocusPoint()119 sVECTOR3D vw_GetCameraFocusPoint()
120 {
121 	return CameraFocusPoint;
122 }
123 
124 /*
125  * Move camera by direction.
126  */
vw_SetCameraMove(const sVECTOR3D & NewRotation,float ChangeDistance,const sVECTOR3D & Point)127 void vw_SetCameraMove(const sVECTOR3D &NewRotation, float ChangeDistance, const sVECTOR3D &Point)
128 {
129 	// revert back all movements
130 	CameraLocation -= Point;
131 	vw_RotatePointInv(CameraLocation, CameraRotation);
132 	// change distance
133 	CameraLocation.z += ChangeDistance;
134 	// change rotation angles
135 	CameraRotation += NewRotation;
136 	// apply corrected distance and angles to camera
137 	vw_RotatePoint(CameraLocation, CameraRotation ^ (-1.0f));
138 	CameraLocation += Point;
139 	CameraUpdated = true;
140 
141 	UpdateAudioListenerPosition();
142 }
143 
144 /*
145  * Move camera around point (anchor).
146  */
vw_SetCameraMoveAroundPoint(const sVECTOR3D & Point,float ChangeDistance,const sVECTOR3D & ChangeRotation)147 void vw_SetCameraMoveAroundPoint(const sVECTOR3D &Point, float ChangeDistance, const sVECTOR3D &ChangeRotation)
148 {
149 	constexpr float DegToRadFactor = 0.0174532925f; // conversion factor to convert degrees to radians
150 	CameraFocusPoint = Point;
151 	// initial camera move
152 	vw_SetCameraMove(ChangeRotation, ChangeDistance, Point);
153 
154 	// rotate camera to the point
155 	sVECTOR3D exV{0.0f, 0.0f, 0.0f};
156 	sVECTOR3D V{Point.x - CameraLocation.x,
157 		    Point.y - CameraLocation.y,
158 		    Point.z - CameraLocation.z};
159 	V.Normalize();
160 	if (V.x * V.x + V.y * V.y + V.z * V.z != 0)
161 		exV = V;
162 
163 	float newrotY{0.0f};
164 	if (exV.z != 0.0f) {
165 		if (((0.0f > exV.x) && (0.0f > -exV.z)) || ((0.0f < exV.x) && (0.0f < -exV.z)))
166 			newrotY = (atanf(fabsf(exV.x) / fabsf(exV.z))) / DegToRadFactor;
167 		else
168 			newrotY = -(atanf(fabsf(exV.x) / fabsf(exV.z))) / DegToRadFactor;
169 	}
170 
171 	float newrotX{0.0f};
172 	float kat{(exV.z) * (exV.z) + (exV.x) * (exV.x)};
173 	if (kat != 0.0f) {
174 		kat = sqrtf(kat);
175 		if (0 < exV.y)
176 			newrotX = -(atanf(fabsf(exV.y) / kat)) / DegToRadFactor;
177 		else
178 			newrotX = (atanf(fabsf(exV.y) / kat)) / DegToRadFactor;
179 	}
180 	if (0 > -exV.z)
181 		newrotY += 180;
182 
183 	CameraRotation.x = -newrotX;
184 	CameraRotation.y = -newrotY;
185 	CameraUpdated = true;
186 
187 	UpdateAudioListenerPosition();
188 }
189 
190 /*
191  * Camera deviation setup (need for camera shake effect).
192  */
vw_SetCameraDeviation(const sVECTOR3D & NewCameraDeviation)193 void vw_SetCameraDeviation(const sVECTOR3D &NewCameraDeviation)
194 {
195 	CameraDeviation = NewCameraDeviation;
196 }
197 
198 /*
199  * Camera setup.
200  */
vw_CameraLookAt()201 void vw_CameraLookAt()
202 {
203 	vw_Rotate(-CameraRotation.x, 1.0f, 0.0f, 0.0f);
204 	vw_Rotate(-CameraRotation.y, 0.0f, 1.0f, 0.0f);
205 	vw_Rotate(-CameraRotation.z, 0.0f, 0.0f, 1.0f);
206 
207 	vw_Translate((CameraLocation^(-1.0f)) - CameraDeviation);
208 
209 	// recalculate frustum on camera update
210 	if (CameraUpdated) {
211 		vw_CalculateFrustum();
212 		CameraUpdated = false;
213 	}
214 }
215 
216 } // viewizard namespace
217