-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
360 lines (326 loc) · 13.2 KB
/
main.cpp
File metadata and controls
360 lines (326 loc) · 13.2 KB
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
#include <iostream>
// Loader for OpenGL extensions
// http://glad.dav1d.de/
// THIS IS OPTIONAL AND NOT REQUIRED, ONLY USE THIS IF YOU DON'T WANT GLAD TO INCLUDE windows.h
// GLAD will include windows.h for APIENTRY if it was not previously defined.
// Make sure you have the correct definition for APIENTRY for platforms which define _WIN32 but don't use __stdcall
#ifdef _WIN32
#define APIENTRY __stdcall
#endif
#define GLM_ENABLE_EXPERIMENTAL
#define IMGUI_DEFINE_MATH_OPERATORS
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
// another check related to OpenGL loader
// confirm that GLAD didn't include windows.h
#ifdef _WINDOWS_
#error windows.h was included!
#endif
#include "renderer.h"
#include "scene.h"
#include <utils/random_utils.h>
#include "camera.h"
#include "input.h"
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include <filesystem>
#include "imGuIZMOquat.h"
static string selected_model = "./assets/models/bunny_lp.obj";
static std::vector<string> model_files{};
static string selected_texture = "./assets/textures/UV_Grid_Sm.png";
static string selected_noise_texture = "./assets/textures/Voronoi 7 - 512x512.png";
static std::vector<string> texture_files{};
static float dt_multiplier = 1;
static bool show_debug_buffer = false;
static bool draw_particles = true;
static vec3 particles_spawn_direction{0.775614f, 0.441849f, -0.450769f};
static vec3 particles_spawn_randomness{0.15, 0.15, 0.15};
static float particles_spawn_speed = 3.5;
static float particle_spawn_life = 5;
static float particle_added_spawn_life_randomness = 0.8;
static int particle_number = 100000;
static quat disappearing_object_rotation = toQuat(mat4{1});
static float disappearing_object_scale = 2.f;
static vec3 disappearing_object_position{1.f};
static int particles_framebuffer_width_height[2] = {800, 600};
static float particle_size = 0.1f;
static bool particle_size_auto_scaling = true;
void menu_window(GLFWwindow* window, ImGuiIO& io);
int main(int argc, char* argv[])
{
particles_spawn_direction = normalize(particles_spawn_direction);
for (const auto& entry : std::filesystem::directory_iterator("./assets/models"))
{
model_files.push_back(entry.path().string());
}
for (const auto& entry : std::filesystem::directory_iterator("./assets/textures"))
{
texture_files.push_back(entry.path().string());
}
randInit();
Camera camera{};
int w = 1920;
int h = 1080;
if (argc >= 3)
{
w = std::stoi(argv[1]);
h = std::stoi(argv[2]);
}
Renderer r(camera, w, h);
auto init_res = r.init();
if (init_res != 0)
{
return init_res;
}
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(r.getGlfwWindow(), true);
ImGui_ImplOpenGL3_Init();
r.setProjectionMatrix(perspective(45.0f, static_cast<float>(r.screenWidth()) / static_cast<float>(r.screenHeight()),
0.1f, 10000.0f));
camera.setTransform(inverse(lookAt(vec3(0.0f, 0.0f, 30.0f), vec3(0.0f, 0.0f, -7.0f), vec3(0.0f, 1.0f, 0.0f))));
std::cout << "init done" << std::endl;
r.setKeyCallback(key_callback);
r.setCursorPosCallback(mouse_callback);
int frames = 0;
float cumulative_dt = 0;
auto scene = Scene(r, selected_model, selected_texture, selected_noise_texture, particle_number,
particles_framebuffer_width_height[0], particles_framebuffer_width_height[1]);
scene.init(draw_particles, particle_size);
// Main loop
while (!r.shouldClose())
{
if (reset_scene)
{
std::cout << "resetting scene with model: " << selected_model << " texture: " << selected_texture <<
std::endl;
scene.~Scene();
if (particle_size_auto_scaling)
{
const auto ratio = static_cast<float>(particles_framebuffer_width_height[0] *
particles_framebuffer_width_height[1]) / static_cast<float>(w * h);
particle_size = (1 / (ratio + 0.08f)) * 0.03f;
}
new(&scene) Scene(r, selected_model, selected_texture, selected_noise_texture, particle_number,
particles_framebuffer_width_height[0], particles_framebuffer_width_height[1]);
scene.init(draw_particles, particle_size);
reset_scene = false;
}
// Set values from menu
camera.sensitivity = mouse_sensitivity;
scene.show_debug_buffer = show_debug_buffer;
scene.particles_update_func = [](Particles::Particle& p, const float dt)
{
p.pos(p.pos() + p.velocity() * dt);
};
scene.start_velocity_func = []
{
const auto random_dir = vec3{randMinusOneOne(), randMinusOneOne(), randMinusOneOne()};
const auto direction = vec3{
lerp(particles_spawn_direction[0], random_dir[0], particles_spawn_randomness[0]),
lerp(particles_spawn_direction[1], random_dir[1], particles_spawn_randomness[1]),
lerp(particles_spawn_direction[2], random_dir[2], particles_spawn_randomness[2]),
};
return normalize(direction) * particles_spawn_speed;
};
scene.start_life_func = []
{
return particle_spawn_life + randZeroOne() * particle_spawn_life * particle_added_spawn_life_randomness;
};
scene.disappearing_object_rotation = disappearing_object_rotation;
scene.disappearing_object_scale = disappearing_object_scale;
scene.disappearing_object_position = disappearing_object_position;
glfwPollEvents();
keypresses_handling();
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
if (menu_on)
{
menu_window(r.getGlfwWindow(), io);
ImGui_ImplGlfw_CursorPosCallback(r.getGlfwWindow(), mouseX, mouseY);
}
else
{
if (mouse_updated)
{
disappearing_object_position += vec3{mouseDx, -mouseDy, 0} * mouse_sensitivity;
mouse_updated = false;
}
for (const auto& dir : buffered_directions)
{
camera.addDirection(dir);
}
buffered_directions.clear();
}
frames++;
r.computeDeltaTime();
const float dt = r.deltaTime();
cumulative_dt += dt;
if (cumulative_dt >= 1)
{
cumulative_dt = 0;
std::cout << "dt: " << dt * 1000 << "ms" << std::endl;
std::cout << "FPS: " << 1 / dt << std::endl;
std::cout << "num of active particles: " << scene.particles.livingParticles << std::endl;
}
if (!pause)
{
scene.mainLoop(dt * dt_multiplier);
}
r.render();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
r.swapBuffers();
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
return 0;
}
static void HelpMarker(const char* desc)
{
ImGui::TextDisabled("(?)");
if (ImGui::BeginItemTooltip())
{
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
void menu_window(GLFWwindow* window, ImGuiIO& io)
{
ImGui::Begin("Menu");
ImGui::Text("P pauses and resumes the simulation");
ImGui::Text("R resets the simulation");
ImGui::Text("Press esc to close the menu and move the object");
ImGui::SliderFloat("dt_multiplier", &dt_multiplier, 0.0f, 5.0f);
ImGui::SliderFloat("mouse sensitivity", &mouse_sensitivity, 0.0f, 1.0f);
// Model selection
static int selected_model_idx = 0;
if (ImGui::BeginCombo("model", selected_model.c_str()))
{
for (int i = 0; i < model_files.size(); i++)
{
const bool is_selected = (selected_model_idx == i);
if (ImGui::Selectable(model_files[i].c_str(), is_selected))
{
selected_model_idx = i;
selected_model = model_files[selected_model_idx];
reset_scene = true;
}
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
// Texture selection
static int selected_texure_idx = 0;
if (ImGui::BeginCombo("texture", selected_texture.c_str()))
{
for (int i = 0; i < texture_files.size(); i++)
{
const bool is_selected = (selected_texure_idx == i);
if (ImGui::Selectable(texture_files[i].c_str(), is_selected))
{
selected_texure_idx = i;
selected_texture = texture_files[selected_texure_idx];
reset_scene = true;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
static bool different_noise_texture = true;
ImGui::Checkbox("Use different noise texture", &different_noise_texture);
ImGui::SameLine();
HelpMarker("If unchecked uses the selected texture as both the noise texture and the object texture");
if (different_noise_texture)
{
// Noise Texture selection
static int selected_noise_texture_idx = 0;
if (ImGui::BeginCombo("noise texture", selected_noise_texture.c_str()))
{
for (int i = 0; i < texture_files.size(); i++)
{
const bool is_selected = (selected_noise_texture_idx == i);
if (ImGui::Selectable(texture_files[i].c_str(), is_selected))
{
selected_noise_texture_idx = i;
selected_noise_texture = texture_files[selected_noise_texture_idx];
reset_scene = true;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
else
{
selected_noise_texture = selected_texture;
}
ImGui::SeparatorText("Object control");
if (ImGui::Button("Reset object position, rotation and scaling"))
{
disappearing_object_position = vec3{1};
disappearing_object_scale = 2.f;
disappearing_object_rotation = toQuat(mat3{1});
reset_scene = true;
}
ImGui::gizmo3D("Rotate object", disappearing_object_rotation, 200,
imguiGizmo::mode3Axes | imguiGizmo::cubeAtOrigin);
ImGui::DragFloat("Scale object", &disappearing_object_scale, 0.005f, 0.0f, 20.f, "%.3f");
ImGui::SeparatorText("Particle spawn");
if (ImGui::Checkbox("draw particles", &draw_particles))
reset_scene = true;
ImGui::Text("The options below affect only the particles that are not yet spawned");
if (ImGui::SliderInt("Number of max particles", &particle_number, 0, 1000000000, "%d",
ImGuiSliderFlags_Logarithmic))
reset_scene = true;
ImGui::gizmo3D("Particles Direction", particles_spawn_direction, 200, imguiGizmo::modeDirection);
ImGui::SliderFloat3("Randomness XYZ", &particles_spawn_randomness[0], 0.f, 1.f, "%.3f");
ImGui::DragFloat("Speed", &particles_spawn_speed, 0.005f, 0.0f, 10.f, "%.3f", ImGuiSliderFlags_Logarithmic);
if (ImGui::Checkbox("Particle size auto scaling", &particle_size_auto_scaling))
reset_scene = true;
ImGui::SameLine();
HelpMarker("If checked the particle size roughly scales with the resolution of the particle buffer");
if (!particle_size_auto_scaling)
{
if (ImGui::DragFloat("Size", &particle_size, 0.005f, 0.0f, 10.f, "%.3f", ImGuiSliderFlags_Logarithmic))
reset_scene = true;
}
ImGui::SeparatorText("Other options");
if (ImGui::DragInt2("Particle buffer resolution (width, height)", particles_framebuffer_width_height, 1.f, 1.f,
4000.f, "%d"))
reset_scene = true;
ImGui::SeparatorText("Particle lifetime");
ImGui::Text("The options below affect only the particles that are not yet spawned");
ImGui::DragFloat("Particle spawn life", &particle_spawn_life, 0.005f, 0.f, 100.f, "%.3f",
ImGuiSliderFlags_Logarithmic);
ImGui::SliderFloat("Particle added spawn life randomness", &particle_added_spawn_life_randomness, 0.f, 1.f, "%.3f");
ImGui::Checkbox("Show debug buffer (particles spawned in the current frame)", &show_debug_buffer);
static bool vsync = true;
if (ImGui::Checkbox("Vsync", &vsync))
{
glfwSwapInterval(vsync);
};
ImGui::Checkbox("Pause", &pause);
if (ImGui::Button("Reset scene"))
reset_scene = true;
if (ImGui::Button("Quit"))
glfwSetWindowShouldClose(window, GL_TRUE);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}