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