Welcome to mirror list, hosted at ThFree Co, Russian Federation.

camera.h « Graphics « Source - github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 7acc05d0eed7ba9382d21bed72b84714b732ea2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
//-----------------------------------------------------------------------------
//           Name: camera.cpp
//      Developer: Wolfire Games LLC
//         Author: David Rosen
//    Description: The camera class holds the position, and rotation of the
//                   camera, and the view settings
//        License: Read below
//-----------------------------------------------------------------------------
//
//
//   Copyright 2022 Wolfire Games LLC
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//
//-----------------------------------------------------------------------------
#pragma once

#include <Graphics/graphics.h>
#include <Math/vec4.h>

#include <opengl.h>

#include <vector>
#include <list>
#include <emmintrin.h>

class CameraObject;

/// The Camera class handles the view orientation in 3D space.
class Camera
{
private:
    vec3 facing;  ///< Vector for which direction the camera is pointing
    vec3 flat_facing; ///< Facing on the XZ plane
    float target_horz_fov; ///< The field of view, in degrees.
    float near_plane; ///< Distance to the near plane
    float far_plane; ///< Distance to the far plane
    float chase_distance; ///< How far the chase camera is from the player.
    float old_chase_distance;
    float interp_chase_distance;

    vec3 velocity;
    vec3 up; ///< Up vector (combined with facing, gives complete orientation)
    
    vec3 pos; ///< Current position
    vec3 old_pos; ///< Previous timestep position
	public: // Made this public temporarily to fix VR problem TODO: do this more cleanly
    vec3 interp_pos; ///< Interpolated position (for smooth rendering)
    private:
    float y_rotation; ///< Rotation on the y axis (left and right)
    float x_rotation; ///< Rotation on the x axis (up and down)
    float z_rotation; ///< Rotation on the z axis (roll clockwise and ccw)
    float old_y_rotation; ///< Previous timestep y_rotation
    float old_x_rotation; ///< Previous timestep x_rotation
    float old_z_rotation; ///< Previous timestep z_rotation

    mat4 cameraViewMatrix; ///< Matrix to transform world to view
    mat4 inverseCameraViewMatrix; ///< Matrix to transform view to world
    mat4 lightProjectionMatrix; ///< Ortographic projection matrix for shadows
    mat4 lightViewMatrix; ///< View matrix from light pov for shadows
    
    vec3 mouseray; ///< Vector in the direction that the mouse is pointing
    
    float modelview_matrix[16]; ///< Camera modelview matrix
    float projection_matrix[16]; ///< Camera projection matrix
    int viewport[4]; ///< Viewport dimensions (in pixels)

    int interp_steps;
    int interp_progress;
    float GetInterpWeight() const;

    bool auto_camera;
    int flags_;        

    /// Initializes the camera member variables to default
    void reset();

public:
    vec3 tint;
    vec3 vignette_tint;
    mat4 prev_view_mat;
    // Depth of field filter settings
    float near_blur_amount;
    float far_blur_amount;
    float near_sharp_dist;
    float far_sharp_dist;
    float near_blur_transition_size;
    float far_blur_transition_size;

    float frustumPlanes[6][4]; ///< Frustum plane parameters (ax+by+cz+d)

    struct SIMDPlane {  // TODO: Comment out if SIMD not supported?
        __m128 normal_x;  // same value pre-replicated 4 times for each of these
        __m128 normal_y;
        __m128 normal_z;
        __m128 d;
    };
    SIMDPlane simdFrustumPlanes[6];

    mat4 biasMatrix; ///< Bias matrix for shadow projection
    bool flexible_fov;
    enum CameraFlags {
        kEditorCamera = 1 << 0,
        kPreviewCamera = 1 << 1
    };

    vec3 GetCenterVel() const;
    const vec3& GetFacing() const; ///< Accessor for facing
    const vec3& GetFlatFacing() const; ///< Accessor for flat_facing
    void SetFlatFacing(const vec3 &v); ///< Mutator for flat_facing
	void FixDiscontinuity();

    /// The default Camera constructer initializes the biasMatrix and calls reset()
    Camera();

    CameraObject* m_camera_object; ///<CameraObject exposed for global access (fix)
    
    /**
    * Sets the CameraObject so that it can be accessed globally.
    * @param camera_object A pointer to the CameraObject.
    */
    inline void SetCameraObject(CameraObject* camera_object) { 
        reset(); 
        m_camera_object = camera_object; 
    };
    
    /**
    * Get the CameraObject that is controlling the camera.
    */
    CameraObject* getCameraObject() {
        return m_camera_object; 
    }

    /**
    * Set how far the camera is behind the player.
    * @param chase_distance The new chase distance.
    */
    void SetDistance(const float chase_distance);
    
    /**
    * Set the Y-axis (left and right) rotation of the camera.
    * @param y_rotation The new Y-axis rotation in degrees.
    */
    void SetYRotation(const float y_rotation);    
    
    /**
    * Set the X-axis (up and down) rotation of the camera.
    * @param x_rotation The new X-axis rotation in degrees.
    */
    void SetXRotation(const float x_rotation);

    /**
    * Set the Z-axis (roll) rotation of the camera.
    * @param z_rotation The new Z-axis rotation in degrees.
    */
    void SetZRotation(const float z_rotation);

    void SetInterpSteps(int num_steps);
    void IncrementProgress();

    /**
    * Set the position of the camera.
    * @param pos The new position.
    */
    void SetPos(const vec3 &pos);
    void ASSetPos(vec3 pos);

    /**
    * Set the field of view of the camera.
    * @param fov The new FOV in degrees.
    */
    void SetFOV(const float fov);
    
    /**
    * Set the x and y rotation of the camera to look at a point.
    * @param point The point to look at.
    */
    void LookAt(const vec3 &point);
    

    // Lots of accessors
    float GetYRotation() const;
    float GetXRotation() const;
    float GetZRotation() const;
    vec3 GetPos() const;
    vec3 ASGetPos() const;
    const vec3& GetMouseRay() const;
    vec3 ASGetMouseRay() const;
    const vec3& GetUpVector() const;
    vec3 ASGetUpVector() const;
    const float& GetNearPlane() const;
    const float& GetFarPlane() const;
    const float& GetFOV() const;
    const vec3& GetVelocity() const;
    void SetVelocity(const vec3 &vel);

    void SetAutoCamera( bool val );
    bool GetAutoCamera( );

    /**
    * Get the Camera->World transformation matrix.
    * @return The 4x4 transform matrix.
    */
    const mat4& getInverseCameraMatrix() const;
    
    /**
    * Get the World->Camera transformation matrix.
    * @return The 4x4 transform matrix.
    */
    const mat4& getCameraMatrix() const;

    /**
    * Convert a point from world coordinates to camera coordinates.
    * @param absolute The point in world space to convert.
    * @return The point in camera space.
    */ 
    vec3 getRelative(const vec3 &absolute);
    
    /**
    * Convert a point from world coordinates to screen coordinates.
    * @param point The point in world space to convert.
    * @return The point in screen space.
    */ 
    vec3 worldToScreen(const vec3 point) const;

    /**
    * Set up an orthographic projection for use with shadow rendering.
    * @param direction The direction that the light is coming from.
    *                   The projection will face the opposite direction.
    * @param center       Where the projection will start.
    * @param scale       The dimensions of the projection square.
    */
    void applyShadowViewpoint(vec3 direction, vec3 center, float scale, mat4 *proj_matrix = NULL, mat4 *view_matrix = NULL, float far_back = 1000.0f);

    /**
    * Apply the camera view to the OpenGL matrices.
    */
    void applyViewpoint();

    /**
    * Gets a vector that points through a specific pixel on the screen.
    * @param x X-coordinate in pixels
    * @param y Y-coordinate in pixels
    * @return The 3D vector that would go through that pixel.
    */
    vec3 GetRayThroughPixel(int x, int y);

    /**
    * Get the coordinates of a pixel (un)projected into world space.
    * @param x X-coordinate in pixels
    * @param y Y-coordinate in pixels
    * @return The 3D coordinates of the (un)projected pixel.
    */
    vec3 UnProjectPixel(int x, int y);

    /**
    * Get the coordinates of a world space point projected on the screen.
    * @param point The world space point to project
    * @return The coordinates of the pixel.
    */
    vec3 ProjectPoint(const vec3 &point);
    vec3 ProjectPoint(float x, float y, float z);

    /**
    * Calculate facing vectors based on rotation values.
    */
    void CalcFacing();
    
    /**
    * Calculate up vector based on facing vector and global up (0,1,0).
    */
    void calcUp();
    
    /**
    * Calculate frustum plane parameters based on modelview and 
    * projection matrices.
    */
    void calcFrustumPlanes( const mat4 &p, const mat4 &mv );
        
    /**
    * Check if a sphere is within the view frustum.
    * @param where The center of the sphere.
    * @param radius The radius of the sphere.
    * @return Returns 2 if the sphere is entirely in the frustum, 1 if partially, 0 if not at all
    */
    int checkSphereInFrustum(vec3 where, float radius) const;

    /**
    * Check if an array of spheres are within the view frustum.
    * @param count The number of spheres to check.
    * @param where_x The center of the sphere (x).
    * @param where_y The center of the sphere (y).
    * @param where_z The center of the sphere (z).
    * @param radius The radius of the spheres (same across all the spheres).
    * @param radius The view distance to cull against before checking against frustum planes.
    * @param is_visible_result The result of the visibility checks will be written here, not bit-packed.
    */
    void checkSpheresInFrustum(int count, float* where_x, float* where_y, float* where_z, float radius, float cull_distance_squared, uint32_t* is_visible_result) const;

    /**
    * Check if an axis-aligned box is within the view frustum.
    * @param start The minimum corner of the box.
    * @param end The maximum corner of the box.
    * @return Returns 2 if fully in, 1 if partly in, 0 if out of frustum.
    */
    int checkBoxInFrustum(vec3 start, vec3 end) const;

    /**
    * Camera uses the Singleton pattern, this returns a pointer to the static Camera.
    * @return Returns a pointer to the static Camera.
    */
    void PushState();
    void PopState();
    mat4 GetPerspectiveMatrix() const;
    void ASSetVelocity(vec3 vel);
    void UpdateShake();
    float GetChaseDistance() const;
    void SetFacing(const vec3 &_facing);
    void SetUp(const vec3 &_up);
    void ASSetUp( vec3 _up );
    void ASSetFacing( vec3 _facing );
    void ASLookAt(vec3 new_val);
    mat4 GetViewMatrix();
    mat4 GetProjMatrix();
    void DrawSafeZone();
    int GetFlags();
    void SetFlags(int val);

    //void PrintDifferences( const Camera& cam );
    void SetMatrices(const mat4& view, const mat4& proj);
};

class ActiveCameras {
private:
    //Cameras used logically to represent a remote virtual player, but isn't used for rendering.
    std::vector<Camera> virtual_cameras;
    std::vector<int> free_virtual_cameras;

    std::list<Camera> cameras;
    std::vector<Camera*> camera_ptrs;
    Camera* active;
    int active_id;

    void mSet(int which) {
        if(which >= (int)cameras.size()){
            cameras.resize(which+1);
            camera_ptrs.resize(cameras.size());
            int counter = 0;
            for(std::list<Camera>::iterator iter = cameras.begin(); 
                iter != cameras.end(); ++iter)
            {
                camera_ptrs[counter++] = &(*iter);
            }
        }
        active = camera_ptrs[which];
        active_id = which;
    }
public:
	std::vector<Camera>& GetVirtualCameras() {
		return virtual_cameras;
	}
 

    int CreateVirtualCameraInstance() {
        int virtual_camera_index = 0;
        if(free_virtual_cameras.size() > 0) {
            virtual_camera_index = *free_virtual_cameras.rbegin();
            free_virtual_cameras.resize(free_virtual_cameras.size() - 1);
        } else {
            virtual_cameras.resize(virtual_cameras.size() + 1);
            virtual_camera_index = (int) virtual_cameras.size() - 1;
        }

        return virtual_camera_index + 255;
    }

    void FreeVirtualCameraInstance(int index) {
        int virtual_camera_index = index - 255;

        if(virtual_camera_index >= 0) {
            free_virtual_cameras.push_back(virtual_camera_index);
        }
    }

    static ActiveCameras* Instance() {
        static ActiveCameras instance;
        return &instance;
    }

    static Camera* Get() {
        return Instance()->active;
    }

    static Camera* GetCamera(int camera_id) {
        if (camera_id >= 255) {
            int virtual_camera_index = camera_id - 255;

            if (virtual_camera_index >= 0 && virtual_camera_index < Instance()->virtual_cameras.size()) {
                return &Instance()->virtual_cameras[virtual_camera_index];
            } else {
                return nullptr;
            }
        } else {
#ifdef DEBUG
            if(NumCameras() <= camera_id) {
                LOGW << "Trying to get camera with id " << camera_id << ", but only " << NumCameras() << " are available" << std::endl;
                return Instance()->camera_ptrs[camera_id];
            }
#endif
            if (camera_id >= 0 && camera_id < Instance()->camera_ptrs.size()) {
                return Instance()->camera_ptrs[camera_id];
            } else {
                return nullptr;
            }
        }
    }

    static int NumCameras() {
        return (int) Instance()->cameras.size();
    }

    void UpdatePrevViewMats() {
        for(std::list<Camera>::iterator iter = cameras.begin(); 
            iter != cameras.end(); ++iter)
        {
            Camera* camera = &(*iter);
            camera->prev_view_mat = camera->GetViewMatrix();
        }

        for(std::vector<Camera>::iterator iter = virtual_cameras.begin(); 
            iter != virtual_cameras.end(); ++iter)
        {
            Camera* camera = &(*iter);
            camera->prev_view_mat = camera->GetViewMatrix();
        }
    }

    static int GetID() {
        return Instance()->active_id;
    }

    static void Set(int which) {
        Instance()->mSet(which);
    }

    void Dispose() {
        virtual_cameras.clear();
        cameras.clear();
        camera_ptrs.clear();
        active = NULL;
    }

};