-
Notifications
You must be signed in to change notification settings - Fork 1
/
scene.cpp
208 lines (166 loc) · 5.31 KB
/
scene.cpp
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
/**
TIE-02201 Ohjelmointi 2: Perusteet, K2019
Assignment 12.4: Matopelin paluu
3D Snake game made with OpenGL ES 2.0.
See 'instructions.txt' for further information.
scene.cpp
Defines a class representing a 3D scene that stores
GameObjects, a level mesh and a camera.
@author Joona Perasto, 272725, [email protected]
*/
#include "scene.hh"
#include "renderable.hh"
#include "gameobject.hh"
#include "fooditem.hh"
#include "level.hh"
#include "snake.hh"
Scene::Scene(): camera_(nullptr), colliders_(nullptr)
{
loadResources();
}
void Scene::update(float deltaTime)
{
for (GameObject* object : gameObjects_)
object->update(deltaTime);
}
void Scene::render(QOpenGLFunctions* gl)
{
// Cant render without camera
if (camera_ == nullptr)
return;
// Sort game objects by shader in advance for efficiency
// Happens every frame so could be done more efficient, but this makes stuff a lot easier
renderMap_.clear();
for (Renderable* renderable : gameObjects_)
{
QOpenGLShaderProgram* program = renderable->getShaderProgram();
renderMap_[program].append(renderable);
}
// Add the level to render queue
renderMap_[level_->getShaderProgram()].append(level_);
QVector3D lightDir = QVector3D(0.7f, 0.7f, 0.7f).normalized();
// Loop through map sorted by shader programs
for (QOpenGLShaderProgram* program : renderMap_.keys())
{
// Set object's shader program in OpenGL
program->bind();
// Send ambient lighting value to shader program
program->setUniformValue("ambient", 0.7f);
for (Renderable* renderable : renderMap_[program])
{
// Calculate transformation matrices for object
QMatrix4x4 modelMatrix = renderable->getTransform()->getModelMatrix();
QMatrix4x4 mvpMatrix = camera_->computeMvpMatrix(modelMatrix);
QVector3D eyeLightDir = lightDir;
// Send matrices and light direction to the program
program->setUniformValue("mvpMatrix", mvpMatrix);
program->setUniformValue("modelMatrix", modelMatrix);
program->setUniformValue("eyeLightDir", eyeLightDir);
renderable->render(gl);
}
// Unbind the shader program from OpenGL
program->release();
}
}
void Scene::addGameObject(GameObject *gameObject)
{
gameObjects_.append(gameObject);
}
void Scene::removeGameObject(GameObject *object)
{
int objIndex = gameObjects_.indexOf(object);
if (objIndex != -1)
{
GameObject* obj = gameObjects_.at(objIndex);
gameObjects_.remove(objIndex);
delete obj;
}
}
void Scene::setCamera(Camera *camera)
{
camera_ = camera;
}
void Scene::setLevel(Level *level)
{
level_ = level;
}
bool Scene::isVectorInsideCollider(QVector3D vector)
{
// Convert to 2D Point
QPointF vectorPoint(
qreal(vector.x()),
qreal(vector.z())
);
for (QPolygonF collider : *colliders_)
if (collider.containsPoint(vectorPoint, Qt::FillRule::OddEvenFill))
return true;
return false;
}
void Scene::clearGameObjects()
{
for (GameObject* obj : gameObjects_)
delete obj;
gameObjects_.clear();
}
QVector<FoodItem*> Scene::getFoodItems() const
{
QVector<FoodItem*> items;
for (GameObject* obj : gameObjects_)
{
FoodItem* item = dynamic_cast<FoodItem*>(obj);
if (item != nullptr)
items.append(item);
}
return items;
}
PolyData* Scene::getColliders() const
{
return colliders_;
}
void Scene::addRandomFood()
{
FoodItem* food = nullptr;
int r = rand() % 21;
if (r <= 16)
food = new FoodItem(this, "apple");
else if (r <= 18)
food = new FoodItem(this, "burger");
else
food = new FoodItem(this, "odens");
// Make sure that the food doesn't get spawned inside a collider
bool insideCollider = true;
QVector3D foodPos;
while (insideCollider)
{
foodPos = QVector3D(
rand()%1000 / 1000.0f * 20.0f-10.0f,
0.0f,
rand()%1000 / 1000.0f * 20.0f-10.0f
);
insideCollider = isVectorInsideCollider(foodPos);
}
food->setPosition(foodPos);
addGameObject(food);
}
void Scene::loadResources()
{
// Create single instance for a resource manager
ResourceManager& resourceManager = ResourceManager::getInstance();
// Load necessary resources at the beginning instead of during runtime to prevent hiccups
resourceManager.createProgram("snake_program",
"snake_vertex.glsl",
"snake_fragment.glsl");
resourceManager.createProgram("food_program",
"basic_vertex.glsl",
"food_fragment.glsl");
resourceManager.createProgram("level_program",
"basic_vertex.glsl",
"level_fragment.glsl");
resourceManager.loadMesh("apple_mesh.obj");
resourceManager.loadMesh("burger_mesh.obj");
resourceManager.loadMesh("dens_mesh.obj");
resourceManager.loadMesh("level.obj");
resourceManager.loadTexture("solid_color_atlas.png");
resourceManager.loadTexture("odens_tex.png");
colliders_ = resourceManager.loadPolygons("poly_colliders.obj");
}