blob: 35a4101dd9c383e0a4d9a40e691c915852f817b5 [file] [log] [blame]
Tony Barbour2f18b292016-02-25 15:44:10 -07001/*
2 * Copyright (C) 2016 Google, Inc.
3 *
Jon Ashburn43b53e82016-04-19 11:30:31 -06004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Tony Barbour2f18b292016-02-25 15:44:10 -07007 *
Jon Ashburn43b53e82016-04-19 11:30:31 -06008 * http://www.apache.org/licenses/LICENSE-2.0
Tony Barbour2f18b292016-02-25 15:44:10 -07009 *
Jon Ashburn43b53e82016-04-19 11:30:31 -060010 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Tony Barbour2f18b292016-02-25 15:44:10 -070015 */
16
17#include <cassert>
18#include <cmath>
19#include <array>
20#include <glm/gtc/matrix_transform.hpp>
21#include "Simulation.h"
22
23namespace {
24
25class MeshPicker {
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -070026 public:
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -070027 MeshPicker()
28 : pattern_({{
29 Meshes::MESH_PYRAMID, Meshes::MESH_ICOSPHERE, Meshes::MESH_TEAPOT, Meshes::MESH_PYRAMID, Meshes::MESH_ICOSPHERE,
30 Meshes::MESH_PYRAMID, Meshes::MESH_PYRAMID, Meshes::MESH_PYRAMID, Meshes::MESH_PYRAMID, Meshes::MESH_PYRAMID,
31 }}),
32 cur_(-1) {}
Tony Barbour2f18b292016-02-25 15:44:10 -070033
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -070034 Meshes::Type pick() {
Tony Barbour2f18b292016-02-25 15:44:10 -070035 cur_ = (cur_ + 1) % pattern_.size();
36 return pattern_[cur_];
37 }
38
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -070039 float scale(Meshes::Type type) const {
Tony Barbour2f18b292016-02-25 15:44:10 -070040 float base = 0.005f;
41
42 switch (type) {
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -070043 case Meshes::MESH_PYRAMID:
44 default:
45 return base * 1.0f;
46 case Meshes::MESH_ICOSPHERE:
47 return base * 3.0f;
48 case Meshes::MESH_TEAPOT:
49 return base * 10.0f;
Tony Barbour2f18b292016-02-25 15:44:10 -070050 }
51 }
52
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -070053 private:
Tony Barbour2f18b292016-02-25 15:44:10 -070054 const std::array<Meshes::Type, 10> pattern_;
55 int cur_;
56};
57
58class ColorPicker {
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -070059 public:
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -070060 ColorPicker(unsigned int rng_seed) : rng_(rng_seed), red_(0.0f, 1.0f), green_(0.0f, 1.0f), blue_(0.0f, 1.0f) {}
Tony Barbour2f18b292016-02-25 15:44:10 -070061
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -070062 glm::vec3 pick() { return glm::vec3{red_(rng_), green_(rng_), blue_(rng_)}; }
Tony Barbour2f18b292016-02-25 15:44:10 -070063
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -070064 private:
Tony Barbour2f18b292016-02-25 15:44:10 -070065 std::mt19937 rng_;
66 std::uniform_real_distribution<float> red_;
67 std::uniform_real_distribution<float> green_;
68 std::uniform_real_distribution<float> blue_;
69};
70
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -070071} // namespace
Tony Barbour2f18b292016-02-25 15:44:10 -070072
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -070073Animation::Animation(unsigned int rng_seed, float scale) : rng_(rng_seed), dir_(-1.0f, 1.0f), speed_(0.1f, 1.0f) {
Tony Barbour2f18b292016-02-25 15:44:10 -070074 float x = dir_(rng_);
75 float y = dir_(rng_);
76 float z = dir_(rng_);
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -070077 if (std::abs(x) + std::abs(y) + std::abs(z) == 0.0f) x = 1.0f;
Tony Barbour2f18b292016-02-25 15:44:10 -070078
79 current_.axis = glm::normalize(glm::vec3(x, y, z));
80
81 current_.speed = speed_(rng_);
82 current_.scale = scale;
83
84 current_.matrix = glm::scale(glm::mat4(1.0f), glm::vec3(current_.scale));
85}
86
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -070087glm::mat4 Animation::transformation(float t) {
Tony Barbour2f18b292016-02-25 15:44:10 -070088 current_.matrix = glm::rotate(current_.matrix, current_.speed * t, current_.axis);
89
90 return current_.matrix;
91}
92
93class Curve {
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -070094 public:
Tony Barbour2f18b292016-02-25 15:44:10 -070095 virtual ~Curve() {}
96 virtual glm::vec3 evaluate(float t) = 0;
97};
98
99namespace {
100
101enum CurveType {
102 CURVE_RANDOM,
103 CURVE_CIRCLE,
104 CURVE_COUNT,
105};
106
107class RandomCurve : public Curve {
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700108 public:
Tony Barbour2f18b292016-02-25 15:44:10 -0700109 RandomCurve(unsigned int rng_seed)
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700110 : rng_(rng_seed),
111 direction_(-0.3f, 0.3f),
112 duration_(1.0f, 5.0f),
113 segment_start_(0.0f),
114 segment_direction_(0.0f),
115 time_start_(0.0f),
116 time_duration_(0.0f) {}
Tony Barbour2f18b292016-02-25 15:44:10 -0700117
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700118 glm::vec3 evaluate(float t) {
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700119 if (t >= time_start_ + time_duration_) new_segment(t);
Tony Barbour2f18b292016-02-25 15:44:10 -0700120
121 pos_ += unit_dir_ * (t - last_);
122 last_ = t;
123
124 return pos_;
125 }
126
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700127 private:
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700128 void new_segment(float time_start) {
Tony Barbour2f18b292016-02-25 15:44:10 -0700129 segment_start_ += segment_direction_;
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700130 segment_direction_ = glm::vec3(direction_(rng_), direction_(rng_), direction_(rng_));
Tony Barbour2f18b292016-02-25 15:44:10 -0700131
132 time_start_ = time_start;
133 time_duration_ = duration_(rng_);
134
135 unit_dir_ = segment_direction_ / time_duration_;
136 pos_ = segment_start_;
137 last_ = time_start_;
138 }
139
140 std::mt19937 rng_;
141 std::uniform_real_distribution<float> direction_;
142 std::uniform_real_distribution<float> duration_;
143
144 glm::vec3 segment_start_;
145 glm::vec3 segment_direction_;
146 float time_start_;
147 float time_duration_;
148
149 glm::vec3 unit_dir_;
150 glm::vec3 pos_;
151 float last_;
152};
153
154class CircleCurve : public Curve {
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700155 public:
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700156 CircleCurve(float radius, glm::vec3 axis) : r_(radius) {
Tony Barbour2f18b292016-02-25 15:44:10 -0700157 glm::vec3 a;
158
159 if (axis.x != 0.0f) {
160 a.x = -axis.z / axis.x;
161 a.y = 0.0f;
162 a.z = 1.0f;
163 } else if (axis.y != 0.0f) {
164 a.x = 1.0f;
165 a.y = -axis.x / axis.y;
166 a.z = 0.0f;
167 } else {
168 a.x = 1.0f;
169 a.y = 0.0f;
170 a.z = -axis.x / axis.z;
171 }
172
173 a_ = glm::normalize(a);
174 b_ = glm::normalize(glm::cross(a_, axis));
175 }
176
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700177 glm::vec3 evaluate(float t) {
178 return (a_ * (glm::vec3(std::cos(t)) - glm::vec3(1.0f)) + b_ * glm::vec3(std::sin(t))) * glm::vec3(r_);
Tony Barbour2f18b292016-02-25 15:44:10 -0700179 }
180
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700181 private:
Tony Barbour2f18b292016-02-25 15:44:10 -0700182 float r_;
183 glm::vec3 a_;
184 glm::vec3 b_;
185};
186
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700187} // namespace
Tony Barbour2f18b292016-02-25 15:44:10 -0700188
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700189Path::Path(unsigned int rng_seed) : rng_(rng_seed), type_(0, CURVE_COUNT - 1), duration_(5.0f, 20.0f) {
Tony Barbour2f18b292016-02-25 15:44:10 -0700190 // trigger a subpath generation
191 current_.end = -1.0f;
192 current_.now = 0.0f;
193}
194
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700195glm::vec3 Path::position(float t) {
Tony Barbour2f18b292016-02-25 15:44:10 -0700196 current_.now += t;
197
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700198 while (current_.now >= current_.end) generate_subpath();
Tony Barbour2f18b292016-02-25 15:44:10 -0700199
200 return current_.origin + current_.curve->evaluate(current_.now - current_.start);
201}
202
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700203void Path::generate_subpath() {
Tony Barbour2f18b292016-02-25 15:44:10 -0700204 float duration = duration_(rng_);
205 CurveType type = static_cast<CurveType>(type_(rng_));
206
207 if (current_.curve) {
208 current_.origin += current_.curve->evaluate(current_.end - current_.start);
209 current_.start = current_.end;
210 } else {
211 std::uniform_real_distribution<float> origin(0.0f, 2.0f);
212 current_.origin = glm::vec3(origin(rng_), origin(rng_), origin(rng_));
213 current_.start = current_.now;
214 }
215
216 current_.end = current_.start + duration;
217
218 Curve *curve;
219
220 switch (type) {
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700221 case CURVE_RANDOM:
222 curve = new RandomCurve(rng_());
223 break;
224 case CURVE_CIRCLE: {
225 std::uniform_real_distribution<float> dir(-1.0f, 1.0f);
226 glm::vec3 axis(dir(rng_), dir(rng_), dir(rng_));
227 if (axis.x == 0.0f && axis.y == 0.0f && axis.z == 0.0f) axis.x = 1.0f;
Tony Barbour2f18b292016-02-25 15:44:10 -0700228
Mark Lobodzinskicc7c3052017-01-26 13:34:13 -0700229 std::uniform_real_distribution<float> radius_(0.02f, 0.2f);
230 curve = new CircleCurve(radius_(rng_), axis);
231 } break;
232 default:
233 assert(!"unreachable");
234 curve = nullptr;
235 break;
Tony Barbour2f18b292016-02-25 15:44:10 -0700236 }
237
238 current_.curve.reset(curve);
239}
240
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700241Simulation::Simulation(int object_count) : random_dev_() {
Tony Barbour2f18b292016-02-25 15:44:10 -0700242 MeshPicker mesh;
243 ColorPicker color(random_dev_());
244
245 objects_.reserve(object_count);
246 for (int i = 0; i < object_count; i++) {
247 Meshes::Type type = mesh.pick();
248 float scale = mesh.scale(type);
249
250 objects_.emplace_back(Object{
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700251 type, glm::vec3(0.5f + 0.5f * (float)i / object_count), color.pick(), Animation(random_dev_(), scale),
252 Path(random_dev_()),
Tony Barbour2f18b292016-02-25 15:44:10 -0700253 });
254 }
255}
256
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700257void Simulation::set_frame_data_size(uint32_t size) {
Tony Barbour2f18b292016-02-25 15:44:10 -0700258 uint32_t offset = 0;
259 for (auto &obj : objects_) {
260 obj.frame_data_offset = offset;
261 offset += size;
262 }
263}
264
Mark Lobodzinskibc9caa52017-01-26 12:16:30 -0700265void Simulation::update(float time, int begin, int end) {
Tony Barbour2f18b292016-02-25 15:44:10 -0700266 for (int i = begin; i < end; i++) {
267 auto &obj = objects_[i];
268
269 glm::vec3 pos = obj.path.position(time);
270 glm::mat4 trans = obj.animation.transformation(time);
271 obj.model = glm::translate(glm::mat4(1.0f), pos) * trans;
272 }
273}