forked from ixchow/15-466-f17-base2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Scene.cpp
146 lines (125 loc) · 4.37 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
#include "Scene.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
glm::mat4 Scene::Transform::make_local_to_parent() const {
return glm::mat4( //translate
glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
glm::vec4(position, 1.0f)
)
* glm::mat4_cast(rotation) //rotate
* glm::mat4( //scale
glm::vec4(scale.x, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, scale.y, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, scale.z, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)
);
}
glm::mat4 Scene::Transform::make_parent_to_local() const {
glm::vec3 inv_scale;
inv_scale.x = (scale.x == 0.0f ? 0.0f : 1.0f / scale.x);
inv_scale.y = (scale.y == 0.0f ? 0.0f : 1.0f / scale.y);
inv_scale.z = (scale.z == 0.0f ? 0.0f : 1.0f / scale.z);
return glm::mat4( //un-scale
glm::vec4(inv_scale.x, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, inv_scale.y, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, inv_scale.z, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)
)
* glm::mat4_cast(glm::inverse(rotation)) //un-rotate
* glm::mat4( //un-translate
glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
glm::vec4(-position, 1.0f)
);
}
glm::mat4 Scene::Transform::make_local_to_world() const {
if (parent) {
return parent->make_local_to_world() * make_local_to_parent();
} else {
return make_local_to_parent();
}
}
glm::mat4 Scene::Transform::make_world_to_local() const {
if (parent) {
return make_parent_to_local() * parent->make_world_to_local();
} else {
return make_parent_to_local();
}
}
void Scene::Transform::DEBUG_assert_valid_pointers() const {
if (parent == nullptr) {
//if no parent, can't have siblings:
assert(prev_sibling == nullptr);
assert(next_sibling == nullptr);
} else {
//if have parent, last child if and only if no next sibling:
assert((next_sibling == nullptr) == (this == parent->last_child));
}
//check proper return pointers from neighbors:
assert(prev_sibling == nullptr || prev_sibling->next_sibling == this);
assert(next_sibling == nullptr || next_sibling->prev_sibling == this);
assert(last_child == nullptr || last_child->parent == this);
}
void Scene::Transform::set_parent(Transform *new_parent, Transform *before) {
DEBUG_assert_valid_pointers();
assert(before == nullptr || (new_parent != nullptr && before->parent == new_parent));
if (parent) {
//remove from existing parent:
if (prev_sibling) prev_sibling->next_sibling = next_sibling;
if (next_sibling) next_sibling->prev_sibling = prev_sibling;
else parent->last_child = prev_sibling;
next_sibling = prev_sibling = nullptr;
}
parent = new_parent;
if (parent) {
//add to new parent:
if (before) {
prev_sibling = before->prev_sibling;
next_sibling = before;
next_sibling->prev_sibling = this;
} else {
prev_sibling = parent->last_child;
parent->last_child = this;
}
if (prev_sibling) prev_sibling->next_sibling = this;
}
DEBUG_assert_valid_pointers();
}
//---------------------------
glm::mat4 Scene::Camera::make_projection() const {
return glm::infinitePerspective( fovy, aspect, near );
}
//---------------------------
void Scene::render() {
glm::mat4 world_to_camera = camera.transform.make_world_to_local();
glm::mat4 world_to_clip = camera.make_projection() * world_to_camera;
//Get world-space position of all lights:
for (auto const &light : lights) {
glm::mat4 mv = world_to_camera * light.transform.make_local_to_world();
(void)mv;
}
for (auto const &object : objects) {
glm::mat4 local_to_world = object.transform.make_local_to_world();
//compute modelview+projection (object space to clip space) matrix for this object:
glm::mat4 mvp = world_to_clip * local_to_world;
//compute modelview (object space to camera local space) matrix for this object:
glm::mat4 mv = world_to_camera * local_to_world;
//NOTE: inverse cancels out transpose unless there is scale involved
glm::mat3 itmv = glm::inverse(glm::transpose(glm::mat3(mv)));
//set up program uniforms:
glUseProgram(object.program);
if (object.program_mvp != -1U) {
glUniformMatrix4fv(object.program_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
}
if (object.program_itmv != -1U) {
glUniformMatrix3fv(object.program_itmv, 1, GL_FALSE, glm::value_ptr(itmv));
}
glBindVertexArray(object.vao);
//draw the object:
glDrawArrays(GL_TRIANGLES, object.start, object.count);
}
}