diff --git a/CMakeLists.txt b/CMakeLists.txt index b7dca6b..37f99c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") include(FindPkgConfig) find_package(glfw3 3.3 REQUIRED) find_package(OpenGL REQUIRED) +find_package(SDL2 REQUIRED) +include_directories(${SDL2_INCLUDE_DIRS}) include_directories("src/") include_directories("gl/include") @@ -30,4 +32,4 @@ set(SOURCE ) add_executable(demo main.cpp gl/src/glad.c ${SOURCE} lib/easyloggingpp/src/easylogging++.cc) -target_link_libraries(demo glfw OpenGL::GL) \ No newline at end of file +target_link_libraries(demo glfw OpenGL::GL ${SDL2_LIBRARIES}) \ No newline at end of file diff --git a/main.cpp b/main.cpp index b87737f..3f33291 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ #include +#include #include "imgui.h" #include "imgui_impl_glfw.h" @@ -7,6 +8,8 @@ #include "peripherals_glfw.h" #include "demo/demo_engine.h" #include "timer.h" +#include "audio/sound_server.h" +#include using namespace acidrain; using namespace std; @@ -15,30 +18,30 @@ INITIALIZE_EASYLOGGINGPP int main() { acidrain::peripherals_glfw peripherals; - peripherals.init(); + peripherals.init(demo_data::screen_width, demo_data::screen_height, "acidrain", false); LOG(INFO) << "peripherals initialized"; glDisable(GL_DEPTH_TEST); - const float DEMO_LENGTH_IN_SECONDS = 100; + const float DEMO_LENGTH_IN_SECONDS = 1000; // -------------------------------------------------------------------------------------- // Load resources // -------------------------------------------------------------------------------------- acidrain::texture_generator tg(256, 256); - tg.brick(0, 50, 20, 4, glm::vec4(1), glm::vec4(0)); -// tg.checker_board(0, 50, glm::vec4(1), glm::vec4(0)); +// tg.brick(0, 50, 20, 4, glm::vec4(1), glm::vec4(0)); + tg.checker_board(0, 50, glm::vec4(1), glm::vec4(0)); - shared_ptr affectedSphere = mesh_generator::sphere(50, 50); - map_transform(affectedSphere, tg, 0, 0, 0.2f); - calculate_normals(*affectedSphere.get()); + shared_ptr affected_sphere = mesh_generator::sphere(50, 50); + map_transform(affected_sphere, tg, 0, 0, 0.2f); + calculate_normals(*affected_sphere); // affectedSphere = mesh_generator::cog(0.2, 0.5, 50, 4, 0.1, 0.2, 0.2, 0.1); - demo_data::meshes.push_back(affectedSphere); + demo_data::meshes.push_back(affected_sphere); demo_data::meshes.push_back(mesh_generator::sphere(3, 3)); - demo_data::meshes.push_back(mesh_generator::grid(30, 30)); + demo_data::meshes.push_back(mesh_generator::grid(1, 1)); demo_data::meshes.push_back(mesh_generator::cube()); auto mat = std::make_shared(); @@ -49,21 +52,21 @@ int main() { mat->shininess = 200; mat->cast_shadows = true; - auto *textureGenerator1 = new texture_generator(256, 256); -// mat->textures[texture_role::diffuse] = textureGenerator1->checker_board(0, 20, -// colour(1, 1, 1, 1), -// colour(0, 0.5, 0.2, 1)).get_texture(0); - mat->textures[texture_role::diffuse] = textureGenerator1->brick(0, - 50, 20, - 4, - colour(0.3, 0.1, 0, 1), - colour(1, 0.3, 0, 1)).get_texture(0); + auto *texgen = new texture_generator(256, 256); + mat->textures[texture_role::diffuse] = texgen->checker_board(0, 20, + colour(1, 1, 1, 1), + colour(0, 0.5, 0.2, 1)).get_texture(0); +// mat->textures[texture_role::diffuse] = textureGenerator1->brick(0, +// 50, 20, +// 4, +// colour(0.3, 0.1, 0, 1), +// colour(1, 0.3, 0, 1)).get_texture(0); demo_data::materials.push_back(mat); auto material2 = make_shared(); material2->ambient = glm::vec4(0, 0, 0.15, 1); - material2->textures[texture_role::diffuse] = textureGenerator1->get_texture(0); + material2->textures[texture_role::diffuse] = texgen->get_texture(0); // material2->diffuse = glm::vec4(0.2, 1.0, 0.7, 1); material2->diffuse = glm::vec4(1, 1, 1, 1); material2->specular = glm::vec4(0.3, 0.3, 0.3, 1); @@ -102,14 +105,14 @@ int main() { // Set up demo parts // -------------------------------------------------------------------------------------- - DemoPartClear demoPartClear; - demoPartClear.startTime = 0; - demoPartClear.endTime = DEMO_LENGTH_IN_SECONDS; + demo_part_clear demoPartClear; + demoPartClear.start_time = 0; + demoPartClear.end_time = DEMO_LENGTH_IN_SECONDS; demoPartClear.color = glm::vec4(0.1f, 0.1f, 0.3f, 1.0f); - DemoPartScene demoPartScene; - demoPartScene.startTime = 0; - demoPartScene.endTime = DEMO_LENGTH_IN_SECONDS; + demo_part_scene demoPartScene; + demoPartScene.start_time = 0; + demoPartScene.end_time = DEMO_LENGTH_IN_SECONDS; demoPartScene.cameraName = "cam1"; demoPartScene.lightName = "light1"; @@ -135,21 +138,21 @@ int main() { back_plane->material_ = demo_data::materials[1]; back_plane->position = glm::vec3(0, 5, -5); back_plane->scale = glm::vec3(10); - back_plane->rotation = angleAxis(3.141529f, glm::vec3(1.0f, 0.0f, 0.0f)); + back_plane->rotation = glm::angleAxis(3.141529f, glm::vec3(1.0f, 0.0f, 0.0f)); auto left_plane = std::make_shared("left plane"); left_plane->mesh_ = demo_data::meshes[2]; left_plane->material_ = demo_data::materials[1]; left_plane->position = glm::vec3(-5, 5, 0); left_plane->scale = glm::vec3(10); - left_plane->rotation = angleAxis(-3.141529f / 2.0f, glm::vec3(0.0f, 1.0f, 0.0f)); + left_plane->rotation = glm::angleAxis(-3.141529f / 2.0f, glm::vec3(0.0f, 1.0f, 0.0f)); auto right_plane = std::make_shared("right plane"); right_plane->mesh_ = demo_data::meshes[2]; right_plane->material_ = demo_data::materials[1]; right_plane->position = glm::vec3(5, 5, 0); right_plane->scale = glm::vec3(10); - right_plane->rotation = angleAxis(3.141529f / 2.0f, glm::vec3(0.0f, 1.0f, 0.0f)); + right_plane->rotation = glm::angleAxis(3.141529f / 2.0f, glm::vec3(0.0f, 1.0f, 0.0f)); auto bigSphere = make_shared("big sphere"); bigSphere->mesh_ = demo_data::meshes[0]; @@ -178,7 +181,7 @@ int main() { lightNode->spot_cutoff = 50.0f; lightNode->spot_exponent = 16.0f; lightNode->ambient = glm::vec4(0.1, 0.1, 0.1, 1.0); - lightNode->diffuse = glm::vec4(0.5, 1.0, 1.0, 1.0); + lightNode->diffuse = glm::vec4(0.1, 0.3, 1.0, 1.0); lightNode->specular = glm::vec4(0.0, 0.8, 0.1, 1.0); auto lightNode2 = make_shared(light_type::spot); @@ -188,8 +191,8 @@ int main() { lightNode2->spot_cutoff = 50.0f; lightNode2->spot_exponent = 16.0f; lightNode2->ambient = glm::vec4(0.1, 0.1, 0.1, 1.0); - lightNode2->diffuse = glm::vec4(1.0, 0.5, 1.0, 1.0); - lightNode2->specular = glm::vec4(0.0, 0.8, 0.1, 1.0); + lightNode2->diffuse = glm::vec4(1.0, 0.5, 0.3, 1.0); + lightNode2->specular = glm::vec4(1.0, 0.8, 0.1, 1.0); scene1->tree->add(ground_plane); scene1->tree->add(back_plane); @@ -213,14 +216,15 @@ int main() { glBindFramebuffer(GL_FRAMEBUFFER, 0); - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; - ImGui::StyleColorsDark(); - - // Setup Platform/Renderer backends - ImGui_ImplGlfw_InitForOpenGL(((peripherals_glfw*)&peripherals)->get_window(), true); - ImGui_ImplOpenGL3_Init("#version 150"); +// IMGUI_CHECKVERSION(); +// ImGui::CreateContext(); +// ImGuiIO& io = ImGui::GetIO(); +// (void) io; +// ImGui::StyleColorsDark(); +// +// // Setup Platform/Renderer backends +// ImGui_ImplGlfw_InitForOpenGL(((peripherals_glfw *) &peripherals)->get_window(), true); +// ImGui_ImplOpenGL3_Init("#version 150"); timer timer1; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); @@ -228,56 +232,57 @@ int main() { bool show_another_window = false; while (!peripherals.should_close() && timer1.seconds_since_start() < DEMO_LENGTH_IN_SECONDS) { - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - { - static float f = 0.0f; - static int counter = 0; - - ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. - - ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) - ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state - ImGui::Checkbox("Another Window", &show_another_window); - - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color - - if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) - counter++; - ImGui::SameLine(); - ImGui::Text("counter = %d", counter); - - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::End(); - } +// ImGui_ImplOpenGL3_NewFrame(); +// ImGui_ImplGlfw_NewFrame(); +// ImGui::NewFrame(); +// +// { +// static float f = 0.0f; +// static int counter = 0; +// +// ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. +// +// ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) +// ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state +// ImGui::Checkbox("Another Window", &show_another_window); +// +// ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f +// ImGui::ColorEdit3("clear color", (float *) &clear_color); // Edit 3 floats representing a color +// +// if (ImGui::Button( +// "Button")) // Buttons return true when clicked (most widgets return true when edited/activated) +// counter++; +// ImGui::SameLine(); +// ImGui::Text("counter = %d", counter); +// +// ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); +// ImGui::End(); +// } - double elapsedSeconds = timer1.seconds_since_start(); + auto elapsed_seconds = timer1.seconds_since_start(); bigSphere->mesh_ = mesh_generator::extrude(mesh_generator::sphere(50, 50), {200, 201, 100, 101, 400, 401}, 0.05, - (int) ((sin(elapsedSeconds) + 0.5) * 40)); + (int) ((sinf(elapsed_seconds) + 0.5f) * 40)); - smallSphere->position = glm::vec3(0, sin(2 * M_PI * 0.13 * elapsedSeconds) * 2.0 + 0.5, 0); + smallSphere->position = glm::vec3(0, sin(2 * M_PI * 0.13 * elapsed_seconds) * 2.0 + 0.5, 0); // meshNode->position = glm::vec3(0, 0.001, 0); // camNode->target = glm::vec3(0, 0.0001, 0); // camNode->position = glm::vec3(0, 5, -10); - lightNode2->position = glm::vec3(5 * sin(2 * M_PI * 0.05 * elapsedSeconds), 2, - 5 * cos(2 * M_PI * 0.05 * elapsedSeconds)); - lightNode->position = glm::vec3(5 * cos(2 * M_PI * 0.75 * elapsedSeconds), 2, - 5 * sin(2 * M_PI * 0.75 * elapsedSeconds)); + lightNode2->position = glm::vec3(5 * sin(2 * M_PI * 0.05 * elapsed_seconds), 2, + 5 * cos(2 * M_PI * 0.05 * elapsed_seconds)); + lightNode->position = glm::vec3(5 * cos(2 * M_PI * 0.75 * elapsed_seconds), 2, + 5 * sin(2 * M_PI * 0.75 * elapsed_seconds)); lightMeshNode->position = lightNode2->position; bigSphere->rotation *= angleAxis((float) (M_PI / 4.0 * timer1.lap()), normalize(glm::vec3(0.2, 0.5, 0.3))); - demoPartClear.process(demoPartClear.normalizeTime(elapsedSeconds)); - demoPartScene.process(demoPartScene.normalizeTime(elapsedSeconds)); + demoPartClear.process(demoPartClear.normalize_time(elapsed_seconds)); + demoPartScene.process(demoPartScene.normalize_time(elapsed_seconds)); - ImGui::Render(); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +// ImGui::Render(); +// ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); peripherals.swap_buffers(); peripherals.poll_events(); diff --git a/midi.txt b/midi.txt new file mode 100644 index 0000000..0c499b7 --- /dev/null +++ b/midi.txt @@ -0,0 +1,39 @@ +Midi events delta time + + https://sites.uci.edu/camp2014/2014/05/19/timing-in-midi-files/ + http://www.music.mcgill.ca/~ich/classes/mumt306/StandardMIDIfileformat.html#BM2_3 + + - Delta-time is in some fraction of a beat (or a second, for recording a track with SMPTE times), as specified in the header chunk. + - nardis header track: + Format: 1 + tracks: 10 + division : 480 + The third word, , specifies the meaning of the delta-times. + It has two formats, one for metrical time, and one for time-code-based time: + + bit 15 bits 14 thru 8 bits 7 thru 0 + ======|===============================|============== + 0 | ticks per quarter-note + 1 | negative SMPTE format | ticks per frame + + If bit 15 of is zero, the bits 14 thru 0 represent the number of delta time "ticks" which make up a quarter-note. + For instance, if division is 96, then a time interval of an eighth-note between two events in the file would be 48. + + nardis division == 480 => bit 15 is zero, so we have 480 ticks per quarter note. + default tempo is 120, if not specified by a meta event + default time signature is 4/4 if not specified by a meta event + nardis has 4/4 time signature and tempo of 300000 microseconds per quarter note + + + MIDI header track gives division, which is PPQ (parts per quarter or ticks per quarter note). Nardis = 480 => delta time of 480 means a quarter note. + But how long is a quarter note? that is given by the tempo. + + + +PITCH bending + https://sites.uci.edu/camp2014/2014/04/30/managing-midi-pitchbend-messages/ + - we get a 14bit value, [0..16383] + - map this to [-1..1], meaning that 16383/2 means no bend + - the float is the relative amount of bending, we should multiply it by a synth setting which says what is the bending range (+/- 2 semitones for example) + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c4fb29..043f98e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,6 @@ set(HEADERS ${HEADERS} + ${CMAKE_CURRENT_SOURCE_DIR}/audio/sound_server.h ${CMAKE_CURRENT_SOURCE_DIR}/animation_track.h ${CMAKE_CURRENT_SOURCE_DIR}/camera_node.h ${CMAKE_CURRENT_SOURCE_DIR}/colour.h @@ -10,13 +11,15 @@ set(HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/mesh.h ${CMAKE_CURRENT_SOURCE_DIR}/mesh_generator.h ${CMAKE_CURRENT_SOURCE_DIR}/mesh_node.h + ${CMAKE_CURRENT_SOURCE_DIR}/particles.h ${CMAKE_CURRENT_SOURCE_DIR}/peripherals.h ${CMAKE_CURRENT_SOURCE_DIR}/peripherals_glfw.h + ${CMAKE_CURRENT_SOURCE_DIR}/perlin.h ${CMAKE_CURRENT_SOURCE_DIR}/scene.h ${CMAKE_CURRENT_SOURCE_DIR}/scene_node.h ${CMAKE_CURRENT_SOURCE_DIR}/scene_renderer.h ${CMAKE_CURRENT_SOURCE_DIR}/scene_tree.h - ${CMAKE_CURRENT_SOURCE_DIR}/shader.h + ${CMAKE_CURRENT_SOURCE_DIR}/shader_program.h ${CMAKE_CURRENT_SOURCE_DIR}/shader_constants.h ${CMAKE_CURRENT_SOURCE_DIR}/texture.h ${CMAKE_CURRENT_SOURCE_DIR}/texture_generator.h @@ -27,6 +30,7 @@ set(HEADERS set(SOURCE ${SOURCE} + ${CMAKE_CURRENT_SOURCE_DIR}/audio/sound_server.cpp ${CMAKE_CURRENT_SOURCE_DIR}/animation_track.cpp ${CMAKE_CURRENT_SOURCE_DIR}/camera_node.cpp ${CMAKE_CURRENT_SOURCE_DIR}/demo_data.cpp @@ -36,7 +40,9 @@ set(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/mesh.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mesh_generator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mesh_node.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/particles.cpp ${CMAKE_CURRENT_SOURCE_DIR}/peripherals_glfw.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/perlin.cpp ${CMAKE_CURRENT_SOURCE_DIR}/scene.cpp ${CMAKE_CURRENT_SOURCE_DIR}/scene_node.cpp ${CMAKE_CURRENT_SOURCE_DIR}/scene_renderer.cpp diff --git a/src/audio/sound_server.cpp b/src/audio/sound_server.cpp new file mode 100644 index 0000000..1262d86 --- /dev/null +++ b/src/audio/sound_server.cpp @@ -0,0 +1,36 @@ +#include "sound_server.h" +#include +#include + +void audio_callback(void *param, uint8_t *stream, int len) { + auto producer = reinterpret_cast(param); + uint16_t samples = len >> 2; // 4 bytes per F32 + uint16_t frames = samples >> 1; // 2 channels, left and right + producer->render(reinterpret_cast(stream), frames); +} + +sound_server::sound_server(uint16_t samplerate, sound_producer& producer) { + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + std::cerr << "Init failed" << std::endl; + exit(1); + } + + SDL_AudioSpec spec; + spec.freq = samplerate; + spec.format = AUDIO_F32; + spec.samples = 256; + spec.callback = audio_callback; + spec.userdata = reinterpret_cast(&producer); + spec.channels = 2; + + if (SDL_OpenAudio(&spec, nullptr) < 0) { + std::cerr << "Unable to open audio" << std::endl; + exit(1); + } + + SDL_PauseAudio(0); +} + +sound_server::~sound_server() { + SDL_Quit(); +} diff --git a/src/audio/sound_server.h b/src/audio/sound_server.h new file mode 100644 index 0000000..273bf61 --- /dev/null +++ b/src/audio/sound_server.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +struct sound_producer { + // interleaved samples, LR + virtual void render(float *buffer, uint16_t frames) = 0; +}; + +struct sound_server { + sound_server(uint16_t samplerate, sound_producer& producer); + ~sound_server(); +}; diff --git a/src/defines.h b/src/defines.h index ba334dd..9467f45 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,9 +1,18 @@ #pragma once + #include #include #define BEGIN_NAMESPACE namespace acidrain { #define END_NAMESPACE }; +inline int rand_int(int x, int y) { return rand() % (y - x + 1) + x; } + +inline double rand_float() { return ((rand()) / (RAND_MAX + 1.0)); } + +inline double rand_in_range(double x, double y) { + return x + rand_float() * (y - x); +} + //static int SCREEN_WIDTH = 800; //static int SCREEN_HEIGHT = 600; diff --git a/src/demo/demo_part.h b/src/demo/demo_part.h index 793b291..8160af4 100644 --- a/src/demo/demo_part.h +++ b/src/demo/demo_part.h @@ -4,12 +4,12 @@ BEGIN_NAMESPACE -struct DemoPart { - float startTime; // absolute time, since demo starts - float endTime; // absolute time, since demo starts +struct demo_part { + float start_time; // absolute time, since demo starts + float end_time; // absolute time, since demo starts - float normalizeTime(float absoluteTimeInSeconds) { - return (absoluteTimeInSeconds - startTime) / static_cast(endTime - startTime); + float normalize_time(float absolute_time_in_seconds) { + return (absolute_time_in_seconds - start_time) / static_cast(end_time - start_time); } virtual void process(float normalizedTime) = 0; diff --git a/src/demo/demo_part_clear.cpp b/src/demo/demo_part_clear.cpp index 2a23684..c0086b1 100644 --- a/src/demo/demo_part_clear.cpp +++ b/src/demo/demo_part_clear.cpp @@ -2,18 +2,18 @@ BEGIN_NAMESPACE -void DemoPartClear::process(float normalizedTime) { +void demo_part_clear::process(float normalized_time) { glClearColor(color.r, color.g, color.b, color.a); GLbitfield mask = 0; - if (clearDepth) + if (do_clear_depth) mask |= GL_DEPTH_BUFFER_BIT; - if (clearColor) + if (do_clear_color) mask |= GL_COLOR_BUFFER_BIT; - if (clearStencil) + if (do_clear_stencil) mask |= GL_STENCIL_BUFFER_BIT; glClear(mask); diff --git a/src/demo/demo_part_clear.h b/src/demo/demo_part_clear.h index e1374ec..c5dee75 100644 --- a/src/demo/demo_part_clear.h +++ b/src/demo/demo_part_clear.h @@ -5,15 +5,15 @@ BEGIN_NAMESPACE -struct DemoPartClear : DemoPart { +struct demo_part_clear : demo_part { glm::vec4 color = glm::vec4(0, 0, 0, 0); - bool clearDepth = true; - bool clearColor = true; - bool clearStencil = true; + bool do_clear_depth = true; + bool do_clear_color = true; + bool do_clear_stencil = true; - void process(float normalizedTime) override; + void process(float normalized_time) override; }; END_NAMESPACE \ No newline at end of file diff --git a/src/demo/demo_part_marching_cubes.cpp b/src/demo/demo_part_marching_cubes.cpp index ea5cd18..12e5e42 100644 --- a/src/demo/demo_part_marching_cubes.cpp +++ b/src/demo/demo_part_marching_cubes.cpp @@ -6,7 +6,7 @@ BEGIN_NAMESPACE -DemoPartMarchingCubes::DemoPartMarchingCubes(std::shared_ptr affectedMesh) { +demo_part_marching_cubes::demo_part_marching_cubes(std::shared_ptr affectedMesh) { mesh_ = affectedMesh; field.emitters.push_back(glm::vec4(0, 0.7, 0, 1)); @@ -15,36 +15,36 @@ DemoPartMarchingCubes::DemoPartMarchingCubes(std::shared_ptr affectedMesh) // field.emitters.push_back(glm::vec4(-0.5, 0.7, -0.3, 1)); } -void DemoPartMarchingCubes::process(float normalizedTime) { +void demo_part_marching_cubes::process(float normalized_time) { - field.emitters[0].x = sin(normalizedTime * 2 * M_PI * 4); - field.emitters[0].z = cos(normalizedTime * 2 * M_PI * 4); - field.emitters[0].y = 0.7 * cos(normalizedTime * 2 * M_PI * 2); + field.emitters[0].x = sin(normalized_time * 2 * M_PI * 4); + field.emitters[0].z = cos(normalized_time * 2 * M_PI * 4); + field.emitters[0].y = 0.7 * cos(normalized_time * 2 * M_PI * 2); - field.emitters[1].x = sin(normalizedTime * 2 * M_PI * 7); - field.emitters[1].z = cos(normalizedTime * 2 * M_PI * 3.5); + field.emitters[1].x = sin(normalized_time * 2 * M_PI * 7); + field.emitters[1].z = cos(normalized_time * 2 * M_PI * 3.5); - field.emitters[2].y = 0.5 * sin(normalizedTime * 2 * M_PI * 4); - field.emitters[2].z = 0.8 * cos(normalizedTime * 2 * M_PI * 2); + field.emitters[2].y = 0.5 * sin(normalized_time * 2 * M_PI * 4); + field.emitters[2].z = 0.8 * cos(normalized_time * 2 * M_PI * 2); // field.emitters[3].y = 0.8 * cos(normalizedTime * 2 * M_PI * 3); // field.emitters[3].z = 0.2 * sin(normalizedTime * 2 * M_PI * 8); - grid.evaluateForces(field); - grid.triangulate(*mesh_.get(), minFieldValue); + grid.evaluate_forces(field); + grid.triangulate(*mesh_.get(), min_field_value); for (auto &v: mesh_->vertices) - v.normal = field.getFieldNormalAt(v.position); + v.normal = field.get_field_normal_at(v.position); // calculateNormals(*mesh.get()); } -void MarchingCubesGrid::evaluateForces(ForceField &field) { +void marching_cubes_grid::evaluate_forces(force_field &field) { // Make sure we have enough space preallocated. // We use resize because we want it also logically allocated with defaults // so we can simply access an item at certain index with no issues - gridVertices.resize((xCells + 1) * (yCells + 1) * (zCells + 1)); + grid_vertices.resize((xCells + 1) * (yCells + 1) * (zCells + 1)); glm::vec3 stepSize( (xMax - xMin) / static_cast(xCells), @@ -64,11 +64,11 @@ void MarchingCubesGrid::evaluateForces(ForceField &field) { for (int x = 0; x <= xCells; x++) { gridVertex.x = xMin + x * stepSize.x; - gridVertex.w = field.getFieldValueAt(glm::vec3(gridVertex)); + gridVertex.w = field.get_field_value_at(glm::vec3(gridVertex)); // std::cout << std::setprecision(5) << std::fixed << "(x: " << gridVertex.x << ", y: " << gridVertex.y << ", z: " << gridVertex.z << ", val: " << gridVertex.w << ")" << std::endl; - gridVertices[cellIndex] = gridVertex; + grid_vertices[cellIndex] = gridVertex; cellIndex++; } @@ -77,7 +77,7 @@ void MarchingCubesGrid::evaluateForces(ForceField &field) { } -void MarchingCubesGrid::triangulate(mesh &m, float minFieldValue) { +void marching_cubes_grid::triangulate(mesh &m, float minFieldValue) { m.vertices.clear(); m.facets.clear(); @@ -87,20 +87,20 @@ void MarchingCubesGrid::triangulate(mesh &m, float minFieldValue) { for (int y = 0; y < yCells; y++) { for (int x = 0; x < xCells; x++) { - calculateCellVertices(x, y, z); + calculate_cell_vertices(x, y, z); - int cellType = classifyCell(minFieldValue); + int cellType = classify_cell(minFieldValue); if (!edgeTable[cellType]) continue; - calculateIntersectionVertices(cellType, minFieldValue); - addResultingFacets(m, cellType); + calculate_intersection_vertices(cellType, minFieldValue); + add_resulting_facets(m, cellType); } } } } -void MarchingCubesGrid::calculateCellVertices(int x, int y, int z) { +void marching_cubes_grid::calculate_cell_vertices(int x, int y, int z) { // TODO: optimize these out. they are constant for a given grid size. int xVerts = xCells + 1; int yVerts = yCells + 1; @@ -109,61 +109,61 @@ void MarchingCubesGrid::calculateCellVertices(int x, int y, int z) { int leftTopFarthestIndex = z * vertsInXYPlane + x + y * xCells; // see http://paulbourke.net/geometry/polygonise/polygonise1.gif - cubeVertexIndices[0] = leftTopFarthestIndex + xVerts; - cubeVertexIndices[1] = leftTopFarthestIndex + xVerts + 1; - cubeVertexIndices[2] = leftTopFarthestIndex + xVerts + 1 + vertsInXYPlane; - cubeVertexIndices[3] = leftTopFarthestIndex + xVerts + vertsInXYPlane; + cube_vertex_indices[0] = leftTopFarthestIndex + xVerts; + cube_vertex_indices[1] = leftTopFarthestIndex + xVerts + 1; + cube_vertex_indices[2] = leftTopFarthestIndex + xVerts + 1 + vertsInXYPlane; + cube_vertex_indices[3] = leftTopFarthestIndex + xVerts + vertsInXYPlane; - cubeVertexIndices[4] = leftTopFarthestIndex; - cubeVertexIndices[5] = leftTopFarthestIndex + 1; - cubeVertexIndices[6] = leftTopFarthestIndex + 1 + vertsInXYPlane; - cubeVertexIndices[7] = leftTopFarthestIndex + vertsInXYPlane; + cube_vertex_indices[4] = leftTopFarthestIndex; + cube_vertex_indices[5] = leftTopFarthestIndex + 1; + cube_vertex_indices[6] = leftTopFarthestIndex + 1 + vertsInXYPlane; + cube_vertex_indices[7] = leftTopFarthestIndex + vertsInXYPlane; } -int MarchingCubesGrid::classifyCell(float minFieldValue) { +int marching_cubes_grid::classify_cell(float minFieldValue) { int result = 0; for (int i = 0; i < 8; i++) - if (gridVertices[cubeVertexIndices[i]].w <= minFieldValue) + if (grid_vertices[cube_vertex_indices[i]].w <= minFieldValue) result |= 1 << i; return result; } -void MarchingCubesGrid::calculateIntersectionVertices(int cellType, float minFieldValue) { +void marching_cubes_grid::calculate_intersection_vertices(int cellType, float minFieldValue) { if (edgeTable[cellType] & 1) - intersectionVertices[0] = intersection(cubeVertexIndices[0], cubeVertexIndices[1], minFieldValue); + intersection_vertices[0] = intersection(cube_vertex_indices[0], cube_vertex_indices[1], minFieldValue); if (edgeTable[cellType] & 2) - intersectionVertices[1] = intersection(cubeVertexIndices[1], cubeVertexIndices[2], minFieldValue); + intersection_vertices[1] = intersection(cube_vertex_indices[1], cube_vertex_indices[2], minFieldValue); if (edgeTable[cellType] & 4) - intersectionVertices[2] = intersection(cubeVertexIndices[2], cubeVertexIndices[3], minFieldValue); + intersection_vertices[2] = intersection(cube_vertex_indices[2], cube_vertex_indices[3], minFieldValue); if (edgeTable[cellType] & 8) - intersectionVertices[3] = intersection(cubeVertexIndices[3], cubeVertexIndices[0], minFieldValue); + intersection_vertices[3] = intersection(cube_vertex_indices[3], cube_vertex_indices[0], minFieldValue); if (edgeTable[cellType] & 16) - intersectionVertices[4] = intersection(cubeVertexIndices[4], cubeVertexIndices[5], minFieldValue); + intersection_vertices[4] = intersection(cube_vertex_indices[4], cube_vertex_indices[5], minFieldValue); if (edgeTable[cellType] & 32) - intersectionVertices[5] = intersection(cubeVertexIndices[5], cubeVertexIndices[6], minFieldValue); + intersection_vertices[5] = intersection(cube_vertex_indices[5], cube_vertex_indices[6], minFieldValue); if (edgeTable[cellType] & 64) - intersectionVertices[6] = intersection(cubeVertexIndices[6], cubeVertexIndices[7], minFieldValue); + intersection_vertices[6] = intersection(cube_vertex_indices[6], cube_vertex_indices[7], minFieldValue); if (edgeTable[cellType] & 128) - intersectionVertices[7] = intersection(cubeVertexIndices[7], cubeVertexIndices[4], minFieldValue); + intersection_vertices[7] = intersection(cube_vertex_indices[7], cube_vertex_indices[4], minFieldValue); if (edgeTable[cellType] & 256) - intersectionVertices[8] = intersection(cubeVertexIndices[0], cubeVertexIndices[4], minFieldValue); + intersection_vertices[8] = intersection(cube_vertex_indices[0], cube_vertex_indices[4], minFieldValue); if (edgeTable[cellType] & 512) - intersectionVertices[9] = intersection(cubeVertexIndices[1], cubeVertexIndices[5], minFieldValue); + intersection_vertices[9] = intersection(cube_vertex_indices[1], cube_vertex_indices[5], minFieldValue); if (edgeTable[cellType] & 1024) - intersectionVertices[10] = intersection(cubeVertexIndices[2], cubeVertexIndices[6], minFieldValue); + intersection_vertices[10] = intersection(cube_vertex_indices[2], cube_vertex_indices[6], minFieldValue); if (edgeTable[cellType] & 2048) - intersectionVertices[11] = intersection(cubeVertexIndices[3], cubeVertexIndices[7], minFieldValue); + intersection_vertices[11] = intersection(cube_vertex_indices[3], cube_vertex_indices[7], minFieldValue); } -glm::vec3 MarchingCubesGrid::intersection(int v1Index, int v2Index, float minFieldValue) { - glm::vec4 &a = gridVertices[v1Index]; - glm::vec4 &b = gridVertices[v2Index]; +glm::vec3 marching_cubes_grid::intersection(int v1Index, int v2Index, float minFieldValue) { + glm::vec4 &a = grid_vertices[v1Index]; + glm::vec4 &b = grid_vertices[v2Index]; if (a.w != b.w) { float alpha = (minFieldValue - a.w) / (b.w - a.w); @@ -174,7 +174,7 @@ glm::vec3 MarchingCubesGrid::intersection(int v1Index, int v2Index, float minFie } -void MarchingCubesGrid::addResultingFacets(mesh &m, int cellType) { +void marching_cubes_grid::add_resulting_facets(mesh &m, int cellType) { facet f{}; vertex v{}; int vertexOffset = m.vertices.size(); @@ -182,7 +182,7 @@ void MarchingCubesGrid::addResultingFacets(mesh &m, int cellType) { for (int n = 0; triTable[cellType][n] != -1; n += 3) { for (int i = 0; i < 3; i++) { - v.position = intersectionVertices[triTable[cellType][n + 2 - i]]; + v.position = intersection_vertices[triTable[cellType][n + 2 - i]]; m.vertices.push_back(v); } @@ -194,7 +194,7 @@ void MarchingCubesGrid::addResultingFacets(mesh &m, int cellType) { } -float ForceField::getFieldValueAt(const glm::vec3 &position) const { +float force_field::get_field_value_at(const glm::vec3 &position) const { float result = 0; for (auto &e: emitters) { @@ -206,7 +206,7 @@ float ForceField::getFieldValueAt(const glm::vec3 &position) const { } -glm::vec3 ForceField::getFieldNormalAt(const glm::vec3 &position) const { +glm::vec3 force_field::get_field_normal_at(const glm::vec3 &position) const { // Hello blackpawn! http://www.blackpawn.com/texts/metanormals/default.html glm::vec3 normal = glm::vec3(0); diff --git a/src/demo/demo_part_marching_cubes.h b/src/demo/demo_part_marching_cubes.h index 7ec6d40..a8c1c6c 100644 --- a/src/demo/demo_part_marching_cubes.h +++ b/src/demo/demo_part_marching_cubes.h @@ -6,14 +6,14 @@ BEGIN_NAMESPACE -struct ForceField { - float getFieldValueAt(const glm::vec3 &position) const; - glm::vec3 getFieldNormalAt(const glm::vec3 &position) const; +struct force_field { + float get_field_value_at(const glm::vec3& position) const; + glm::vec3 get_field_normal_at(const glm::vec3& position) const; std::vector emitters; // vec4 = position + strength }; -struct MarchingCubesGrid { +struct marching_cubes_grid { int xCells = 60; int yCells = 60; int zCells = 60; @@ -28,31 +28,31 @@ struct MarchingCubesGrid { float zMax = 2; // .w will hold field value for code size optimisation purposes - std::vector gridVertices; + std::vector grid_vertices; - void evaluateForces(ForceField &field); - void triangulate(mesh &m, float minFieldValue); + void evaluate_forces(force_field& field); + void triangulate(mesh& m, float minFieldValue); private: - void calculateCellVertices(int x, int y, int z); - int classifyCell(float minFieldValue); - void calculateIntersectionVertices(int cellType, float minFieldValue); - void addResultingFacets(mesh &m, int cellType); + void calculate_cell_vertices(int x, int y, int z); + int classify_cell(float minFieldValue); + void calculate_intersection_vertices(int cellType, float minFieldValue); + void add_resulting_facets(mesh& m, int cellType); glm::vec3 intersection(int v1Index, int v2Index, float minFieldValue); - int cubeVertexIndices[8]; - glm::vec3 intersectionVertices[12]; + int cube_vertex_indices[8]; + glm::vec3 intersection_vertices[12]; }; -struct DemoPartMarchingCubes : DemoPart { - DemoPartMarchingCubes(std::shared_ptr affectedMesh); +struct demo_part_marching_cubes : demo_part { + explicit demo_part_marching_cubes(std::shared_ptr affected_mesh); - void process(float normalizedTime) override; + void process(float normalized_time) override; - MarchingCubesGrid grid; - ForceField field; - float minFieldValue = 2.6; + marching_cubes_grid grid; + force_field field; + float min_field_value = 2.6; std::shared_ptr mesh_; }; diff --git a/src/demo/demo_part_render_to_texture.cpp b/src/demo/demo_part_render_to_texture.cpp index fee39e9..b411e31 100644 --- a/src/demo/demo_part_render_to_texture.cpp +++ b/src/demo/demo_part_render_to_texture.cpp @@ -3,12 +3,12 @@ BEGIN_NAMESPACE -DemoPartRenderToTexture::DemoPartRenderToTexture(int s, RenderToTextureAction a) +demo_part_render_to_texture::demo_part_render_to_texture(int s, render_to_texture_action a) : slot(s), action(a) { } -void DemoPartRenderToTexture::process(float normalizedTime) { - if (action == RenderToTextureAction::Start) +void demo_part_render_to_texture::process(float normalizedTime) { + if (action == render_to_texture_action::start) demo_data::fbos[slot]->use(); else demo_data::fbos[slot]->unuse(); diff --git a/src/demo/demo_part_render_to_texture.h b/src/demo/demo_part_render_to_texture.h index d71d326..1d24c50 100644 --- a/src/demo/demo_part_render_to_texture.h +++ b/src/demo/demo_part_render_to_texture.h @@ -4,19 +4,18 @@ BEGIN_NAMESPACE -enum class RenderToTextureAction { - Start, - Stop +enum class render_to_texture_action { + start, + stop }; -struct DemoPartRenderToTexture : DemoPart { +struct demo_part_render_to_texture : demo_part { + demo_part_render_to_texture(int slot, render_to_texture_action action); - DemoPartRenderToTexture(int slot, RenderToTextureAction action); - - void process(float normalizedTime) override; + void process(float normalized_time) override; int slot; - RenderToTextureAction action; + render_to_texture_action action; }; END_NAMESPACE \ No newline at end of file diff --git a/src/demo/demo_part_scene.cpp b/src/demo/demo_part_scene.cpp index ae66d97..fbc7420 100644 --- a/src/demo/demo_part_scene.cpp +++ b/src/demo/demo_part_scene.cpp @@ -7,16 +7,13 @@ BEGIN_NAMESPACE -DemoPartScene::DemoPartScene() { +demo_part_scene::demo_part_scene() { renderer = std::make_shared(); } -DemoPartScene::~DemoPartScene() { -} - -void DemoPartScene::process(float normalizedTime) { +void demo_part_scene::process(float normalized_time) { if (scene_->animation) - scene_->animation->set_at_time(normalizedTime); + scene_->animation->set_at_time(normalized_time); if (scene_->tree) { scene_->tree->transform(); diff --git a/src/demo/demo_part_scene.h b/src/demo/demo_part_scene.h index b4f02fc..bbba90e 100644 --- a/src/demo/demo_part_scene.h +++ b/src/demo/demo_part_scene.h @@ -9,27 +9,28 @@ BEGIN_NAMESPACE -struct DemoPartScene : DemoPart { +struct demo_part_scene : demo_part { - DemoPartScene(); - virtual ~DemoPartScene(); + demo_part_scene(); + ~demo_part_scene() = default; + + void process(float normalized_time) override; std::shared_ptr renderer; std::shared_ptr scene_; std::string cameraName; std::string lightName; - float animationStartTime; // normalized time, [0-1] - float animationEndTime; // normalized time, [0-1] + float animationStartTime = 0; // normalized time, [0-1] + + float animationEndTime = 1.0; // normalized time, [0-1] + GLuint fboID = 0; + GLuint shadowMapTexID = 0; + std::shared_ptr firstPassShadowShader; - GLuint fboID; - GLuint shadowMapTexID; - std::shared_ptr firstPassShadowShader; std::shared_ptr firstPassShadowMaterial; + std::shared_ptr secondPassShadowShader; - std::shared_ptr secondPassShadowShader; std::shared_ptr secondPassShadowMaterial; - - void process(float normalizedTime) override; }; END_NAMESPACE diff --git a/src/demo/demo_scene.h b/src/demo/demo_scene.h index a3ead2b..7ec6234 100644 --- a/src/demo/demo_scene.h +++ b/src/demo/demo_scene.h @@ -14,7 +14,7 @@ #include "glm/gtx/transform.hpp" #include "glm/gtc/matrix_transform.hpp" -#include "shader.h" +#include "shader_program.h" #include "texture.h" diff --git a/src/demo_data.cpp b/src/demo_data.cpp index b740c54..7b0731e 100644 --- a/src/demo_data.cpp +++ b/src/demo_data.cpp @@ -3,12 +3,12 @@ BEGIN_NAMESPACE std::vector> demo_data::textures; -std::vector> demo_data::shaders; +std::vector> demo_data::shaders; std::vector> demo_data::materials; std::vector> demo_data::meshes; std::vector> demo_data::fbos; -int demo_data::screen_width = 1024; -int demo_data::screen_height = 768; +int demo_data::screen_width = 1024 * 2; +int demo_data::screen_height = 768 * 2; END_NAMESPACE \ No newline at end of file diff --git a/src/demo_data.h b/src/demo_data.h index 2ae2254..68a30d1 100644 --- a/src/demo_data.h +++ b/src/demo_data.h @@ -10,7 +10,7 @@ BEGIN_NAMESPACE struct demo_data { static std::vector> textures; - static std::vector> shaders; + static std::vector> shaders; static std::vector> materials; static std::vector> meshes; static std::vector> fbos; diff --git a/src/fbo.cpp b/src/fbo.cpp index 92b4184..2e6cb94 100644 --- a/src/fbo.cpp +++ b/src/fbo.cpp @@ -24,8 +24,7 @@ fbo::fbo(int w, int h) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, color_buffer_id, - 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, color_buffer_id, 0); glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer_id); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); @@ -52,7 +51,7 @@ void fbo::use() { old_width = demo_data::screen_width; old_height = demo_data::screen_height; - demo_data::screen_height = width; + demo_data::screen_width = width; demo_data::screen_height = height; glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_id); diff --git a/src/light_node.h b/src/light_node.h index 243521d..3f79fa7 100644 --- a/src/light_node.h +++ b/src/light_node.h @@ -13,7 +13,7 @@ enum class light_type { }; struct light_node : scene_node { - light_node(light_type type); + explicit light_node(light_type type); void calculate_local_transform() override; diff --git a/src/material.cpp b/src/material.cpp index fbbb440..5b40792 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -29,7 +29,7 @@ GLenum to_gl(const blending_constant &c) { void set_material(std::shared_ptr &mat) { // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - mat->shader_->use(); + mat->shader->bind(); // if (material->textures[TextureRole::Diffuse]) { // std::cout << "CAN has diffuse texture!!!!!!!!!11" << std::endl; @@ -86,7 +86,7 @@ void unset_material(std::shared_ptr &mat) { // textureUnit++; // } - mat->shader_->unuse(); + mat->shader->unbind(); if (mat->transparent) glDisable(GL_BLEND); diff --git a/src/material.h b/src/material.h index c305f87..c0b1572 100644 --- a/src/material.h +++ b/src/material.h @@ -3,7 +3,7 @@ #include #include #include "texture.h" -#include "shader.h" +#include "shader_program.h" #include "glm/glm.hpp" BEGIN_NAMESPACE @@ -52,11 +52,11 @@ struct material { blending_constant blend_dst_fact = blending_constant::one_minus_src_alpha; fill_mode_type fill_mode = fill_mode_type::solid; - std::shared_ptr shader_; + std::shared_ptr shader; texture_map textures; }; -void set_material(std::shared_ptr &material); -void unset_material(std::shared_ptr &material); +void set_material(std::shared_ptr& material); +void unset_material(std::shared_ptr& material); END_NAMESPACE diff --git a/src/mesh_node.h b/src/mesh_node.h index 0724ad1..adf461c 100644 --- a/src/mesh_node.h +++ b/src/mesh_node.h @@ -8,7 +8,7 @@ BEGIN_NAMESPACE struct mesh_node : scene_node { mesh_node(); - mesh_node(std::string name); + explicit mesh_node(std::string name); std::shared_ptr mesh_; std::shared_ptr material_; diff --git a/src/particles.cpp b/src/particles.cpp new file mode 100644 index 0000000..8568bfd --- /dev/null +++ b/src/particles.cpp @@ -0,0 +1,225 @@ +#include "particles.h" + +BEGIN_NAMESPACE + +particle_emitter::particle_emitter() { + to_spawn = 0; + start_size = 1.0f; + end_size = 1.0f; +} + +particle *particle_emitter::new_particle() { + particle *p; + if (dead_particles.empty()) { + p = new particle{}; + } else { + p = dead_particles.back(); + dead_particles.pop_back(); + } + + particles.push_back(p); + return p; +} + +void particle_emitter::update(float elapsed_ms) { + float factor = elapsed_ms / 1000.0f; + + for (auto p : particles) { + p->old_pos = p->position; + p->position += p->velocity * factor; + p->life -= life_decay * factor; + p->color = glm::mix(start_colour, end_colour, p->life); + p->size = glm::mix(start_size, end_size, p->life); + } + + // move dead particles to the dead list + auto pit = particles.begin(); + while (pit != particles.end()) { + if ((*pit)->life <= 0.0) { + dead_particles.push_back(*pit); + pit = particles.erase(pit); + } else { + ++pit; + } + } + + // spawn if needed + to_spawn += factor * emission_rate; + auto new_particles = static_cast(to_spawn); + + for (auto i = 0; i < new_particles; i++) { + particle *p = new_particle(); + spawn(p); + } + to_spawn -= static_cast(new_particles); +} + + +void particle_system::update(float elapsed_ms) { + particles.clear(); + + for (auto& emitter: emitters) { + emitter->update(elapsed_ms); + std::copy(emitter->particles.begin(), emitter->particles.end(), std::back_inserter(particles)); + } + + for (auto& modifier: modifiers) { + for (auto& particle: particles) { + modifier->affect_particle(particle, elapsed_ms); + } + } +} + + +void particle_system::render() { + + // draw trail + // draw head + +// Matrix mat; +// mat.fromGL(GL_MODELVIEW_MATRIX); +// +// Vector3D a(mat._mat[0], mat._mat[4], mat._mat[8]); +// Vector3D b(mat._mat[1], mat._mat[5], mat._mat[9]); +// +// Vector3D pos[4]; +// pos[0] = (-a - b); +// pos[1] = (a - b); +// pos[2] = (a + b); +// pos[3] = (-a + b); +// +// +// glEnable(GL_COLOR_MATERIAL); +// glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); +// +// glBegin(GL_QUADS); +// +// for (ParticleList::iterator it = particles.begin(); it != particles.end(); it++) { +// Particle *p = (*it); +// +// glColor4d(p->color.r, p->color.g, p->color.b, p->color.a); +// +// glTexCoord2f(1.0f, 1.0f); +// glVertex3d(pos[0].x * p->size + p->position.x, pos[0].y * p->size + p->position.y, pos[0].z * p->size + p->position.z); +// +// glTexCoord2f(0.0f, 1.0f); +// glVertex3d(pos[1].x * p->size + p->position.x, pos[1].y * p->size + p->position.y, pos[1].z * p->size + p->position.z); +// +// glTexCoord2f(0.0f, 0.0f); +// glVertex3d(pos[2].x * p->size + p->position.x, pos[2].y * p->size + p->position.y, pos[2].z * p->size + p->position.z); +// +// glTexCoord2f(1.0f, 0.0f); +// glVertex3d(pos[3].x * p->size + p->position.x, pos[3].y * p->size + p->position.y, pos[3].z * p->size + p->position.z); +// } +// +// glEnd(); +// +// // +// +// glDisable(GL_TEXTURE_2D); +// glBegin(GL_LINES); +// +// for (ParticleList::iterator it = particles.begin(); it != particles.end(); it++) { +// Particle *p = (*it); +// +// glColor4d(p->color.r, p->color.g, p->color.b, p->color.a); +// +// glVertex3d(p->previousPosition.x, p->previousPosition.y, p->previousPosition.z); +// glVertex3d(p->position.x, p->position.y, p->position.z); +// } +// +// glEnd(); +// +// +// glDisable(GL_COLOR_MATERIAL); + + + /* + + glEnable( GL_COLOR_MATERIAL ); + glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); + + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE ); + + + // This is how will our point sprite's size will be modified by + // distance from the viewer + float quadratic[] = { 1.0f, 0.0f, 0.01f }; + glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic ); + + // Query for the max point size supported by the hardware + float maxSize = 0.0f; + glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); + + // Clamp size to 100.0f or the sprites could get a little too big on some + // of the newer graphic cards. My ATI card at home supports a max point + // size of 1024.0f! + maxSize = min( maxSize, 100.0f ); + glPointSize( maxSize ); + + // The alpha of a point is calculated to allow the fading of points + // instead of shrinking them past a defined threshold size. The threshold + // is defined by GL_POINT_FADE_THRESHOLD_SIZE_ARB and is not clamped to + // the minimum and maximum point sizes. + glPointParameterfARB( GL_POINT_FADE_THRESHOLD_SIZE_ARB, 60.0f ); + + glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 1.0f ); + glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, maxSize ); + + // Specify point sprite texture coordinate replacement mode for each + // texture unit + glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE ); + + glEnable( GL_POINT_SPRITE_ARB ); + + + glBegin( GL_POINTS ); + for ( ParticleList::iterator it = particles.begin(); it != particles.end(); it++ ) { + Particle *p = (*it); + glColor4d( p->color.r, p->color.g, p->color.b, p->color.a ); + glVertex3d( p->position.x, p->position.y, p->position.z ); + } + glEnd(); + + glDisable( GL_POINT_SPRITE_ARB ); + glDisable( GL_BLEND ); + + glDisable( GL_COLOR_MATERIAL ); + */ +} + +dot_particle_emitter::dot_particle_emitter() { + emission_rate = 30.0f; + life_decay = 0.1; +} + +void dot_particle_emitter::spawn(acidrain::particle *p) { + if (nullptr == p) { + return; + } + p->position = {0, 0, 0}; + p->color = {rand_in_range(0, 1), rand_in_range(0, 1), rand_in_range(0, 1), 1.0}; + p->velocity = glm::normalize(glm::vec3(rand_in_range(-1, 1), rand_in_range(-1, 1), rand_in_range(-1, 1))); + // p->velocity *= 10; + + p->life = 1.0; +} + +END_NAMESPACE + +void acidrain::particle_attractor::init(glm::vec3& center, float s) { + attractor_center = center; + strength = s; +} + +void acidrain::particle_attractor::affect_particle(acidrain::particle *p, float elapsed_ms) { + float factor = elapsed_ms / 1000.0f; + + glm::vec3 attract_direction = attractor_center - p->position; + float distance_to_center = glm::length(attract_direction); + + float amount = 1.0f / (distance_to_center * distance_to_center) * strength; + p->velocity += attract_direction * amount * factor; +} + diff --git a/src/particles.h b/src/particles.h new file mode 100644 index 0000000..223fc72 --- /dev/null +++ b/src/particles.h @@ -0,0 +1,76 @@ +#pragma once + +#include "defines.h" +#include "colour.h" +#include +#include + +BEGIN_NAMESPACE + +struct particle; +struct particle_emitter; +struct particle_modifier; + +using particle_list = std::vector; +using particle_emitter_list = std::vector; +using particle_modifier_list = std::vector; + +struct particle { + glm::vec3 position; + glm::vec3 old_pos; + glm::vec3 velocity; + colour color; + float life; + float size; +}; + +struct particle_emitter { + particle_emitter(); + virtual ~particle_emitter() = default; + + particle *new_particle(); + void update(float elapsed_ms); + + virtual void spawn(particle *p) = 0; + + particle_list particles; + particle_list dead_particles; + + glm::vec3 position{}; + float emission_rate{}; // particles per second + float to_spawn; + float life_decay{}; + colour start_colour{}; + colour end_colour{}; + float start_size; + float end_size; +}; + +struct particle_modifier { + virtual void affect_particle(particle *p, float elapsed_ms) = 0; +}; + +struct particle_system { + void update(float elapsed_ms); + void render(); + + particle_list particles; + particle_emitter_list emitters; + particle_modifier_list modifiers; +}; + +struct dot_particle_emitter : particle_emitter { + dot_particle_emitter(); + void spawn(particle *p) override; +}; + + +struct particle_attractor : particle_modifier { + void init(glm::vec3& center, float strength_); + void affect_particle(particle *p, float elapsed_ms) override; + + glm::vec3 attractor_center; + float strength; +}; + +END_NAMESPACE diff --git a/src/peripherals.h b/src/peripherals.h index c553790..ebb002c 100644 --- a/src/peripherals.h +++ b/src/peripherals.h @@ -5,7 +5,7 @@ BEGIN_NAMESPACE class peripherals { public: - virtual bool init() = 0; + virtual bool init(uint16_t width, uint16_t height, const char* title, bool fullscreen = false) = 0; virtual void swap_buffers() = 0; virtual void poll_events() = 0; virtual bool should_close() = 0; diff --git a/src/peripherals_glfw.cpp b/src/peripherals_glfw.cpp index 7cd164c..01c6cc6 100644 --- a/src/peripherals_glfw.cpp +++ b/src/peripherals_glfw.cpp @@ -1,7 +1,6 @@ #include "peripherals_glfw.h" #include #include -#include "demo_data.h" #include "defines.h" BEGIN_NAMESPACE @@ -20,7 +19,7 @@ static void key_callback(GLFWwindow *window, int key, int scancode, int action, } } -bool peripherals_glfw::init() { +bool peripherals_glfw::init(uint16_t width, uint16_t height, const char *title, bool fullscreen) { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); @@ -31,10 +30,9 @@ bool peripherals_glfw::init() { glfwSetErrorCallback(error_callback); - bool fullscreen = false; - window = glfwCreateWindow(demo_data::screen_width, - demo_data::screen_height, - "Demo", + window = glfwCreateWindow(width, + height, + title, fullscreen ? glfwGetPrimaryMonitor() : nullptr, nullptr); if (window == nullptr) { diff --git a/src/peripherals_glfw.h b/src/peripherals_glfw.h index fe3ab79..5f06301 100644 --- a/src/peripherals_glfw.h +++ b/src/peripherals_glfw.h @@ -9,7 +9,7 @@ BEGIN_NAMESPACE class peripherals_glfw : public peripherals { public: - bool init() override; + bool init(uint16_t width, uint16_t height, const char* title, bool fullscreen = false) override; void swap_buffers() override; void poll_events() override; bool should_close() override; diff --git a/src/perlin.cpp b/src/perlin.cpp new file mode 100644 index 0000000..3dc24fb --- /dev/null +++ b/src/perlin.cpp @@ -0,0 +1,263 @@ +#include "perlin.h" +#include + +// Thank you, Ken Perlin + +BEGIN_NAMESPACE + +namespace perlin { + +#define B 0x100 +#define BM 0xff +#define N 0x1000 +#define NP 12 /* 2^N */ +#define NM 0xfff + +#define s_curve(t) ( t * t * (3. - 2. * t) ) +#define lerp(t, a, b) ( a + t * (b - a) ) +#define setup(i, b0, b1, r0, r1)\ + t = vec[i] + N;\ + b0 = ((int)t) & BM;\ + b1 = (b0+1) & BM;\ + r0 = t - (int)t;\ + r1 = r0 - 1.; +#define at2(rx, ry) ( rx * q[0] + ry * q[1] ) +#define at3(rx, ry, rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) + + +/* Coherent noise function over 1, 2 or 3 dimensions */ +/* (copyright Ken Perlin) */ + +static int p[B + B + 2]; +static double g3[B + B + 2][3]; +static double g2[B + B + 2][2]; +static double g1[B + B + 2]; +static int start = 1; + +double noise1(double arg) { + int bx0, bx1; + double rx0, rx1, sx, t, u, v, vec[1]; + + vec[0] = arg; + if (start) { + start = 0; + init(); + } + + setup(0, bx0, bx1, rx0, rx1); + + sx = s_curve(rx0); + u = rx0 * g1[p[bx0]]; + v = rx1 * g1[p[bx1]]; + + return (lerp(sx, u, v)); +} + +double noise2(double vec[2]) { + int bx0, bx1, by0, by1, b00, b10, b01, b11; + double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; + int i, j; + + if (start) { + start = 0; + init(); + } + + setup(0, bx0, bx1, rx0, rx1); + setup(1, by0, by1, ry0, ry1); + + i = p[bx0]; + j = p[bx1]; + + b00 = p[i + by0]; + b10 = p[j + by0]; + b01 = p[i + by1]; + b11 = p[j + by1]; + + sx = s_curve(rx0); + sy = s_curve(ry0); + + q = g2[b00]; + u = at2(rx0, ry0); + q = g2[b10]; + v = at2(rx1, ry0); + a = lerp(sx, u, v); + + q = g2[b01]; + u = at2(rx0, ry1); + q = g2[b11]; + v = at2(rx1, ry1); + b = lerp(sx, u, v); + + return lerp(sy, a, b); +} + +double noise3(double vec[3]) { + int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; + double rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; + int i, j; + + if (start) { + start = 0; + init(); + } + + setup(0, bx0, bx1, rx0, rx1); + setup(1, by0, by1, ry0, ry1); + setup(2, bz0, bz1, rz0, rz1); + + i = p[bx0]; + j = p[bx1]; + + b00 = p[i + by0]; + b10 = p[j + by0]; + b01 = p[i + by1]; + b11 = p[j + by1]; + + t = s_curve(rx0); + sy = s_curve(ry0); + sz = s_curve(rz0); + + q = g3[b00 + bz0]; + u = at3(rx0, ry0, rz0); + q = g3[b10 + bz0]; + v = at3(rx1, ry0, rz0); + a = lerp(t, u, v); + + q = g3[b01 + bz0]; + u = at3(rx0, ry1, rz0); + q = g3[b11 + bz0]; + v = at3(rx1, ry1, rz0); + b = lerp(t, u, v); + + c = lerp(sy, a, b); + + q = g3[b00 + bz1]; + u = at3(rx0, ry0, rz1); + q = g3[b10 + bz1]; + v = at3(rx1, ry0, rz1); + a = lerp(t, u, v); + + q = g3[b01 + bz1]; + u = at3(rx0, ry1, rz1); + q = g3[b11 + bz1]; + v = at3(rx1, ry1, rz1); + b = lerp(t, u, v); + + d = lerp(sy, a, b); + + return lerp(sz, c, d); +} + +void normalize2(double v[2]) { + double s; + + s = sqrt(v[0] * v[0] + v[1] * v[1]); + v[0] = v[0] / s; + v[1] = v[1] / s; +} + +void normalize3(double v[3]) { + double s; + + s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + v[0] = v[0] / s; + v[1] = v[1] / s; + v[2] = v[2] / s; +} + +/* --- My harmonic summing functions - PDB --------------------------*/ + +/* +In what follows "alpha" is the weight when the sum is formed. +Typically it is 2, As this approaches 1 the function is noisier. +"beta" is the harmonic scaling/spacing, typically 2. +*/ + +double noise1D(double x, double alpha, double beta, int n) { + int i; + double val, sum = 0; + double p, scale = 1; + + p = x; + for (i = 0; i < n; i++) { + val = noise1(p); + sum += val / scale; + scale *= alpha; + p *= beta; + } + return (sum); +} + +double noise2D(double x, double y, double alpha, double beta, int n) { + int i; + double val, sum = 0; + double p[2], scale = 1; + + p[0] = x; + p[1] = y; + for (i = 0; i < n; i++) { + val = noise2(p); + sum += val / scale; + scale *= alpha; + p[0] *= beta; + p[1] *= beta; + } + return (sum); +} + +double noise3D(double x, double y, double z, double alpha, double beta, int n) { + int i; + double val, sum = 0; + double p[3], scale = 1; + + p[0] = x; + p[1] = y; + p[2] = z; + for (i = 0; i < n; i++) { + val = noise3(p); + sum += val / scale; + scale *= alpha; + p[0] *= beta; + p[1] *= beta; + p[2] *= beta; + } + return (sum); +} + +void init() { + int i, j, k; + + for (i = 0; i < B; i++) { + p[i] = i; + g1[i] = (double) ((rand() % (B + B)) - B) / B; + + for (j = 0; j < 2; j++) + g2[i][j] = (double) ((rand() % (B + B)) - B) / B; + normalize2(g2[i]); + + for (j = 0; j < 3; j++) + g3[i][j] = (double) ((rand() % (B + B)) - B) / B; + normalize3(g3[i]); + } + + while (--i) { + k = p[i]; + p[i] = p[j = rand() % B]; + p[j] = k; + } + + for (i = 0; i < B + 2; i++) { + p[B + i] = p[i]; + g1[B + i] = g1[i]; + for (j = 0; j < 2; j++) + g2[B + i][j] = g2[i][j]; + for (j = 0; j < 3; j++) + g3[B + i][j] = g3[i][j]; + } +} + + +} + +END_NAMESPACE \ No newline at end of file diff --git a/src/perlin.h b/src/perlin.h new file mode 100644 index 0000000..8b77297 --- /dev/null +++ b/src/perlin.h @@ -0,0 +1,14 @@ +#pragma once + +#include "defines.h" + +BEGIN_NAMESPACE +namespace perlin { + +void init(); + +double noise1D(double x, double alpha, double beta, int n); +double noise2D(double x, double y, double alpha, double beta, int n); +double noise3D(double x, double y, double z, double alpha, double beta, int n); +} +END_NAMESPACE \ No newline at end of file diff --git a/src/scene_node.cpp b/src/scene_node.cpp index 0a7130a..57f8623 100644 --- a/src/scene_node.cpp +++ b/src/scene_node.cpp @@ -15,24 +15,31 @@ void scene_node::calculate_local_transform() { * glm::scale(glm::mat4(1.0f), scale); } -void scene_node::apply_parent_transform(const glm::mat4 &parent_transform) { +void scene_node::apply_parent_transform(const glm::mat4& parent_transform) { model_to_world_space_matrix = parent_transform * local_to_parent_space_matrix; - for (auto &child: children) + for (auto& child: children) child->apply_parent_transform(model_to_world_space_matrix); } -mesh_node &scene_node::as_mesh_node() { +mesh_node& scene_node::as_mesh_node() { return *static_cast(this); } -light_node &scene_node::as_light_node() { +light_node& scene_node::as_light_node() { return *static_cast(this); } -camera_node &scene_node::as_camera_node() { +camera_node& scene_node::as_camera_node() { return *static_cast(this); } +static size_t current_id = 0; + +scene_node::scene_node() { + id = current_id++; + rotation = glm::angleAxis(0.0f, glm::vec3(1, 0, 0)); +} + END_NAMESPACE diff --git a/src/scene_node.h b/src/scene_node.h index 077d7b7..8b433f1 100644 --- a/src/scene_node.h +++ b/src/scene_node.h @@ -21,14 +21,16 @@ struct light_node; struct camera_node; struct scene_node { + scene_node(); + virtual void calculate_local_transform(); - void apply_parent_transform(const glm::mat4 &parent_transform); + void apply_parent_transform(const glm::mat4& parent_transform); - mesh_node &as_mesh_node(); - light_node &as_light_node(); - camera_node &as_camera_node(); + mesh_node& as_mesh_node(); + light_node& as_light_node(); + camera_node& as_camera_node(); - int id; + size_t id; std::string name; scene_node_type type; // We rely on type comparison instead of dynamic casting because comparing types is much faster diff --git a/src/scene_renderer.cpp b/src/scene_renderer.cpp index 2b48e99..b841da9 100644 --- a/src/scene_renderer.cpp +++ b/src/scene_renderer.cpp @@ -1,6 +1,6 @@ #include "scene_renderer.h" #include "light_node.h" -#include "shader.h" +#include "shader_program.h" #include "material.h" #include "mesh_node.h" #include "demo_data.h" @@ -277,20 +277,20 @@ scene_renderer::scene_renderer() glGenFramebuffers(1, &fbo_id); - first_pass_shadow_shader = std::make_shared(vs, ps); + first_pass_shadow_shader = std::make_shared(vs, ps); first_pass_shadow_material = std::make_shared(); - first_pass_shadow_material->shader_ = first_pass_shadow_shader; + first_pass_shadow_material->shader = first_pass_shadow_shader; first_pass_shadow_material->zbuffer_write = true; first_pass_shadow_material->zbuffer_test = true; first_pass_shadow_material->transparent = false; first_pass_shadow_material->cull_faces = true; first_pass_shadow_material->cull_front_faces = false; - second_pass_shadow_shader = std::make_shared(vs3, ps3); + second_pass_shadow_shader = std::make_shared(vs3, ps3); second_pass_shadow_material = std::make_shared(); - second_pass_shadow_material->shader_ = second_pass_shadow_shader; + second_pass_shadow_material->shader = second_pass_shadow_shader; second_pass_shadow_material->diffuse = glm::vec4(1, 0, 0, 1); second_pass_shadow_material->zbuffer_write = true; second_pass_shadow_material->zbuffer_test = true; @@ -299,21 +299,34 @@ scene_renderer::scene_renderer() second_pass_shadow_material->flat_shaded = false; } -void scene_renderer::attach_depth_texture(texture &text) const { +void scene_renderer::attach_depth_texture(texture& text) const { glBindFramebuffer(GL_FRAMEBUFFER, fbo_id); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, text.get_id(), 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } -void scene_renderer::render(const scene_tree &tree, const std::string &cameraName) { -// for (auto &node: scene.lights) { -// light_node &light = node->as_light_node(); -// glActiveTexture(GL_TEXTURE0); -// render_shadow_map(scene, light); -// } -std::shared_ptr camNode = tree.node_by_name_and_type(cameraName, scene_node_type::camera); - camera_node &camera = camNode->as_camera_node(); +std::string to_string(const glm::vec3& v) { + std::stringstream ss; + ss << "{x:" << v.x << ", y:" << v.y << ", z:" << v.z << "}"; + return ss.str(); +} + +std::string to_string(const glm::quat& v) { + std::stringstream ss; + ss << "{x:" << v.x << ", y:" << v.y << ", z:" << v.z << ", w:" << v.w << "}"; + return ss.str(); +} + +void scene_renderer::render(const scene_tree& tree, const std::string& cam_name) { + for (auto& node: tree.lights) { + light_node& light = node->as_light_node(); + glActiveTexture(GL_TEXTURE0); + render_shadow_map(tree, light); + } + + std::shared_ptr cam_node = tree.node_by_name_and_type(cam_name, scene_node_type::camera); + camera_node& camera = cam_node->as_camera_node(); shader_consts.set(uniforms::ViewMatrix, camera.view_matrix); shader_consts.set(uniforms::ProjectionMatrix, camera.projection_matrix); @@ -323,81 +336,87 @@ std::shared_ptr camNode = tree.node_by_name_and_type(cameraName, sce set_material(second_pass_shadow_material); - int lightIndex = 0; - for (auto &node: tree.lights) { - light_node &light = node->as_light_node(); + int light_index = 0; + for (auto& node: tree.lights) { + light_node& light = node->as_light_node(); - shader_consts.set(uniforms::WorldToLightMatrix, light.world_to_light_matrix[0], lightIndex); - shader_consts.set(uniforms::LightProjectionMatrix, light.light_projection_matrix[0], lightIndex); - shader_consts.set(uniforms::ShadowMatrix, light.final_shadow_map_matrix[0], lightIndex); + shader_consts.set(uniforms::WorldToLightMatrix, light.world_to_light_matrix[0], light_index); + shader_consts.set(uniforms::LightProjectionMatrix, light.light_projection_matrix[0], light_index); + shader_consts.set(uniforms::ShadowMatrix, light.final_shadow_map_matrix[0], light_index); shader_consts.set(uniforms::ShadowBiasMatrix, light.shadow_map_bias_matrix); - glm::vec3 lightPositionInEyeSpace = light.position - camera.position; - shader_consts.set(uniforms::LightPosition, lightPositionInEyeSpace, lightIndex); + glm::vec3 light_pos_in_eye_space = light.position - camera.position; + shader_consts.set(uniforms::LightPosition, light_pos_in_eye_space, light_index); - glm::vec3 lightTargetInEyeSpace = light.spot_target - camera.position; - shader_consts.set(uniforms::LightTarget, lightTargetInEyeSpace, lightIndex); + glm::vec3 light_target_in_eye_space = light.spot_target - camera.position; + shader_consts.set(uniforms::LightTarget, light_target_in_eye_space, light_index); - shader_consts.set(uniforms::LightAmbient, light.ambient, lightIndex); - shader_consts.set(uniforms::LightDiffuse, light.diffuse, lightIndex); - shader_consts.set(uniforms::LightSpecular, light.specular, lightIndex); + shader_consts.set(uniforms::LightAmbient, light.ambient, light_index); + shader_consts.set(uniforms::LightDiffuse, light.diffuse, light_index); + shader_consts.set(uniforms::LightSpecular, light.specular, light_index); - shader_consts.set(uniforms::LightSpotCutoff, light.spot_cutoff, lightIndex); - shader_consts.set(uniforms::LightSpotExponent, light.spot_exponent, lightIndex); - shader_consts.set(uniforms::LightAttenuation, light.attenuation, lightIndex); + shader_consts.set(uniforms::LightSpotCutoff, light.spot_cutoff, light_index); + shader_consts.set(uniforms::LightSpotExponent, light.spot_exponent, light_index); + shader_consts.set(uniforms::LightAttenuation, light.attenuation, light_index); - glActiveTexture(GL_TEXTURE0 + 4 + lightIndex); + glActiveTexture(GL_TEXTURE0 + 4 + light_index); glBindTexture(GL_TEXTURE_2D, light.shadow_map[0]->get_id()); - if (lightIndex == 0) { - shader_consts.set(uniforms::ShadowMap1, lightIndex + 4); - } else if (lightIndex == 1) { - shader_consts.set(uniforms::ShadowMap2, lightIndex + 4); - } else if (lightIndex == 2) { - shader_consts.set(uniforms::ShadowMap3, lightIndex + 4); - } else if (lightIndex == 3) { - shader_consts.set(uniforms::ShadowMap4, lightIndex + 4); + if (light_index == 0) { + shader_consts.set(uniforms::ShadowMap1, light_index + 4); + } else if (light_index == 1) { + shader_consts.set(uniforms::ShadowMap2, light_index + 4); + } else if (light_index == 2) { + shader_consts.set(uniforms::ShadowMap3, light_index + 4); + } else if (light_index == 3) { + shader_consts.set(uniforms::ShadowMap4, light_index + 4); } - lightIndex++; + light_index++; } // draw opaque nodes - for (auto &node: tree.nodes) { + for (auto& node: tree.nodes) { if (node->type == scene_node_type::mesh) { - mesh_node &meshNode = node->as_mesh_node(); + mesh_node& mesh_node = node->as_mesh_node(); - glm::mat3 normalMatrix = glm::inverseTranspose( - glm::mat3(camera.view_matrix * meshNode.model_to_world_space_matrix)); +// if (node->name == "light mesh") { +// LOG(INFO) << "rendering light mesh. position: " << to_string(mesh_node.position) +// << ", scale: " << to_string(mesh_node.scale) +// << ", rotation: " << to_string(mesh_node.rotation); +// } - shader_consts.set(uniforms::ModelToWorldMatrix, meshNode.model_to_world_space_matrix); - shader_consts.set(uniforms::NormalMatrix, normalMatrix); - shader_consts.set(uniforms::MaterialAmbientColor, meshNode.material_->ambient); - shader_consts.set(uniforms::MaterialDiffuseColor, meshNode.material_->diffuse); - shader_consts.set(uniforms::MaterialSpecularColor, meshNode.material_->specular); - shader_consts.set(uniforms::MaterialShininess, meshNode.material_->shininess); + glm::mat3 normal_mat = glm::inverseTranspose( + glm::mat3(camera.view_matrix * mesh_node.model_to_world_space_matrix)); - shader_consts.apply_to(*second_pass_shadow_material->shader_); + shader_consts.set(uniforms::ModelToWorldMatrix, mesh_node.model_to_world_space_matrix); + shader_consts.set(uniforms::NormalMatrix, normal_mat); + shader_consts.set(uniforms::MaterialAmbientColor, mesh_node.material_->ambient); + shader_consts.set(uniforms::MaterialDiffuseColor, mesh_node.material_->diffuse); + shader_consts.set(uniforms::MaterialSpecularColor, mesh_node.material_->specular); + shader_consts.set(uniforms::MaterialShininess, mesh_node.material_->shininess); - if (meshNode.material_->textures[texture_role::diffuse]) { - int textureUnit = 0; - glActiveTexture(GL_TEXTURE0 + textureUnit); - meshNode.material_->textures[texture_role::diffuse]->use(); + shader_consts.apply_to(*second_pass_shadow_material->shader); - second_pass_shadow_material->shader_->setIntUniform(textureUnit, "diffuseMap"); + if (mesh_node.material_->textures[texture_role::diffuse]) { + int texture_unit = 0; + glActiveTexture(GL_TEXTURE0 + texture_unit); + mesh_node.material_->textures[texture_role::diffuse]->use(); + + second_pass_shadow_material->shader->set_int(texture_unit, "diffuseMap"); } else { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); } - meshNode.mesh_->render(second_pass_shadow_material->flat_shaded); + mesh_node.mesh_->render(second_pass_shadow_material->flat_shaded); } } unset_material(second_pass_shadow_material); } -void scene_renderer::render_shadow_map(const scene_tree &scene, light_node &light) { +void scene_renderer::render_shadow_map(const scene_tree& scene, light_node& light) { light.calculate_local_transform(); attach_depth_texture(*light.shadow_map[0]); @@ -416,13 +435,13 @@ void scene_renderer::render_shadow_map(const scene_tree &scene, light_node &ligh set_material(first_pass_shadow_material); // first pass - draw all objects that may cast shadows as seen from light - for (auto &node: scene.nodes) { + for (auto& node: scene.nodes) { if (node->type == scene_node_type::mesh) { - mesh_node &meshNode = node->as_mesh_node(); + mesh_node& meshNode = node->as_mesh_node(); if (!meshNode.material_->transparent && meshNode.material_->cast_shadows) { shader_consts.set(uniforms::ModelToWorldMatrix, meshNode.model_to_world_space_matrix); - shader_consts.apply_to(*first_pass_shadow_material->shader_); + shader_consts.apply_to(*first_pass_shadow_material->shader); meshNode.mesh_->render(first_pass_shadow_material->flat_shaded); } diff --git a/src/scene_renderer.h b/src/scene_renderer.h index 464d266..cc8aa74 100644 --- a/src/scene_renderer.h +++ b/src/scene_renderer.h @@ -6,7 +6,7 @@ BEGIN_NAMESPACE -class shader; +class shader_program; class material; @@ -17,16 +17,16 @@ public: scene_renderer(); - void render(const scene_tree &tree, const std::string &cameraName); + void render(const scene_tree &tree, const std::string &cam_name); private: void attach_depth_texture(texture &text) const; void render_shadow_map(const scene_tree &scene, light_node &light); - std::shared_ptr first_pass_shadow_shader; + std::shared_ptr first_pass_shadow_shader; std::shared_ptr first_pass_shadow_material; - std::shared_ptr second_pass_shadow_shader; + std::shared_ptr second_pass_shadow_shader; std::shared_ptr second_pass_shadow_material; shader_constants shader_consts; diff --git a/src/scene_tree.cpp b/src/scene_tree.cpp index aa837b7..95514ef 100644 --- a/src/scene_tree.cpp +++ b/src/scene_tree.cpp @@ -1,29 +1,31 @@ #include "scene_tree.h" +#include + BEGIN_NAMESPACE -std::shared_ptr scene_tree::nodeById(int id) const { +std::shared_ptr scene_tree::node_by_id(size_t id) const { for (auto& node : nodes) if (node->id == id) return node; - return std::shared_ptr(nullptr); + return {nullptr}; } -std::shared_ptr scene_tree::node_by_name_and_type(std::string name, scene_node_type type) const { +std::shared_ptr scene_tree::node_by_name_and_type(const std::string& name, scene_node_type type) const { for (auto& node : nodes) if (node->name == name && node->type == type) return node; - return std::shared_ptr(nullptr); + return {nullptr}; } void scene_tree::add(std::shared_ptr node) { - add(node, std::shared_ptr(nullptr)); + add(std::move(node), std::shared_ptr(nullptr)); } -void scene_tree::add(std::shared_ptr node, std::shared_ptr parent) { +void scene_tree::add(const std::shared_ptr& node, std::shared_ptr parent) { nodes.push_back(node); node->parent = parent; diff --git a/src/scene_tree.h b/src/scene_tree.h index 2ff71d7..0a10ea3 100644 --- a/src/scene_tree.h +++ b/src/scene_tree.h @@ -8,11 +8,11 @@ BEGIN_NAMESPACE class scene_tree { public: - std::shared_ptr nodeById(int id) const; - std::shared_ptr node_by_name_and_type(std::string name, scene_node_type type) const; + std::shared_ptr node_by_id(size_t id) const; + std::shared_ptr node_by_name_and_type(const std::string& name, scene_node_type type) const; void add(std::shared_ptr node); - void add(std::shared_ptr node, std::shared_ptr parent); + void add(const std::shared_ptr& node, std::shared_ptr parent); void transform(); diff --git a/src/shader.cpp b/src/shader.cpp index 892c222..b197d0e 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -1,4 +1,4 @@ -#include "shader.h" +#include "shader_program.h" #include BEGIN_NAMESPACE @@ -47,7 +47,7 @@ void check_link_error(GLuint program_id) { } } -shader::shader(const char *vs_content, const char *ps_content) +shader_program::shader_program(const char *vs_content, const char *ps_content) : shader_ids{0, 0}, program_id{0} { @@ -117,7 +117,7 @@ shader::shader(const char *vs_content, const char *ps_content) // glUseProgram(program_id); } -shader::~shader() { +shader_program::~shader_program() { glDetachShader(program_id, shader_ids[0]); glDetachShader(program_id, shader_ids[1]); @@ -127,53 +127,53 @@ shader::~shader() { glDeleteProgram(program_id); } -void shader::use() const { +void shader_program::bind() const { glUseProgram(program_id); } -void shader::unuse() const { +void shader_program::unbind() { glUseProgram(0); } -int shader::getUniform(const char *uniformName) { - if (uniform_cache.count(uniformName) == 0) { - uniform_cache[uniformName] = glGetUniformLocation(program_id, uniformName); +int shader_program::get_uniform(const char *name) { + if (uniform_cache.count(name) == 0) { + uniform_cache[name] = glGetUniformLocation(program_id, name); } - return uniform_cache[uniformName]; + return uniform_cache[name]; } -void shader::setMatrix3Uniform(float *matrix, const char *uniformName) { - GLint location = getUniform(uniformName); +void shader_program::set_mat3(float *matrix, const char *uniform_name) { + GLint location = get_uniform(uniform_name); if (location != -1) glUniformMatrix3fv(location, 1, false, matrix); } -void shader::setMatrix4Uniform(float *matrix, const char *uniformName) { - GLint location = getUniform(uniformName); +void shader_program::set_mat4(float *matrix, const char *uniform_name) { + GLint location = get_uniform(uniform_name); if (location != -1) glUniformMatrix4fv(location, 1, false, matrix); } -void shader::setVec3Uniform(float *value, const char *uniformName) { - GLint location = getUniform(uniformName); +void shader_program::set_vec3(float *value, const char *uniform_name) { + GLint location = get_uniform(uniform_name); if (location != -1) glUniform3fv(location, 1, value); } -void shader::setVec4Uniform(float *value, const char *uniformName) { - GLint location = getUniform(uniformName); +void shader_program::set_vec4(float *value, const char *uniform_name) { + GLint location = get_uniform(uniform_name); if (location != -1) glUniform4fv(location, 1, value); } -void shader::setIntUniform(int value, const char *uniformName) { - GLint location = getUniform(uniformName); +void shader_program::set_int(int value, const char *uniform_name) { + GLint location = get_uniform(uniform_name); if (location != -1) glUniform1i(location, value); } -void shader::setFloatUniform(float value, const char *uniformName) { - GLint location = getUniform(uniformName); +void shader_program::set_float(float value, const char *uniform_name) { + GLint location = get_uniform(uniform_name); if (location != -1) glUniform1f(location, value); } diff --git a/src/shader.h b/src/shader.h deleted file mode 100644 index 13d7598..0000000 --- a/src/shader.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "defines.h" -#include - -BEGIN_NAMESPACE - -class shader { -public: - shader(const char *vs_content, const char *ps_content); - virtual ~shader(); - - void use() const; - void unuse() const; - - GLuint getId() const { return program_id; } - int getUniform(const char *uniformName); - - void setMatrix3Uniform(float *value, const char *uniformName); - void setMatrix4Uniform(float *value, const char *uniformName); - void setVec3Uniform(float *value, const char *uniformName); - void setVec4Uniform(float *value, const char *uniformName); - void setFloatUniform(float value, const char *uniformName); - void setIntUniform(int value, const char *uniformName); - -private: - GLuint program_id; - GLuint shader_ids[2]; - std::map uniform_cache; -}; - - -END_NAMESPACE diff --git a/src/shader_constants.h b/src/shader_constants.h index 4ff5d3b..08b0678 100644 --- a/src/shader_constants.h +++ b/src/shader_constants.h @@ -1,7 +1,7 @@ #pragma once #include "defines.h" -#include "shader.h" +#include "shader_program.h" #include "texture.h" #include #include "material.h" @@ -16,8 +16,7 @@ struct uniform_descriptor { std::string member_name; // TODO: implement memoization of uniform name calculation - - uniform_descriptor(const char *member) { + explicit uniform_descriptor(const char *member) { structure_name = ""; member_name = member; } @@ -27,7 +26,7 @@ struct uniform_descriptor { member_name = member; } - std::string get_name() { + std::string get_name() const { if (structure_name.empty()) return member_name; @@ -36,7 +35,7 @@ struct uniform_descriptor { return ss.str(); } - std::string get_name(int index) { + std::string get_name(int index) const { std::stringstream ss; if (structure_name.empty()) { ss << member_name << "[" << index << "]"; @@ -93,72 +92,72 @@ public: shader_constant_type type; - glm::vec3 vec3Val{}; - glm::vec4 vec4Val{}; - glm::mat3 mat3Val{}; - glm::mat4 mat4Val{}; - int intVal{}; - float floatVal{}; + glm::vec3 vec3_val{}; + glm::vec4 vec4_val{}; + glm::mat3 mat3_val{}; + glm::mat4 mat4_val{}; + int int_val{}; + float float_val{}; - shader_constant_value(const shader_constant_value &rhs) { + shader_constant_value(const shader_constant_value& rhs) { type = rhs.type; - vec3Val = rhs.vec3Val; - vec4Val = rhs.vec4Val; - mat3Val = rhs.mat3Val; - mat4Val = rhs.mat4Val; - intVal = rhs.intVal; - floatVal = rhs.floatVal; + vec3_val = rhs.vec3_val; + vec4_val = rhs.vec4_val; + mat3_val = rhs.mat3_val; + mat4_val = rhs.mat4_val; + int_val = rhs.int_val; + float_val = rhs.float_val; } - shader_constant_value(glm::vec3 &value) { - vec3Val = value; + explicit shader_constant_value(glm::vec3& value) { + vec3_val = value; type = shader_constant_type::vec3; } - shader_constant_value(glm::vec4 &value) { - vec4Val = value; + explicit shader_constant_value(glm::vec4& value) { + vec4_val = value; type = shader_constant_type::vec4; } - shader_constant_value(glm::mat3 &value) { - mat3Val = value; + explicit shader_constant_value(glm::mat3& value) { + mat3_val = value; type = shader_constant_type::mat3; } - shader_constant_value(glm::mat4 &value) { - mat4Val = value; + explicit shader_constant_value(glm::mat4& value) { + mat4_val = value; type = shader_constant_type::mat4; } - shader_constant_value(int value) { - intVal = value; + explicit shader_constant_value(int value) { + int_val = value; type = shader_constant_type::integer; } - shader_constant_value(float value) { - floatVal = value; + explicit shader_constant_value(float value) { + float_val = value; type = shader_constant_type::decimal; } - void apply_to(shader &sh, const char *uniform_name) { + void apply_to(shader_program& sh, const char *uniform_name) { switch (type) { case shader_constant_type::vec3: - sh.setVec3Uniform(glm::value_ptr(vec3Val), uniform_name); + sh.set_vec3(glm::value_ptr(vec3_val), uniform_name); break; case shader_constant_type::vec4: - sh.setVec4Uniform(glm::value_ptr(vec4Val), uniform_name); + sh.set_vec4(glm::value_ptr(vec4_val), uniform_name); break; case shader_constant_type::mat3: - sh.setMatrix3Uniform(glm::value_ptr(mat3Val), uniform_name); + sh.set_mat3(glm::value_ptr(mat3_val), uniform_name); break; case shader_constant_type::mat4: - sh.setMatrix4Uniform(glm::value_ptr(mat4Val), uniform_name); + sh.set_mat4(glm::value_ptr(mat4_val), uniform_name); break; case shader_constant_type::integer: - sh.setIntUniform(intVal, uniform_name); + sh.set_int(int_val, uniform_name); break; case shader_constant_type::decimal: - sh.setFloatUniform(floatVal, uniform_name); + sh.set_float(float_val, uniform_name); break; } } @@ -168,56 +167,56 @@ public: class shader_constants { public: - void set(uniform_descriptor descriptor, glm::mat3 value) { + void set(const uniform_descriptor& descriptor, glm::mat3 value) { constants[descriptor.get_name()] = std::make_shared(value); } - void set(uniform_descriptor descriptor, glm::mat3 value, int index) { + void set(const uniform_descriptor& descriptor, glm::mat3 value, int index) { constants[descriptor.get_name(index)] = std::make_shared(value); } - void set(uniform_descriptor descriptor, glm::mat4 value) { + void set(const uniform_descriptor& descriptor, glm::mat4 value) { constants[descriptor.get_name()] = std::make_shared(value); } - void set(uniform_descriptor descriptor, glm::mat4 value, int index) { + void set(const uniform_descriptor& descriptor, glm::mat4 value, int index) { constants[descriptor.get_name(index)] = std::make_shared(value); } - void set(uniform_descriptor descriptor, glm::vec3 value) { + void set(const uniform_descriptor& descriptor, glm::vec3 value) { constants[descriptor.get_name()] = std::make_shared(value); } - void set(uniform_descriptor descriptor, glm::vec3 value, int index) { + void set(const uniform_descriptor& descriptor, glm::vec3 value, int index) { constants[descriptor.get_name(index)] = std::make_shared(value); } - void set(uniform_descriptor descriptor, glm::vec4 value) { + void set(const uniform_descriptor& descriptor, glm::vec4 value) { constants[descriptor.get_name()] = std::make_shared(value); } - void set(uniform_descriptor descriptor, glm::vec4 value, int index) { + void set(const uniform_descriptor& descriptor, glm::vec4 value, int index) { constants[descriptor.get_name(index)] = std::make_shared(value); } - void set(uniform_descriptor descriptor, int value) { + void set(const uniform_descriptor& descriptor, int value) { constants[descriptor.get_name()] = std::make_shared(value); } - void set(uniform_descriptor descriptor, int value, int index) { + void set(const uniform_descriptor& descriptor, int value, int index) { constants[descriptor.get_name(index)] = std::make_shared(value); } - void set(uniform_descriptor descriptor, float value) { + void set(const uniform_descriptor& descriptor, float value) { constants[descriptor.get_name()] = std::make_shared(value); } - void set(uniform_descriptor descriptor, float value, int index) { + void set(const uniform_descriptor& descriptor, float value, int index) { constants[descriptor.get_name(index)] = std::make_shared(value); } - void apply_to(shader &shd) { - for (auto &kv: constants) + void apply_to(shader_program& shd) { + for (auto& kv: constants) kv.second->apply_to(shd, kv.first.c_str()); } diff --git a/src/shader_program.h b/src/shader_program.h new file mode 100644 index 0000000..2e3f2b5 --- /dev/null +++ b/src/shader_program.h @@ -0,0 +1,33 @@ +#pragma once + +#include "defines.h" +#include + +BEGIN_NAMESPACE + +class shader_program { +public: + shader_program(const char *vs_content, const char *ps_content); + virtual ~shader_program(); + + void bind() const; + static void unbind() ; + + GLuint get_id() const { return program_id; } + + int get_uniform(const char *name); + + void set_mat3(float *value, const char *uniform_name); + void set_mat4(float *value, const char *uniform_name); + void set_vec3(float *value, const char *uniform_name); + void set_vec4(float *value, const char *uniform_name); + void set_float(float value, const char *uniform_name); + void set_int(int value, const char *uniform_name); + +private: + GLuint program_id; + GLuint shader_ids[2]; + std::map uniform_cache; +}; + +END_NAMESPACE diff --git a/src/timer.cpp b/src/timer.cpp index f8f4e9b..7a6f000 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -7,15 +7,15 @@ timer::timer() { last_lap_time = start_time; } -double timer::seconds_since_start() { +float timer::seconds_since_start() { std::chrono::time_point now = std::chrono::system_clock::now(); - std::chrono::duration elapsed_seconds = now - start_time; + std::chrono::duration elapsed_seconds = now - start_time; return elapsed_seconds.count(); } -double timer::lap() { +float timer::lap() { std::chrono::time_point now = std::chrono::system_clock::now(); - std::chrono::duration elapsed_seconds = now - last_lap_time; + std::chrono::duration elapsed_seconds = now - last_lap_time; last_lap_time = now; return elapsed_seconds.count(); } diff --git a/src/timer.h b/src/timer.h index 03c0b8b..501d596 100644 --- a/src/timer.h +++ b/src/timer.h @@ -9,8 +9,8 @@ class timer { public: timer(); - double seconds_since_start(); - double lap(); + float seconds_since_start(); + float lap(); private: std::chrono::time_point start_time; diff --git a/story-ideas.txt b/story-ideas.txt new file mode 100644 index 0000000..f241028 --- /dev/null +++ b/story-ideas.txt @@ -0,0 +1,12 @@ +intro: +- benzene elements come together and form the symbol +- they slowly come into place and rotate +- either explode into particles or fade away + +scenes: +- camera flyby trhough a sci-fi tunnel composed of metalic pipe systems and awkward light +- walk through a forest made with L-systems +- heightmap + + + \ No newline at end of file