Browse Source

Added basic view frustum culling

Thomas Buck 10 years ago
parent
commit
21d2478397
14 changed files with 406 additions and 331 deletions
  1. 3
    0
      ChangeLog.md
  2. 21
    6
      include/Camera.h
  3. 12
    0
      include/Render.h
  4. 38
    17
      include/RoomData.h
  5. 0
    23
      include/World.h
  6. 234
    35
      src/Camera.cpp
  7. 0
    145
      src/Entity.cpp
  8. 3
    7
      src/Game.cpp
  9. 57
    21
      src/Render.cpp
  10. 6
    10
      src/Room.cpp
  11. 0
    28
      src/RoomData.cpp
  12. 11
    0
      src/UI.cpp
  13. 9
    38
      src/World.cpp
  14. 12
    1
      src/loader/LoaderTR2.cpp

+ 3
- 0
ChangeLog.md View File

2
 
2
 
3
 ## OpenRaider (0.1.3) xythobuz <xythobuz@xythobuz.de>
3
 ## OpenRaider (0.1.3) xythobuz <xythobuz@xythobuz.de>
4
 
4
 
5
+    [ 20141222 ]
6
+    * Added basic (not yet working) view frustum culling
7
+
5
     [ 20141220 ]
8
     [ 20141220 ]
6
     * Fixed Room StaticModel rotation
9
     * Fixed Room StaticModel rotation
7
 
10
 

+ 21
- 6
include/Camera.h View File

8
 #ifndef _CAMERA_H_
8
 #ifndef _CAMERA_H_
9
 #define _CAMERA_H_
9
 #define _CAMERA_H_
10
 
10
 
11
+#include <glm/vec2.hpp>
11
 #include <glm/vec3.hpp>
12
 #include <glm/vec3.hpp>
12
 #include <glm/mat4x4.hpp>
13
 #include <glm/mat4x4.hpp>
13
 
14
 
15
+#include "RoomData.h"
16
+
14
 class Camera {
17
 class Camera {
15
   public:
18
   public:
16
 
19
 
18
 
21
 
19
     static void handleAction(ActionEvents action, bool isFinished);
22
     static void handleAction(ActionEvents action, bool isFinished);
20
     static void handleMouseMotion(int x, int y);
23
     static void handleMouseMotion(int x, int y);
21
-    static glm::mat4 getViewMatrix();
22
-
23
-    static float getRadianPitch() { return thetaX; }
24
-    static float getRadianYaw() { return thetaY; }
25
-    static void setRadianPitch(float x) { thetaX = x; }
24
+    static bool update();
26
 
25
 
27
     static void setPosition(glm::vec3 p) { pos = p; }
26
     static void setPosition(glm::vec3 p) { pos = p; }
28
     static glm::vec3 getPosition() { return pos; }
27
     static glm::vec3 getPosition() { return pos; }
29
 
28
 
29
+    static glm::vec2 getRotation() { return rot; }
30
+    static glm::mat4 getProjectionMatrix() { return projection; }
31
+    static glm::mat4 getViewMatrix() { return view; }
32
+
30
     static void setSensitivityX(float sens) { rotationDeltaX = sens; }
33
     static void setSensitivityX(float sens) { rotationDeltaX = sens; }
31
     static float getSensitivityX() { return rotationDeltaX; }
34
     static float getSensitivityX() { return rotationDeltaX; }
32
 
35
 
33
     static void setSensitivityY(float sens) { rotationDeltaY = sens; }
36
     static void setSensitivityY(float sens) { rotationDeltaY = sens; }
34
     static float getSensitivityY() { return rotationDeltaY; }
37
     static float getSensitivityY() { return rotationDeltaY; }
35
 
38
 
39
+    static void setUpdateViewFrustum(bool u) { updateViewFrustum = u; }
40
+    static bool getUpdateViewFrustum() { return updateViewFrustum; }
41
+
42
+    static bool boxInFrustum(BoundingBox b);
43
+    static void displayFrustum(glm::mat4 MVP);
44
+
36
   private:
45
   private:
37
     static glm::vec3 pos;
46
     static glm::vec3 pos;
38
-    static float thetaX, thetaY;
47
+    static glm::vec2 rot;
48
+    static glm::vec3 lastPos;
49
+    static glm::vec2 lastRot;
50
+    static glm::vec2 lastSize;
51
+    static glm::mat4 projection;
52
+    static glm::mat4 view;
39
     static float rotationDeltaX, rotationDeltaY;
53
     static float rotationDeltaX, rotationDeltaY;
54
+    static bool updateViewFrustum;
40
 };
55
 };
41
 
56
 
42
 #endif
57
 #endif

+ 12
- 0
include/Render.h View File

9
 #ifndef _RENDER_H_
9
 #ifndef _RENDER_H_
10
 #define _RENDER_H_
10
 #define _RENDER_H_
11
 
11
 
12
+#include <vector>
12
 #include <glm/vec4.hpp>
13
 #include <glm/vec4.hpp>
13
 
14
 
15
+#include "Room.h"
14
 #include "TextureManager.h"
16
 #include "TextureManager.h"
15
 
17
 
16
 enum class RenderMode {
18
 enum class RenderMode {
28
 
30
 
29
     static void display();
31
     static void display();
30
 
32
 
33
+    static void clearRoomList();
34
+
31
     static void screenShot(const char* filenameBase);
35
     static void screenShot(const char* filenameBase);
32
 
36
 
33
     static void drawTexture(float x, float y, float w, float h, glm::vec4 color,
37
     static void drawTexture(float x, float y, float w, float h, glm::vec4 color,
34
                             unsigned int texture, TextureManager::TextureStorage s);
38
                             unsigned int texture, TextureManager::TextureStorage s);
35
 
39
 
40
+    static void setDisplayViewFrustum(bool d) { displayViewFrustum = d; }
41
+    static bool getDisplayViewFrustum() { return displayViewFrustum; }
42
+
36
   private:
43
   private:
44
+    static void buildRoomList(int room);
45
+
37
     static RenderMode mode;
46
     static RenderMode mode;
47
+    static std::vector<Room*> roomList;
48
+
49
+    static bool displayViewFrustum;
38
 };
50
 };
39
 
51
 
40
 #endif
52
 #endif

+ 38
- 17
include/RoomData.h View File

15
 class BoundingBox {
15
 class BoundingBox {
16
   public:
16
   public:
17
     BoundingBox(glm::vec3 min, glm::vec3 max) : a(min), b(max) { }
17
     BoundingBox(glm::vec3 min, glm::vec3 max) : a(min), b(max) { }
18
-    bool inBox(float x, float y, float z) { return ((y > a.y) && (y < b.y) && inBoxPlane(x, z)); }
19
-    bool inBoxPlane(float x, float z) { return ((x > a.x) && (x < b.x) && (z > a.z) && (z < b.z)); }
18
+
19
+    bool inBox(glm::vec3 p) {
20
+        return ((p.y >= a.y) && (p.y <= b.y) && inBoxPlane(p));
21
+    }
22
+
23
+    bool inBoxPlane(glm::vec3 p) {
24
+        return ((p.x >= a.x) && (p.x <= b.x) && (p.z >= a.z) && (p.z <= b.z));
25
+    }
26
+
27
+    glm::vec3 getVertexP(glm::vec3 normal) {
28
+        glm::vec3 p = a;
29
+        if (normal.x >= 0.0f)
30
+            p.x = b.x;
31
+        if (normal.y >= 0.0f)
32
+            p.y = b.y;
33
+        if (normal.z >= 0.0f)
34
+            p.z = b.z;
35
+        return p;
36
+    }
20
 
37
 
21
   private:
38
   private:
22
     glm::vec3 a, b;
39
     glm::vec3 a, b;
38
 
55
 
39
 // --------------------------------------
56
 // --------------------------------------
40
 
57
 
58
+class Portal {
59
+  public:
60
+    Portal(int adj, glm::vec3 n, glm::vec3 v1, glm::vec3 v2, glm::vec3 v3,
61
+           glm::vec3 v4) : adjoiningRoom(adj), normal(n) {
62
+        vert[0] = v1; vert[1] = v2;
63
+        vert[2] = v3; vert[3] = v4;
64
+    }
65
+    int getAdjoiningRoom() { return adjoiningRoom; }
66
+    glm::vec3 getNormal() { return normal; }
67
+    glm::vec3 getVertex(int i) { assert((i >= 0) && (i < 4)); return vert[i]; }
68
+
69
+  private:
70
+    int adjoiningRoom;
71
+    glm::vec3 normal;
72
+    glm::vec3 vert[4];
73
+};
74
+
75
+// --------------------------------------
76
+
41
 class Light {
77
 class Light {
42
   public:
78
   public:
43
     /*!
79
     /*!
67
 
103
 
68
 // --------------------------------------
104
 // --------------------------------------
69
 
105
 
70
-class Portal {
71
-  public:
72
-    Portal(glm::vec3 vert[4], float norm[3], int adj);
73
-
74
-    void getVertices(float vert[4][3]);
75
-    int getAdjoiningRoom();
76
-
77
-  private:
78
-    float vertices[4][3];
79
-    float normal[3];
80
-    int adjoiningRoom;
81
-};
82
-
83
-// --------------------------------------
84
-
85
 class Sector {
106
 class Sector {
86
   public:
107
   public:
87
     Sector(float f, float c, bool w) : floor(f), ceiling(c), wall(w) { }
108
     Sector(float f, float c, bool w) : floor(f), ceiling(c), wall(w) { }

+ 0
- 23
include/World.h View File

59
     unsigned long sizeMesh();
59
     unsigned long sizeMesh();
60
     Mesh& getMesh(unsigned long index);
60
     Mesh& getMesh(unsigned long index);
61
 
61
 
62
-    /*!
63
-     * \brief Find room a location is in.
64
-     *
65
-     * If it fails to be in a room it gives closest overlapping room.
66
-     * \param index Guessed room index
67
-     * \param x X coordinate
68
-     * \param y Y coordinate
69
-     * \param z Z coordinate
70
-     * \returns correct room index or -1 for unknown
71
-     */
72
-    long getRoomByLocation(long index, float x, float y, float z);
73
-
74
-    /*!
75
-     * \brief Find room a location is in.
76
-     *
77
-     * If it fails to be in a room it gives closest overlapping room.
78
-     * \param x X coordinate
79
-     * \param y Y coordinate
80
-     * \param z Z coordinate
81
-     * \returns correct room index or -1 for unknown
82
-     */
83
-    long getRoomByLocation(float x, float y, float z);
84
-
85
   private:
62
   private:
86
     std::vector<std::unique_ptr<Room>> mRooms;
63
     std::vector<std::unique_ptr<Room>> mRooms;
87
     std::vector<std::unique_ptr<SpriteSequence>> mSprites;
64
     std::vector<std::unique_ptr<SpriteSequence>> mSprites;

+ 234
- 35
src/Camera.cpp View File

9
 #include <glm/gtc/matrix_transform.hpp>
9
 #include <glm/gtc/matrix_transform.hpp>
10
 
10
 
11
 #include "global.h"
11
 #include "global.h"
12
+#include "system/Window.h"
12
 #include "Camera.h"
13
 #include "Camera.h"
13
 
14
 
15
+#define NEAR 0
16
+#define FAR 1
17
+#define TOP 2
18
+#define BOTTOM 3
19
+#define LEFT 4
20
+#define RIGHT 5
21
+
22
+#define NTL 0
23
+#define NBL 1
24
+#define NBR 2
25
+#define NTR 3
26
+#define FTL 4
27
+#define FBL 5
28
+#define FBR 6
29
+#define FTR 7
30
+
31
+struct Plane {
32
+    glm::vec3 normal, pos;
33
+    float d;
34
+
35
+    Plane(glm::vec3 n = glm::vec3(0.0f, 0.0f, 0.0f),
36
+          glm::vec3 p = glm::vec3(0.0f, 0.0f, 0.0f)) {
37
+        set(n, p);
38
+    }
39
+
40
+    void set(glm::vec3 a, glm::vec3 b, glm::vec3 c) {
41
+        glm::vec3 aux1 = a - b;
42
+        glm::vec3 aux2 = c - b;
43
+        normal = glm::normalize(glm::cross(aux2, aux1));
44
+        pos = b;
45
+        d = -glm::dot(normal, pos);
46
+    }
47
+
48
+    void set(glm::vec3 n, glm::vec3 p) {
49
+        normal = n;
50
+        pos = p;
51
+        d = -glm::dot(normal, pos);
52
+    }
53
+
54
+    float distance(glm::vec3 p) {
55
+        return d + glm::dot(normal, p);
56
+    }
57
+};
58
+
59
+// ----------------------------------------------------------------------------
60
+
61
+const static float fov = 45.0f;
62
+const static float nearDist = 0.1f;
63
+const static float farDist = 75000.0f;
64
+const static float freeCameraStep = 256.0f;
65
+
14
 glm::vec3 Camera::pos(0.0f, 0.0f, 0.0f);
66
 glm::vec3 Camera::pos(0.0f, 0.0f, 0.0f);
15
-float Camera::thetaX = 0.0f;
16
-float Camera::thetaY = 0.0f;
67
+glm::vec2 Camera::rot(0.0f, 0.0f);
68
+glm::vec3 Camera::lastPos(1.0f, 0.0f, 0.0f);
69
+glm::vec2 Camera::lastRot(1.0f, 0.0f);
70
+glm::vec2 Camera::lastSize(0.0f, 0.0f);
71
+glm::mat4 Camera::projection(1.0f);
72
+glm::mat4 Camera::view(1.0f);
17
 float Camera::rotationDeltaX = 0.75f;
73
 float Camera::rotationDeltaX = 0.75f;
18
 float Camera::rotationDeltaY = 0.75f;
74
 float Camera::rotationDeltaY = 0.75f;
75
+bool Camera::updateViewFrustum = true;
76
+static Plane planes[6];
77
+
78
+static glm::vec3 frustumColors[6] = {
79
+    glm::vec3(1.0f, 0.0f, 0.0f),
80
+    glm::vec3(0.0f, 1.0f, 0.0f),
81
+    glm::vec3(0.0f, 0.0f, 1.0f),
82
+    glm::vec3(1.0f, 1.0f, 0.0f),
83
+    glm::vec3(0.0f, 1.0f, 1.0f),
84
+    glm::vec3(1.0f, 0.0f, 1.0f)
85
+};
86
+static glm::vec3 frustumVertices[8];
19
 
87
 
20
 void Camera::reset() {
88
 void Camera::reset() {
21
     pos = glm::vec3(0.0f, 0.0f, 0.0f);
89
     pos = glm::vec3(0.0f, 0.0f, 0.0f);
22
-    thetaX = 0.0f;
23
-    thetaY = 0.0f;
90
+    rot = glm::vec2(0.0f, 0.0f);
91
+    lastPos = glm::vec3(1.0f, 0.0f, 0.0f);
92
+    lastRot = glm::vec2(1.0f, 0.0f);
93
+    lastSize = glm::vec2(0.0f, 0.0f);
94
+    projection = glm::mat4(1.0f);
95
+    view = glm::mat4(1.0f);
24
 }
96
 }
25
 
97
 
26
 void Camera::handleAction(ActionEvents action, bool isFinished) {
98
 void Camera::handleAction(ActionEvents action, bool isFinished) {
27
     if (isFinished)
99
     if (isFinished)
28
         return;
100
         return;
29
 
101
 
30
-    const static float step = 256.0f;
31
-
32
     glm::vec3 dir(
102
     glm::vec3 dir(
33
-        glm::cos(thetaY) * glm::sin(thetaX),
34
-        glm::sin(thetaY),
35
-        glm::cos(thetaY) * glm::cos(thetaX)
103
+        glm::cos(rot.y) * glm::sin(rot.x),
104
+        glm::sin(rot.y),
105
+        glm::cos(rot.y) * glm::cos(rot.x)
36
     );
106
     );
37
     glm::vec3 right(
107
     glm::vec3 right(
38
-        glm::sin(thetaX - glm::pi<float>() / 2.0f),
108
+        glm::sin(rot.x - glm::pi<float>() / 2.0f),
39
         0.0f,
109
         0.0f,
40
-        glm::cos(thetaX - glm::pi<float>() / 2.0f)
110
+        glm::cos(rot.x - glm::pi<float>() / 2.0f)
41
     );
111
     );
42
-    glm::vec3 up = glm::cross(right, dir);
112
+    glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
43
 
113
 
44
     if (action == forwardAction) {
114
     if (action == forwardAction) {
45
-        pos += dir * step;
115
+        pos += dir * freeCameraStep;
46
     } else if (action == backwardAction) {
116
     } else if (action == backwardAction) {
47
-        pos -= dir * step;
117
+        pos -= dir * freeCameraStep;
48
     } else if (action == leftAction) {
118
     } else if (action == leftAction) {
49
-        pos += right * step;
119
+        pos += right * freeCameraStep;
50
     } else if (action == rightAction) {
120
     } else if (action == rightAction) {
51
-        pos -= right * step;
121
+        pos -= right * freeCameraStep;
52
     } else if (action == jumpAction) {
122
     } else if (action == jumpAction) {
53
-        pos += up * step;
123
+        pos += up * freeCameraStep;
54
     } else if (action == crouchAction) {
124
     } else if (action == crouchAction) {
55
-        pos -= up * step;
125
+        pos -= up * freeCameraStep;
56
     } else if (action == useAction) {
126
     } else if (action == useAction) {
57
     } else if (action == holsterAction) {
127
     } else if (action == holsterAction) {
58
     } else if (action == walkAction) {
128
     } else if (action == walkAction) {
61
 
131
 
62
 void Camera::handleMouseMotion(int x, int y) {
132
 void Camera::handleMouseMotion(int x, int y) {
63
     while (x > 0) {
133
     while (x > 0) {
64
-        thetaX += rotationDeltaX;
134
+        rot.x += rotationDeltaX;
65
         x--;
135
         x--;
66
     }
136
     }
67
     while (x < 0) {
137
     while (x < 0) {
68
-        thetaX -= rotationDeltaX;
138
+        rot.x -= rotationDeltaX;
69
         x++;
139
         x++;
70
     }
140
     }
71
     while (y > 0) {
141
     while (y > 0) {
72
-        if (thetaY > -(glm::pi<float>() / 2.0f)) {
73
-            thetaY -= rotationDeltaY;
142
+        if (rot.y > -(glm::pi<float>() / 2.0f)) {
143
+            rot.y -= rotationDeltaY;
74
         }
144
         }
75
         y--;
145
         y--;
76
     }
146
     }
77
     while (y < 0) {
147
     while (y < 0) {
78
-        if (thetaY < (glm::pi<float>() / 2.0f)) {
79
-            thetaY += rotationDeltaY;
148
+        if (rot.y < (glm::pi<float>() / 2.0f)) {
149
+            rot.y += rotationDeltaY;
80
         }
150
         }
81
         y++;
151
         y++;
82
     }
152
     }
83
 
153
 
84
-    while (thetaX > (glm::pi<float>() * 2.0f))
85
-        thetaX -= glm::pi<float>() * 2.0f;
154
+    while (rot.x > (glm::pi<float>() * 2.0f))
155
+        rot.x -= glm::pi<float>() * 2.0f;
86
 
156
 
87
-    while (thetaX < -(glm::pi<float>() * 2.0f))
88
-        thetaX += glm::pi<float>() * 2.0f;
157
+    while (rot.x < -(glm::pi<float>() * 2.0f))
158
+        rot.x += glm::pi<float>() * 2.0f;
89
 }
159
 }
90
 
160
 
91
-glm::mat4 Camera::getViewMatrix() {
161
+bool Camera::update() {
162
+    glm::vec2 size(getWindow().getWidth(), getWindow().getHeight());
163
+
164
+    if ((lastPos == pos) && (lastRot == rot) && (lastSize == size))
165
+        return false;
166
+
167
+    if (lastSize != size) {
168
+        projection = glm::perspective(fov, size.x / size.y, nearDist, farDist);
169
+        lastSize = size;
170
+    }
171
+
92
     glm::vec3 dir(
172
     glm::vec3 dir(
93
-        glm::cos(thetaY) * glm::sin(thetaX),
94
-        glm::sin(thetaY),
95
-        glm::cos(thetaY) * glm::cos(thetaX)
173
+        glm::cos(rot.y) * glm::sin(rot.x),
174
+        glm::sin(rot.y),
175
+        glm::cos(rot.y) * glm::cos(rot.x)
96
     );
176
     );
177
+
97
     glm::vec3 right(
178
     glm::vec3 right(
98
-        glm::sin(thetaX - glm::pi<float>() / 2.0f),
179
+        glm::sin(rot.x - glm::pi<float>() / 2.0f),
99
         0.0f,
180
         0.0f,
100
-        glm::cos(thetaX - glm::pi<float>() / 2.0f)
181
+        glm::cos(rot.x - glm::pi<float>() / 2.0f)
101
     );
182
     );
183
+
102
     glm::vec3 up = glm::cross(right, dir);
184
     glm::vec3 up = glm::cross(right, dir);
103
-    return glm::lookAt(pos, pos + dir, up);
185
+    view = glm::lookAt(pos, pos + dir, up);
186
+
187
+    if (!updateViewFrustum)
188
+        return false;
189
+
190
+    dir = glm::normalize(dir);
191
+    right = glm::normalize(right);
192
+    up = glm::normalize(up);
193
+
194
+    static float tang = glm::tan(glm::radians(fov * 0.5f));
195
+    static float nh = nearDist * tang;
196
+    float nw = nh * (size.x / size.y);
197
+    static float fh = farDist * tang;
198
+    float fw = fh * (size.x / size.y);
199
+
200
+    glm::vec3 nearCenter = pos + dir * nearDist;
201
+    glm::vec3 farCenter = pos + dir * farDist;
202
+
203
+    frustumVertices[NTL] = nearCenter + up * nh - right * nw;
204
+    frustumVertices[NTR] = nearCenter + up * nh + right * nw;
205
+    frustumVertices[NBL] = nearCenter - up * nh - right * nw;
206
+    frustumVertices[NBR] = nearCenter - up * nh + right * nw;
207
+    frustumVertices[FTL] = farCenter + up * fh - right * fw;
208
+    frustumVertices[FTR] = farCenter + up * fh + right * fw;
209
+    frustumVertices[FBL] = farCenter - up * fh - right * fw;
210
+    frustumVertices[FBR] = farCenter - up * fh + right * fw;
211
+
212
+#if 1
213
+    planes[TOP].set(frustumVertices[NTR], frustumVertices[NTL], frustumVertices[FTL]);
214
+    planes[BOTTOM].set(frustumVertices[NBL], frustumVertices[NBR], frustumVertices[FBR]);
215
+    planes[LEFT].set(frustumVertices[NTL], frustumVertices[NBL], frustumVertices[FBL]);
216
+    planes[RIGHT].set(frustumVertices[NBR], frustumVertices[NTR], frustumVertices[FBR]);
217
+    planes[NEAR].set(frustumVertices[NTL], frustumVertices[NTR], frustumVertices[NBR]);
218
+    planes[FAR].set(frustumVertices[FTR], frustumVertices[FTL], frustumVertices[FBL]);
219
+#else
220
+    planes[NEAR].set(-dir, nearCenter);
221
+    planes[FAR].set(dir, farCenter);
222
+
223
+    glm::vec3 aux = glm::normalize((nearCenter + up * nh) - pos);
224
+    glm::vec3 normal = glm::cross(aux, right);
225
+    planes[TOP].set(normal, nearCenter + up * nh);
226
+
227
+    aux = glm::normalize((nearCenter - up * nh) - pos);
228
+    normal = glm::cross(right, aux);
229
+    planes[BOTTOM].set(normal, nearCenter - up * nh);
230
+
231
+    aux = glm::normalize((nearCenter - right * nw) - pos);
232
+    normal = glm::cross(aux, up);
233
+    planes[LEFT].set(normal, nearCenter - right * nw);
234
+
235
+    aux = glm::normalize((nearCenter + right * nw) - pos);
236
+    normal = glm::cross(up, aux);
237
+    planes[RIGHT].set(normal, nearCenter + right * nw);
238
+#endif
239
+
240
+    lastPos = pos;
241
+    lastRot = rot;
242
+    return true;
243
+}
244
+
245
+bool Camera::boxInFrustum(BoundingBox b) {
246
+    for (int i = 0; i < 6; i++) {
247
+        if (planes[i].distance(b.getVertexP(planes[i].normal)) < 0)
248
+            return false;
249
+    }
250
+    return true;
251
+}
252
+
253
+void Camera::displayFrustum(glm::mat4 MVP) {
254
+    std::vector<glm::vec3> verts;
255
+    std::vector<glm::vec3> cols;
256
+    std::vector<unsigned short> inds;
257
+
258
+    verts.push_back(frustumVertices[NTL]);
259
+    verts.push_back(frustumVertices[NTR]);
260
+    verts.push_back(frustumVertices[NBR]);
261
+    verts.push_back(frustumVertices[NBL]);
262
+
263
+    verts.push_back(frustumVertices[FTR]);
264
+    verts.push_back(frustumVertices[FTL]);
265
+    verts.push_back(frustumVertices[FBL]);
266
+    verts.push_back(frustumVertices[FBR]);
267
+
268
+    verts.push_back(frustumVertices[NBL]);
269
+    verts.push_back(frustumVertices[NBR]);
270
+    verts.push_back(frustumVertices[FBR]);
271
+    verts.push_back(frustumVertices[FBL]);
272
+
273
+    verts.push_back(frustumVertices[NTR]);
274
+    verts.push_back(frustumVertices[NTL]);
275
+    verts.push_back(frustumVertices[FTL]);
276
+    verts.push_back(frustumVertices[FTR]);
277
+
278
+    verts.push_back(frustumVertices[NTL]);
279
+    verts.push_back(frustumVertices[NBL]);
280
+    verts.push_back(frustumVertices[FBL]);
281
+    verts.push_back(frustumVertices[FTL]);
282
+
283
+    verts.push_back(frustumVertices[NBR]);
284
+    verts.push_back(frustumVertices[NTR]);
285
+    verts.push_back(frustumVertices[FTR]);
286
+    verts.push_back(frustumVertices[FBR]);
287
+
288
+    for (int i = 0; i < 6; i++) {
289
+        cols.push_back(frustumColors[i]);
290
+        cols.push_back(frustumColors[i]);
291
+        cols.push_back(frustumColors[i]);
292
+        cols.push_back(frustumColors[i]);
293
+
294
+        inds.push_back(4 * i);
295
+        inds.push_back((4 * i) + 1);
296
+        inds.push_back((4 * i) + 2);
297
+        inds.push_back((4 * i) + 3);
298
+        inds.push_back((4 * i) + 2);
299
+        inds.push_back(4 * i);
300
+    }
301
+
302
+    Window::drawGL(verts, cols, inds, MVP);
104
 }
303
 }
105
 
304
 

+ 0
- 145
src/Entity.cpp View File

40
 }
40
 }
41
 
41
 
42
 void Entity::move(char movement) {
42
 void Entity::move(char movement) {
43
-    const float moved = 180.0f;
44
-    const float testd = 220.0f;
45
-    const float camHeight = 8.0f;
46
-    float x, y, z, pitch, h, floor, ceiling;
47
-    long roomNew, sector;
48
-    bool wall;
49
-    unsigned int roomFlags;
50
 
43
 
51
-    switch (moveType) {
52
-        case MoveTypeWalkNoSwim:
53
-        case MoveTypeWalk:
54
-            pitch = 0.0f; // in the future pitch could control jump up blocks here
55
-            break;
56
-
57
-        case MoveTypeNoClipping:
58
-        case MoveTypeFly:
59
-        case MoveTypeSwim:
60
-            pitch = angles[2];
61
-            break;
62
-    }
63
-
64
-    switch (movement) {
65
-        case 'f':
66
-            x = pos[0] + (testd * sinf(angles[1]));
67
-            y = pos[1] + (testd * sinf(pitch));
68
-            z = pos[2] + (testd * cosf(angles[1]));
69
-            break;
70
-        case 'b':
71
-            x = pos[0] - (testd * sinf(angles[1]));
72
-            y = pos[1] - (testd * sinf(pitch));
73
-            z = pos[2] - (testd * cosf(angles[1]));
74
-            break;
75
-        case 'l':
76
-            x = pos[0] - (testd * sinf(angles[1] + 90.0f));
77
-            y = pos[1];
78
-            z = pos[2] - (testd * cosf(angles[1] + 90.0f));
79
-            break;
80
-        case 'r':
81
-            x = pos[0] + (testd * sinf(angles[1] + 90.0f));
82
-            y = pos[1];
83
-            z = pos[2] + (testd * cosf(angles[1] + 90.0f));
84
-            break;
85
-        default:
86
-            return;
87
-    }
88
-
89
-    roomNew = getWorld().getRoomByLocation(room, x, y, z);
90
-
91
-    if (roomNew == -1) { // Will we hit a portal?
92
-        roomNew = getWorld().getRoom(room).getAdjoiningRoom(pos[0], pos[1], pos[2],
93
-                  x, y, z);
94
-
95
-        if (roomNew > -1)
96
-            getLog() << "Crossing from room " << room << " to " << roomNew << Log::endl;
97
-        else
98
-            //! \fixme mRooms, sectors, ... are now std::vector, but often upper bound checks are missing
99
-            return;
100
-    }
101
-
102
-    roomFlags = getWorld().getRoom(roomNew).getFlags();
103
-    sector = getWorld().getRoom(roomNew).getSector(x, z, &floor, &ceiling);
104
-    wall = getWorld().getRoom(roomNew).isWall(sector);
105
-
106
-    // If you're underwater you may want to swim  =)
107
-    // ...if you're worldMoveType_walkNoSwim, you better hope it's shallow
108
-    if ((roomFlags & RoomFlagUnderWater) && (moveType == MoveTypeWalk))
109
-        moveType = MoveTypeSwim;
110
-
111
-    // Don't swim on land
112
-    if (!(roomFlags & RoomFlagUnderWater) && (moveType == MoveTypeSwim))
113
-        moveType = MoveTypeWalk;
114
-
115
-    // Mongoose 2002.09.02, Add check for room -> room transition
116
-    // (Only allow by movement between rooms by using portals)
117
-    if (((moveType == MoveTypeNoClipping) ||
118
-         (moveType == MoveTypeFly) ||
119
-         (moveType == MoveTypeSwim)) ||
120
-        ((roomNew > -1) && (!wall))) {
121
-        room = roomNew;
122
-
123
-        switch (movement) {
124
-            case 'f':
125
-                x = pos[0] + (moved * sinf(angles[1]));
126
-                y = pos[1] + (moved * sinf(pitch));
127
-                z = pos[2] + (moved * cosf(angles[1]));
128
-                break;
129
-            case 'b':
130
-                x = pos[0] - (moved * sinf(angles[1]));
131
-                y = pos[1] - (moved * sinf(pitch));
132
-                z = pos[2] - (moved * cosf(angles[1]));
133
-                break;
134
-            case 'l':
135
-                x = pos[0] - (moved * sinf(angles[1] + 90.0f));
136
-                z = pos[2] - (moved * cosf(angles[1] + 90.0f));
137
-                break;
138
-            case 'r':
139
-                x = pos[0] + (moved * sinf(angles[1] + 90.0f));
140
-                z = pos[2] + (moved * cosf(angles[1] + 90.0f));
141
-                break;
142
-        }
143
-
144
-        /*! \fixme Test for vector (move vector) / plane (portal) collision here
145
-         * to see if we need to switch rooms... man...
146
-         */
147
-
148
-        h = y;
149
-        getWorld().getRoom(room).getHeightAtPosition(x, &h, z);
150
-
151
-        switch (moveType) {
152
-            case MoveTypeFly:
153
-            case MoveTypeSwim:
154
-                // Don't fall out of world, avoid a movement that does
155
-                if (h > y - camHeight) {
156
-                    pos[0] = x;
157
-                    pos[1] = y;
158
-                    pos[2] = z;
159
-                }
160
-                break;
161
-
162
-            case MoveTypeWalk:
163
-            case MoveTypeWalkNoSwim:
164
-                y = pos[1];  // Override vector movement walking ( er, not pretty )
165
-
166
-                // Now fake gravity
167
-                // Mongoose 2002.08.14, Remember TR is upside down ( you fall 'up' )
168
-
169
-                //ddist = h - pos[1];
170
-
171
-                // This is to force false gravity, by making camera stay on ground
172
-                pos[1] = h; //roomFloor->bbox_min[1];
173
-
174
-                // Check for camera below terrian and correct
175
-                if (pos[1] < h - camHeight)
176
-                    pos[1] = h - camHeight;
177
-
178
-                pos[0] = x;
179
-                pos[2] = z;
180
-                break;
181
-
182
-            case MoveTypeNoClipping:
183
-                pos[0] = x;
184
-                pos[1] = y;
185
-                pos[2] = z;
186
-                break;
187
-        }
188
-    }
189
 }
44
 }
190
 
45
 
191
 void Entity::print() {
46
 void Entity::print() {

+ 3
- 7
src/Game.cpp View File

52
         Font::drawText(10, getWindow().getHeight() - 25, 0.6f, BLUE, s.str());
52
         Font::drawText(10, getWindow().getHeight() - 25, 0.6f, BLUE, s.str());
53
 
53
 
54
         s.str("");
54
         s.str("");
55
-        s << "X: " << Camera::getPosition().x << " (" << Camera::getRadianPitch() << ")";
55
+        s << "X: " << Camera::getPosition().x << " (" << Camera::getRotation().x << ")";
56
         Font::drawText(10, getWindow().getHeight() - 70, 0.6f, BLUE, s.str());
56
         Font::drawText(10, getWindow().getHeight() - 70, 0.6f, BLUE, s.str());
57
 
57
 
58
         s.str("");
58
         s.str("");
59
-        s << "Y: " << Camera::getPosition().y << " (" << Camera::getRadianYaw() << ")";
59
+        s << "Y: " << Camera::getPosition().y << " (" << Camera::getRotation().y << ")";
60
         Font::drawText(10, getWindow().getHeight() - 55, 0.6f, BLUE, s.str());
60
         Font::drawText(10, getWindow().getHeight() - 55, 0.6f, BLUE, s.str());
61
 
61
 
62
         s.str("");
62
         s.str("");
71
     Render::setMode(RenderMode::LoadScreen);
71
     Render::setMode(RenderMode::LoadScreen);
72
 
72
 
73
     Camera::reset();
73
     Camera::reset();
74
+    Render::clearRoomList();
74
     SoundManager::clear();
75
     SoundManager::clear();
75
     getTextureManager().clear();
76
     getTextureManager().clear();
76
     getWorld().destroy();
77
     getWorld().destroy();
134
         return;
135
         return;
135
 
136
 
136
     Camera::handleMouseMotion(xrel, yrel);
137
     Camera::handleMouseMotion(xrel, yrel);
137
-
138
-    /* TODO
139
-    float angles[3] = { 0.0f, getCamera().getRadianYaw(), getCamera().getRadianPitch() };
140
-    getLara().setAngles(angles);
141
-    */
142
 }
138
 }
143
 
139
 
144
 Entity& Game::getLara() {
140
 Entity& Game::getLara() {

+ 57
- 21
src/Render.cpp View File

17
 #include "global.h"
17
 #include "global.h"
18
 #include "Camera.h"
18
 #include "Camera.h"
19
 #include "Game.h"
19
 #include "Game.h"
20
-#include "Render.h"
21
 #include "utils/strings.h"
20
 #include "utils/strings.h"
22
 #include "utils/tga.h"
21
 #include "utils/tga.h"
23
 #include "World.h"
22
 #include "World.h"
24
 #include "system/Window.h"
23
 #include "system/Window.h"
24
+#include "Render.h"
25
 
25
 
26
 RenderMode Render::mode = RenderMode::Disabled;
26
 RenderMode Render::mode = RenderMode::Disabled;
27
+std::vector<Room*> Render::roomList;
28
+bool Render::displayViewFrustum = false;
27
 
29
 
28
 RenderMode Render::getMode() {
30
 RenderMode Render::getMode() {
29
     return mode;
31
     return mode;
38
         case RenderMode::Wireframe:
40
         case RenderMode::Wireframe:
39
             //glClearColor(PURPLE[0] / 256.0f, PURPLE[1] / 256.0f,
41
             //glClearColor(PURPLE[0] / 256.0f, PURPLE[1] / 256.0f,
40
             //             PURPLE[2] / 256.0f, PURPLE[3] / 256.0f);
42
             //             PURPLE[2] / 256.0f, PURPLE[3] / 256.0f);
41
-            //glDisable(GL_TEXTURE_2D);
42
             break;
43
             break;
43
         default:
44
         default:
44
             //glClearColor(BLACK[0] / 256.0f, BLACK[1] / 256.0f,
45
             //glClearColor(BLACK[0] / 256.0f, BLACK[1] / 256.0f,
45
             //             BLACK[2] / 256.0f, BLACK[3] / 256.0f);
46
             //             BLACK[2] / 256.0f, BLACK[3] / 256.0f);
46
-            //glEnable(GL_TEXTURE_2D);
47
             break;
47
             break;
48
     }
48
     }
49
 }
49
 }
66
         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
66
         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
67
     }
67
     }
68
 
68
 
69
+    if (Camera::update()) {
70
+        clearRoomList();
71
+        buildRoomList(-2); // TODO cache room
72
+        std::cout << "Rendering " << roomList.size() << "/"
73
+                  << getWorld().sizeRoom() << " rooms..." << std::endl;
74
+    }
75
+
76
+    glm::mat4 projection = Camera::getProjectionMatrix();
69
     glm::mat4 view = Camera::getViewMatrix();
77
     glm::mat4 view = Camera::getViewMatrix();
70
 
78
 
71
-    static unsigned int w = getWindow().getWidth();
72
-    static unsigned int h = getWindow().getHeight();
73
-    static glm::mat4 projection = glm::perspective(45.0f, // Field of View
74
-                                  (float)getWindow().getWidth()
75
-                                  / (float)getWindow().getHeight(),
76
-                                  0.1f, // Min Distance
77
-                                  100000.0f); // Max Distance
78
-
79
-    if ((w != getWindow().getWidth()) || (h != getWindow().getHeight())) {
80
-        w = getWindow().getWidth();
81
-        h = getWindow().getHeight();
82
-        glm::mat4 projection = glm::perspective(45.0f, // Field of View
83
-                                                (float)getWindow().getWidth() / (float)getWindow().getHeight(),
84
-                                                0.1f, // Min Distance
85
-                                                100000.0f); // Max Distance
79
+    for (auto r : roomList) {
80
+        r->display(view, projection);
86
     }
81
     }
87
 
82
 
88
-    // Just draw all rooms, as a test
89
-    for (int i = 0; i < getWorld().sizeRoom(); i++)
90
-        getWorld().getRoom(i).display(view, projection);
83
+    if (displayViewFrustum)
84
+        Camera::displayFrustum(projection * view);
91
 
85
 
92
     if (mode == RenderMode::Wireframe) {
86
     if (mode == RenderMode::Wireframe) {
93
         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
87
         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
94
     }
88
     }
95
 }
89
 }
96
 
90
 
91
+void Render::clearRoomList() {
92
+    roomList.clear();
93
+}
94
+
95
+void Render::buildRoomList(int room) {
96
+    if (room < -1) {
97
+        // Check if the camera currently is in a room...
98
+        for (int i = 0; i < getWorld().sizeRoom(); i++) {
99
+            if (getWorld().getRoom(i).getBoundingBox().inBox(Camera::getPosition())) {
100
+                buildRoomList(i);
101
+                return;
102
+            }
103
+        }
104
+        std::cout << "Camera not found!" << std::endl;
105
+        buildRoomList(-1);
106
+    } else if (room == -1) {
107
+        // Check visibility for all rooms!
108
+        for (int i = 0; i < getWorld().sizeRoom(); i++) {
109
+            if (Camera::boxInFrustum(getWorld().getRoom(i).getBoundingBox())) {
110
+                roomList.push_back(&getWorld().getRoom(i));
111
+            }
112
+        }
113
+    } else {
114
+        // Check visibility of room and connected rooms, recursively?
115
+        if (Camera::boxInFrustum(getWorld().getRoom(room).getBoundingBox())) {
116
+            roomList.push_back(&getWorld().getRoom(room));
117
+            for (int i = 0; i < getWorld().getRoom(room).sizePortals(); i++) {
118
+                int r = getWorld().getRoom(room).getPortal(i).getAdjoiningRoom();
119
+                bool found = false;
120
+                for (int n = 0; n < roomList.size(); n++) {
121
+                    if (roomList.at(n) == &getWorld().getRoom(r)) {
122
+                        found = true;
123
+                        break;
124
+                    }
125
+                }
126
+                if (!found)
127
+                    buildRoomList(r);
128
+            }
129
+        }
130
+    }
131
+}
132
+
97
 void Render::screenShot(const char* filenameBase) {
133
 void Render::screenShot(const char* filenameBase) {
98
     /*
134
     /*
99
     int sz = getWindow().getWidth() * getWindow().getHeight();
135
     int sz = getWindow().getWidth() * getWindow().getHeight();

+ 6
- 10
src/Room.cpp View File

64
 
64
 
65
 int Room::getAdjoiningRoom(float x, float y, float z,
65
 int Room::getAdjoiningRoom(float x, float y, float z,
66
                            float x2, float y2, float z2) {
66
                            float x2, float y2, float z2) {
67
-    float vertices[4][3];
68
     glm::vec3 orig(x, y, z);
67
     glm::vec3 orig(x, y, z);
69
     glm::vec3 dir(x2 - x, y2 - y, z2 - z);
68
     glm::vec3 dir(x2 - x, y2 - y, z2 - z);
70
     glm::vec3 intersect;
69
     glm::vec3 intersect;
71
-    glm::vec3 verts[4];
72
 
70
 
73
     for (unsigned long i = 0; i < portals.size(); i++) {
71
     for (unsigned long i = 0; i < portals.size(); i++) {
74
-        portals.at(i)->getVertices(vertices);
75
-        verts[0] = glm::vec3(vertices[0][0], vertices[0][1], vertices[0][2]);
76
-        verts[1] = glm::vec3(vertices[1][0], vertices[1][1], vertices[1][2]);
77
-        verts[2] = glm::vec3(vertices[2][0], vertices[2][1], vertices[2][2]);
78
-        verts[3] = glm::vec3(vertices[3][0], vertices[3][1], vertices[3][2]);
79
-
80
-        if ((glm::intersectLineTriangle(orig, dir, verts[0], verts[1], verts[2], intersect))
81
-            || (glm::intersectLineTriangle(orig, dir, verts[0], verts[3], verts[1], intersect)))
72
+        if ((glm::intersectLineTriangle(orig, dir, portals.at(i)->getVertex(0),
73
+                                        portals.at(i)->getVertex(1),
74
+                                        portals.at(i)->getVertex(2), intersect))
75
+            || (glm::intersectLineTriangle(orig, dir, portals.at(i)->getVertex(0),
76
+                                           portals.at(i)->getVertex(3),
77
+                                           portals.at(i)->getVertex(1), intersect)))
82
             return portals.at(i)->getAdjoiningRoom();
78
             return portals.at(i)->getAdjoiningRoom();
83
     }
79
     }
84
 
80
 

+ 0
- 28
src/RoomData.cpp View File

63
 
63
 
64
 // ----------------------------------------------------------------------------
64
 // ----------------------------------------------------------------------------
65
 
65
 
66
-Portal::Portal(glm::vec3 vert[4], float norm[3], int adj) {
67
-    for (unsigned int i = 0; i < 4; i++) {
68
-        for (unsigned int j = 0; j < 3; j++) {
69
-            vertices[i][j] = vert[i][j];
70
-        }
71
-
72
-        if (i < 3) {
73
-            normal[i] = norm[i];
74
-        }
75
-    }
76
-
77
-    adjoiningRoom = adj;
78
-}
79
-
80
-void Portal::getVertices(float vert[4][3]) {
81
-    for (unsigned int i = 0; i < 4; i++) {
82
-        for (unsigned int j = 0; j < 3; j++) {
83
-            vert[i][j] = vertices[i][j];
84
-        }
85
-    }
86
-}
87
-
88
-int Portal::getAdjoiningRoom() {
89
-    return adjoiningRoom;
90
-}
91
-
92
-// ----------------------------------------------------------------------------
93
-
94
 float Sector::getFloor() {
66
 float Sector::getFloor() {
95
     return floor;
67
     return floor;
96
 }
68
 }

+ 11
- 0
src/UI.cpp View File

9
 #include <cstring>
9
 #include <cstring>
10
 
10
 
11
 #include "global.h"
11
 #include "global.h"
12
+#include "Camera.h"
12
 #include "Console.h"
13
 #include "Console.h"
13
 #include "Game.h"
14
 #include "Game.h"
14
 #include "Log.h"
15
 #include "Log.h"
233
                 getWindow().setFullscreen(fullscreen);
234
                 getWindow().setFullscreen(fullscreen);
234
             }
235
             }
235
 
236
 
237
+            bool updateViewFrustum = Camera::getUpdateViewFrustum();
238
+            if (ImGui::Checkbox("Update Frustum##runtime", &updateViewFrustum)) {
239
+                Camera::setUpdateViewFrustum(updateViewFrustum);
240
+            }
241
+            ImGui::SameLine();
242
+            bool displayViewFrustum = Render::getDisplayViewFrustum();
243
+            if (ImGui::Checkbox("Show Frustum##runtime", &displayViewFrustum)) {
244
+                Render::setDisplayViewFrustum(displayViewFrustum);
245
+            }
246
+
236
             float vol = Sound::getVolume();
247
             float vol = Sound::getVolume();
237
             if (ImGui::InputFloat("Volume##runtime", &vol, 0.0f, 0.0f, 3,
248
             if (ImGui::InputFloat("Volume##runtime", &vol, 0.0f, 0.0f, 3,
238
                                   ImGuiInputTextFlags_EnterReturnsTrue)) {
249
                                   ImGuiInputTextFlags_EnterReturnsTrue)) {

+ 9
- 38
src/World.cpp View File

15
     destroy();
15
     destroy();
16
 }
16
 }
17
 
17
 
18
+void World::destroy() {
19
+    mRooms.clear();
20
+    mSprites.clear();
21
+    mEntities.clear();
22
+    mModels.clear();
23
+    mStaticMeshes.clear();
24
+    mMeshes.clear();
25
+}
26
+
18
 void World::addRoom(Room* room) {
27
 void World::addRoom(Room* room) {
19
     mRooms.emplace_back(std::unique_ptr<Room>(room));
28
     mRooms.emplace_back(std::unique_ptr<Room>(room));
20
 }
29
 }
93
     return *mMeshes.at(index);
102
     return *mMeshes.at(index);
94
 }
103
 }
95
 
104
 
96
-
97
-long World::getRoomByLocation(long index, float x, float y, float z) {
98
-    assert(index >= 0);
99
-    assert(index < (long)mRooms.size());
100
-    Room& room = *mRooms.at(index);
101
-
102
-    if (room.getBoundingBox().inBox(x, y, z))
103
-        return index;
104
-    else
105
-        return getRoomByLocation(x, y, z);
106
-}
107
-
108
-
109
-long World::getRoomByLocation(float x, float y, float z) {
110
-    long hop = -1;
111
-
112
-    for (unsigned long i = 0; i < mRooms.size(); i++) {
113
-        if (mRooms.at(i)->getBoundingBox().inBoxPlane(x, z)) {
114
-            if (mRooms.at(i)->getBoundingBox().inBox(x, y, z))
115
-                return i;
116
-            else
117
-                hop = i; // This room is above or below current position
118
-        }
119
-    }
120
-
121
-    return hop;
122
-}
123
-
124
-
125
-void World::destroy() {
126
-    mRooms.clear();
127
-    mSprites.clear();
128
-    mEntities.clear();
129
-    mModels.clear();
130
-    mStaticMeshes.clear();
131
-    mMeshes.clear();
132
-}
133
-

+ 12
- 1
src/loader/LoaderTR2.cpp View File

273
         }
273
         }
274
 
274
 
275
         uint16_t numPortals = file.readU16();
275
         uint16_t numPortals = file.readU16();
276
+        std::vector<Portal*> portals;
276
         for (unsigned int p = 0; p < numPortals; p++) {
277
         for (unsigned int p = 0; p < numPortals; p++) {
277
             // Which room this portal leads to
278
             // Which room this portal leads to
278
             uint16_t adjoiningRoom = file.readU16();
279
             uint16_t adjoiningRoom = file.readU16();
299
             int16_t yCorner4 = file.read16();
300
             int16_t yCorner4 = file.read16();
300
             int16_t zCorner4 = file.read16();
301
             int16_t zCorner4 = file.read16();
301
 
302
 
302
-            // TODO store portals
303
+            //! \fixme TODO translate vertices by room offset!
304
+
305
+            portals.push_back(new Portal(adjoiningRoom,
306
+                                         glm::vec3(xNormal, yNormal, zNormal),
307
+                                         glm::vec3(xCorner1, yCorner1, zCorner1),
308
+                                         glm::vec3(xCorner2, yCorner2, zCorner2),
309
+                                         glm::vec3(xCorner3, yCorner3, zCorner3),
310
+                                         glm::vec3(xCorner4, yCorner4, zCorner4)));
303
         }
311
         }
304
 
312
 
305
         uint16_t numZSectors = file.readU16();
313
         uint16_t numZSectors = file.readU16();
387
         Room* room = new Room(pos, boundingbox, mesh, roomFlags, alternateRoom,
395
         Room* room = new Room(pos, boundingbox, mesh, roomFlags, alternateRoom,
388
                               numXSectors, numZSectors);
396
                               numXSectors, numZSectors);
389
 
397
 
398
+        for (auto p : portals)
399
+            room->addPortal(p);
400
+
390
         for (auto m : staticModels)
401
         for (auto m : staticModels)
391
             room->addModel(m);
402
             room->addModel(m);
392
 
403
 

Loading…
Cancel
Save