mirror of
https://github.com/MadeOfJelly/MushMachine.git
synced 2025-07-13 12:36:47 +02:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
a6950b9de7 | |||
5023a658e7 | |||
5cc6aa8c74 | |||
563dd80a52 | |||
1ae43457ed | |||
5f066faa28 | |||
bbbbc655e7 | |||
410b373fda | |||
72add20751 | |||
4dd5a69dee | |||
e0f503728d | |||
b520811e72 | |||
69a04cbd7e | |||
ab169927fe | |||
a98098af91 | |||
631b9433c2 | |||
15ab73909f | |||
3dc66de3bc | |||
5e58a61c93 | |||
8f44e09f32 | |||
0408f771b7 | |||
4029dcd50c | |||
338fbf70d0 | |||
e39b23ac72 | |||
c48ae81238 | |||
7a461111e1 | |||
9ff0b17a5e | |||
60aca24ec6 | |||
4304701e5e | |||
601e1ca99d | |||
f5eb0e0dfa |
21
.github/workflows/cmake.yml
vendored
21
.github/workflows/cmake.yml
vendored
@ -41,6 +41,27 @@ jobs:
|
|||||||
## See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
## See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||||
#run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure
|
#run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure
|
||||||
|
|
||||||
|
linux_gles:
|
||||||
|
timeout-minutes: 10
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
# TODO: cache
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: sudo apt update && sudo apt -y install libsdl2-dev
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DMM_OPENGL_3_GLES=ON
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
|
||||||
|
@ -13,7 +13,15 @@ The private repo had over 900 commits, before the first public release.
|
|||||||
- [Github](https://github.com/MadeOfJelly/MushMachine)
|
- [Github](https://github.com/MadeOfJelly/MushMachine)
|
||||||
- [Setup](docs/setup.md)
|
- [Setup](docs/setup.md)
|
||||||
- [Example Game Setup](docs/basic_game.md)
|
- [Example Game Setup](docs/basic_game.md)
|
||||||
|
- [mm_template](https://github.com/MadeOfJelly/mm_template) (a GitHub Template for quick starting MM game dev)
|
||||||
- The [Docs Directory](docs/) contains Documentation loosely based on the Source structure.
|
- The [Docs Directory](docs/) contains Documentation loosely based on the Source structure.
|
||||||
|
- Engine Extensions:
|
||||||
|
- [Box2D integration](https://github.com/Green-Sky/mushmachine_box2d)
|
||||||
|
- [fx_draw (simple line drawing rendertask)](https://github.com/Green-Sky/fx_draw)
|
||||||
|
- Projects using the Engine:
|
||||||
|
- [miniTD](https://github.com/Green-Sky/miniTD)
|
||||||
|
- [LiteParticles2DDemo](https://github.com/MadeOfJelly/mm_lite_particles2d_demo)
|
||||||
|
- [mm_fireworks](https://github.com/Green-Sky/mm_fireworks)
|
||||||
|
|
||||||
## Platforms
|
## Platforms
|
||||||
- PC (Linux, Windows and maybe APPLE(compiles))
|
- PC (Linux, Windows and maybe APPLE(compiles))
|
||||||
|
2
external/entt
vendored
2
external/entt
vendored
Submodule external/entt updated: 8e0747fd50...e5172a9240
2
external/spdlog
vendored
2
external/spdlog
vendored
Submodule external/spdlog updated: eb3220622e...76fb40d954
51
external/tracy/CMakeLists.txt
vendored
51
external/tracy/CMakeLists.txt
vendored
@ -1,29 +1,38 @@
|
|||||||
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
|
||||||
|
|
||||||
add_library(tracy_client
|
if(NOT EMSCRIPTEN)
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/tracy/Tracy.hpp"
|
add_library(tracy_client
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/tracy/TracyLua.hpp"
|
"${CMAKE_CURRENT_LIST_DIR}/tracy/Tracy.hpp"
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/tracy/TracyVulkan.hpp"
|
"${CMAKE_CURRENT_LIST_DIR}/tracy/TracyLua.hpp"
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/tracy/TracyOpenGL.hpp"
|
"${CMAKE_CURRENT_LIST_DIR}/tracy/TracyVulkan.hpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/tracy/TracyOpenGL.hpp"
|
||||||
|
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/tracy/TracyClient.cpp"
|
"${CMAKE_CURRENT_LIST_DIR}/tracy/TracyClient.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_features(tracy_client PUBLIC cxx_std_17)
|
if(TRACY_ENABLE)
|
||||||
|
target_compile_definitions(tracy_client PUBLIC TRACY_ENABLE)
|
||||||
|
#target_compile_definitions(tracy_client PUBLIC TRACY_NO_SYSTEM_TRACING)
|
||||||
|
message("Enabled TRACY")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(TRACY_ENABLE)
|
target_compile_features(tracy_client PUBLIC cxx_std_17)
|
||||||
target_compile_definitions(tracy_client PUBLIC TRACY_ENABLE)
|
|
||||||
#target_compile_definitions(tracy_client PUBLIC TRACY_NO_SYSTEM_TRACING)
|
target_include_directories(tracy_client PUBLIC "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
message("Enabled TRACY")
|
|
||||||
|
if(UNIX)
|
||||||
|
target_link_libraries(tracy_client dl)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(tracy_client ws2_32 dbghelp)
|
||||||
|
endif()
|
||||||
|
else() # EMSCRIPTEN
|
||||||
|
add_library(tracy_client INTERFACE)
|
||||||
|
|
||||||
|
target_compile_features(tracy_client INTERFACE cxx_std_17)
|
||||||
|
|
||||||
|
target_include_directories(tracy_client INTERFACE "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(tracy_client PUBLIC "${CMAKE_CURRENT_LIST_DIR}")
|
|
||||||
|
|
||||||
if(UNIX)
|
|
||||||
target_link_libraries(tracy_client dl)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
target_link_libraries(tracy_client ws2_32 dbghelp)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
2
external/tracy/tracy
vendored
2
external/tracy/tracy
vendored
Submodule external/tracy/tracy updated: 07778badcc...9ba7171c3d
@ -85,8 +85,8 @@ private:
|
|||||||
|
|
||||||
bool entityHasComponent(Registry& registry, EntityType& entity, ComponentTypeID type_id)
|
bool entityHasComponent(Registry& registry, EntityType& entity, ComponentTypeID type_id)
|
||||||
{
|
{
|
||||||
ComponentTypeID type[] = { type_id };
|
const auto storage_it = registry.storage(type_id);
|
||||||
return registry.runtime_view(std::cbegin(type), std::cend(type)).contains(entity);
|
return storage_it != registry.storage().end() && storage_it->second.contains(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -243,7 +243,16 @@ public:
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
auto view = registry.runtime_view(comp_list.begin(), comp_list.end());
|
entt::basic_runtime_view<entt::basic_sparse_set<EntityType>> view{};
|
||||||
|
for (const auto type : comp_list) {
|
||||||
|
auto storage_it = registry.storage(type);
|
||||||
|
if (storage_it != registry.storage().end()) {
|
||||||
|
view.iterate(registry.storage(type)->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add support for exclude
|
||||||
|
|
||||||
ImGui::Text("%lu Entities Matching:", view.size_hint());
|
ImGui::Text("%lu Entities Matching:", view.size_hint());
|
||||||
|
|
||||||
if (ImGui::BeginChild("entity list")) {
|
if (ImGui::BeginChild("entity list")) {
|
||||||
@ -297,7 +306,8 @@ public:
|
|||||||
|
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
// Copyright (c) 2020 Erik Scholz, Gnik Droy
|
// Copyright (c) 2019-2022 Erik Scholz
|
||||||
|
// Copyright (c) 2020 Gnik Droy
|
||||||
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -16,20 +16,20 @@ void Camera3D(MM::Scene& scene) {
|
|||||||
|
|
||||||
ImGui::Indent();
|
ImGui::Indent();
|
||||||
|
|
||||||
auto* camera = scene.try_ctx<MM::OpenGL::Camera3D>();
|
if (!scene.ctx().contains<MM::OpenGL::Camera3D>()) {
|
||||||
if (!camera) {
|
|
||||||
ImGui::TextUnformatted("NO CAMERA!");
|
ImGui::TextUnformatted("NO CAMERA!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto& camera = scene.ctx().at<MM::OpenGL::Camera3D>();
|
||||||
|
|
||||||
static bool follow_entity = false;
|
static bool follow_entity = false;
|
||||||
static MM::Entity tracking = entt::null;
|
static MM::Entity tracking = entt::null;
|
||||||
|
|
||||||
ImGui::InputFloat("screenRatio", &camera->screenRatio);
|
ImGui::InputFloat("screenRatio", &camera.screenRatio);
|
||||||
ImGui::InputFloat("nearPlane", &camera->nearPlane);
|
ImGui::InputFloat("nearPlane", &camera.nearPlane);
|
||||||
ImGui::InputFloat("farPlane", &camera->farPlane);
|
ImGui::InputFloat("farPlane", &camera.farPlane);
|
||||||
|
|
||||||
if (camera->ortho) {
|
if (camera.ortho) {
|
||||||
ImGui::TextUnformatted("orthographic mode");
|
ImGui::TextUnformatted("orthographic mode");
|
||||||
ImGui::Checkbox("follow entity", &follow_entity);
|
ImGui::Checkbox("follow entity", &follow_entity);
|
||||||
|
|
||||||
@ -39,39 +39,39 @@ void Camera3D(MM::Scene& scene) {
|
|||||||
MM::ImGuiWidgets::Entity(tracking, scene);
|
MM::ImGuiWidgets::Entity(tracking, scene);
|
||||||
if (scene.valid(tracking)) {
|
if (scene.valid(tracking)) {
|
||||||
if (scene.all_of<MM::Components::Position2D>(tracking)) {
|
if (scene.all_of<MM::Components::Position2D>(tracking)) {
|
||||||
camera->translation = {scene.get<MM::Components::Position2D>(tracking).pos, 0.f};
|
camera.translation = {scene.get<MM::Components::Position2D>(tracking).pos, 0.f};
|
||||||
} else if (scene.all_of<MM::Components::Position3D>(tracking)) { // "3d" fallback
|
} else if (scene.all_of<MM::Components::Position3D>(tracking)) { // "3d" fallback
|
||||||
camera->translation = scene.get<MM::Components::Position3D>(tracking).pos;
|
camera.translation = scene.get<MM::Components::Position3D>(tracking).pos;
|
||||||
} else {
|
} else {
|
||||||
ImGui::TextUnformatted("error: Entity has neither Position2D nor Position3D");
|
ImGui::TextUnformatted("error: Entity has neither Position2D nor Position3D");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ImGui::DragFloat2("translation", &camera->translation.x, 0.1f);
|
ImGui::DragFloat2("translation", &camera.translation.x, 0.1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui::DragFloat("h_vp_size", &camera->horizontalViewPortSize, 0.1f);
|
ImGui::DragFloat("h_vp_size", &camera.horizontalViewPortSize, 0.1f);
|
||||||
|
|
||||||
// TODO: aspect ratio
|
// TODO: aspect ratio
|
||||||
|
|
||||||
// TODO: check for change
|
// TODO: check for change
|
||||||
camera->setOrthographic();
|
camera.setOrthographic();
|
||||||
} else { // perspective
|
} else { // perspective
|
||||||
ImGui::TextUnformatted("perspective mode");
|
ImGui::TextUnformatted("perspective mode");
|
||||||
|
|
||||||
ImGui::DragFloat3("translation", &camera->translation.x, 0.1f);
|
ImGui::DragFloat3("translation", &camera.translation.x, 0.1f);
|
||||||
ImGui::SliderFloat("fov", &camera->fov, 0.1f, glm::pi<float>());
|
ImGui::SliderFloat("fov", &camera.fov, 0.1f, glm::pi<float>());
|
||||||
|
|
||||||
ImGui::SliderFloat("yaw", &camera->yaw, 0.0f, 2*glm::pi<float>());
|
ImGui::SliderFloat("yaw", &camera.yaw, 0.0f, 2*glm::pi<float>());
|
||||||
ImGui::SliderFloat("pitch", &camera->pitch, -glm::pi<float>()/2, glm::pi<float>()/2);
|
ImGui::SliderFloat("pitch", &camera.pitch, -glm::pi<float>()/2, glm::pi<float>()/2);
|
||||||
|
|
||||||
ImGui::InputFloat3("up", &camera->up.x);
|
ImGui::InputFloat3("up", &camera.up.x);
|
||||||
|
|
||||||
camera->setPerspective();
|
camera.setPerspective();
|
||||||
}
|
}
|
||||||
|
|
||||||
camera->updateView();
|
camera.updateView();
|
||||||
|
|
||||||
ImGui::Unindent();
|
ImGui::Unindent();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "./scene_tools.hpp"
|
#include "./scene_tools.hpp"
|
||||||
#include "mm/components/velocity2d_rotation.hpp"
|
|
||||||
|
|
||||||
#include <mm/engine.hpp>
|
#include <mm/engine.hpp>
|
||||||
|
|
||||||
@ -32,10 +31,11 @@
|
|||||||
namespace MM::Services {
|
namespace MM::Services {
|
||||||
|
|
||||||
bool ImGuiSceneToolsService::enable(Engine& engine, std::vector<UpdateStrategies::TaskInfo>& task_array) {
|
bool ImGuiSceneToolsService::enable(Engine& engine, std::vector<UpdateStrategies::TaskInfo>& task_array) {
|
||||||
if (!engine.tryService<MM::Services::SceneServiceInterface>()) {
|
// enable anyway
|
||||||
LOGIGS("error: no SceneServiceInterface");
|
//if (!engine.tryService<MM::Services::SceneServiceInterface>()) {
|
||||||
return false;
|
//LOGIGS("error: no SceneServiceInterface");
|
||||||
}
|
//return false;
|
||||||
|
//}
|
||||||
|
|
||||||
// setup entity editor defaults
|
// setup entity editor defaults
|
||||||
{
|
{
|
||||||
@ -71,14 +71,13 @@ namespace MM::Services {
|
|||||||
};
|
};
|
||||||
|
|
||||||
menu_bar.menu_tree["Scene"]["TimeCtx"] = [this](Engine& e) {
|
menu_bar.menu_tree["Scene"]["TimeCtx"] = [this](Engine& e) {
|
||||||
MM::Components::TimeDelta* td_ptr = nullptr;
|
bool have_ctx = false;
|
||||||
|
|
||||||
if (auto* ssi_ptr = e.tryService<MM::Services::SceneServiceInterface>()) {
|
if (auto* ssi_ptr = e.tryService<MM::Services::SceneServiceInterface>()) {
|
||||||
auto& scene = ssi_ptr->getScene();
|
have_ctx = ssi_ptr->getScene().ctx().contains<MM::Components::TimeDelta>();
|
||||||
td_ptr = scene.try_ctx<MM::Components::TimeDelta>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::MenuItem("TimeDelta Context", NULL, &_show_time_delta_ctx, td_ptr);
|
ImGui::MenuItem("TimeDelta Context", NULL, &_show_time_delta_ctx, have_ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
// add task
|
// add task
|
||||||
@ -102,6 +101,10 @@ namespace MM::Services {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiSceneToolsService::renderImGui(Engine& engine) {
|
void ImGuiSceneToolsService::renderImGui(Engine& engine) {
|
||||||
|
if (engine.tryService<MM::Services::SceneServiceInterface>() == nullptr) {
|
||||||
|
return; // no scene, nothing to see
|
||||||
|
}
|
||||||
|
|
||||||
auto& scene = engine.tryService<MM::Services::SceneServiceInterface>()->getScene();
|
auto& scene = engine.tryService<MM::Services::SceneServiceInterface>()->getScene();
|
||||||
|
|
||||||
if (_show_scene_metrics) {
|
if (_show_scene_metrics) {
|
||||||
@ -153,10 +156,13 @@ namespace MM::Services {
|
|||||||
|
|
||||||
if (_show_time_delta_ctx) {
|
if (_show_time_delta_ctx) {
|
||||||
if (ImGui::Begin("Scene TimeDelta Context", &_show_time_delta_ctx)) {
|
if (ImGui::Begin("Scene TimeDelta Context", &_show_time_delta_ctx)) {
|
||||||
auto* td_ptr = scene.try_ctx<MM::Components::TimeDelta>();
|
if (scene.ctx().contains<MM::Components::TimeDelta>()) {
|
||||||
ImGui::Value("tickDelta", td_ptr->tickDelta);
|
auto& td = scene.ctx().at<MM::Components::TimeDelta>();
|
||||||
ImGui::SliderFloat("deltaFactor", &td_ptr->deltaFactor, 0.f, 10.f, "%.5f", ImGuiSliderFlags_Logarithmic);
|
ImGui::Value("tickDelta", td.tickDelta);
|
||||||
|
ImGui::SliderFloat("deltaFactor", &td.deltaFactor, 0.f, 10.f, "%.5f", ImGuiSliderFlags_Logarithmic);
|
||||||
|
} else {
|
||||||
|
ImGui::TextUnformatted("No TimeDelta");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
@ -6,20 +6,28 @@
|
|||||||
|
|
||||||
namespace MM::OpenGL {
|
namespace MM::OpenGL {
|
||||||
|
|
||||||
Buffer::Buffer(const void* data, std::size_t size, GLenum usage) : _size(size) {
|
Buffer::Buffer(const void* data, std::size_t size, GLenum usage, GLenum target) : _size(size), _target(target) {
|
||||||
glGenBuffers(1, &_handle);
|
glGenBuffers(1, &_handle);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _handle);
|
glBindBuffer(_target, _handle);
|
||||||
glBufferData(GL_ARRAY_BUFFER, size, data, usage);
|
glBufferData(_target, size, data, usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::~Buffer(void) {
|
Buffer::~Buffer(void) {
|
||||||
glDeleteBuffers(1,&_handle);
|
glDeleteBuffers(1, &_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::bind(void) const {
|
||||||
|
glBindBuffer(_target, _handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::bind(GLenum target) const {
|
void Buffer::bind(GLenum target) const {
|
||||||
glBindBuffer(target, _handle);
|
glBindBuffer(target, _handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Buffer::unbind(void) const {
|
||||||
|
glBindBuffer(_target, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void Buffer::unbind(GLenum target) const {
|
void Buffer::unbind(GLenum target) const {
|
||||||
glBindBuffer(target, 0);
|
glBindBuffer(target, 0);
|
||||||
}
|
}
|
||||||
@ -28,5 +36,9 @@ std::size_t Buffer::getSize(void) const {
|
|||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLuint Buffer::getHandle(void) const {
|
||||||
|
return _handle;
|
||||||
|
}
|
||||||
|
|
||||||
} // MM::OpenGL
|
} // MM::OpenGL
|
||||||
|
|
||||||
|
@ -21,15 +21,20 @@ namespace MM::OpenGL {
|
|||||||
private:
|
private:
|
||||||
GLuint _handle = 0;
|
GLuint _handle = 0;
|
||||||
std::size_t _size = 0;
|
std::size_t _size = 0;
|
||||||
|
GLenum _target;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Buffer(const void* data, std::size_t size, GLenum usage);
|
Buffer(const void* data, std::size_t size, GLenum usage, GLenum target = GL_ARRAY_BUFFER);
|
||||||
~Buffer(void);
|
~Buffer(void);
|
||||||
|
|
||||||
|
void bind(void) const;
|
||||||
void bind(GLenum target) const;
|
void bind(GLenum target) const;
|
||||||
|
void unbind(void) const;
|
||||||
void unbind(GLenum target) const;
|
void unbind(GLenum target) const;
|
||||||
|
|
||||||
std::size_t getSize(void) const;
|
std::size_t getSize(void) const;
|
||||||
|
|
||||||
|
GLuint getHandle(void) const;
|
||||||
};
|
};
|
||||||
} // MM::OpenGL
|
} // MM::OpenGL
|
||||||
|
|
||||||
|
@ -18,10 +18,30 @@ FBOBuilder FBOBuilder::start(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<FrameBufferObject> FBOBuilder::finish(void) {
|
std::shared_ptr<FrameBufferObject> FBOBuilder::finish(void) {
|
||||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
|
const auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
|
if (status == GL_FRAMEBUFFER_COMPLETE) {
|
||||||
return _fbo;
|
return _fbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* error_str = "UNK";
|
||||||
|
switch (status) {
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||||
|
error_str = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
|
||||||
|
break;
|
||||||
|
#ifdef MM_OPENGL_3_GLES
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
|
||||||
|
error_str = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||||
|
error_str = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
|
||||||
|
break;
|
||||||
|
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||||
|
error_str = "GL_FRAMEBUFFER_UNSUPPORTED";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SPDLOG_ERROR("framebuffer status: {}", error_str);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,8 +66,15 @@ FBOBuilder& FBOBuilder::attachTexture(std::shared_ptr<Texture> tex, GLuint attac
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex->getHandle(), 0);
|
if (tex->samples == 0u) {
|
||||||
glFramebufferTexture2D(target, attachment_type, GL_TEXTURE_2D, tex->getHandle(), 0);
|
glFramebufferTexture2D(target, attachment_type, GL_TEXTURE_2D, tex->getHandle(), 0);
|
||||||
|
} else {
|
||||||
|
#ifndef MM_OPENGL_3_GLES
|
||||||
|
glFramebufferTexture2D(target, attachment_type, GL_TEXTURE_2D_MULTISAMPLE, tex->getHandle(), 0);
|
||||||
|
#else
|
||||||
|
assert(false && "GLES has no multisampling support");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
_fbo->_texAttachments.push_back(tex); // keep a ref at the fbo
|
_fbo->_texAttachments.push_back(tex); // keep a ref at the fbo
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -90,6 +90,7 @@ void Shader::setUniformMat3f(const std::string& name, const glm::mat3& matrix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor this whole thing out
|
// TODO: refactor this whole thing out
|
||||||
|
// FIXME: hangs if trailing whitespace
|
||||||
std::string Shader::parse(Engine& engine, const std::string& filePath) {
|
std::string Shader::parse(Engine& engine, const std::string& filePath) {
|
||||||
auto& fs = engine.getService<MM::Services::FilesystemService>();
|
auto& fs = engine.getService<MM::Services::FilesystemService>();
|
||||||
|
|
||||||
|
@ -16,28 +16,49 @@ uint32_t Texture::getHandle(void) const {
|
|||||||
Texture::Texture(
|
Texture::Texture(
|
||||||
uint32_t handle,
|
uint32_t handle,
|
||||||
int32_t width_, int32_t height_,
|
int32_t width_, int32_t height_,
|
||||||
int32_t internalFormat, int32_t format, int32_t type
|
int32_t internalFormat, int32_t format, int32_t type,
|
||||||
|
uint32_t samples_
|
||||||
) : _handle(handle), width(width_), height(height_),
|
) : _handle(handle), width(width_), height(height_),
|
||||||
_internalFormat(internalFormat), _format(format), _type(type) {}
|
samples(samples_),
|
||||||
|
_internalFormat(internalFormat), _format(format), _type(type) {
|
||||||
|
}
|
||||||
|
|
||||||
Texture::~Texture(void) {
|
Texture::~Texture(void) {
|
||||||
glDeleteTextures(1, &_handle);
|
glDeleteTextures(1, &_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::unbind(void) const {
|
void Texture::unbind(void) const {
|
||||||
|
// TODO: do i need ms variant?
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::bind(uint32_t slot) const {
|
void Texture::bind(uint32_t slot) const {
|
||||||
glActiveTexture(GL_TEXTURE0 + slot);
|
glActiveTexture(GL_TEXTURE0 + slot);
|
||||||
glBindTexture(GL_TEXTURE_2D, _handle);
|
if (samples == 0) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _handle);
|
||||||
|
} else {
|
||||||
|
#ifndef MM_OPENGL_3_GLES
|
||||||
|
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _handle);
|
||||||
|
#else
|
||||||
|
assert(false && "GLES has no multisampling support");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::resize(int32_t new_width, int32_t new_height) {
|
void Texture::resize(int32_t new_width, int32_t new_height) {
|
||||||
// if (glTexImage2D == true)
|
// if (glTexImage2D == true)
|
||||||
glBindTexture(GL_TEXTURE_2D, _handle);
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, _internalFormat, new_width, new_height, 0, _format, _type, NULL);
|
if (samples == 0) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _handle);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, _internalFormat, new_width, new_height, 0, _format, _type, NULL);
|
||||||
|
} else {
|
||||||
|
#ifndef MM_OPENGL_3_GLES
|
||||||
|
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _handle);
|
||||||
|
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, _internalFormat, new_width, new_height, 0);
|
||||||
|
#else
|
||||||
|
assert(false && "GLES has no multisampling support");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// HACK: super dirty
|
// HACK: super dirty
|
||||||
*(const_cast<int32_t*>(&width)) = new_width;
|
*(const_cast<int32_t*>(&width)) = new_width;
|
||||||
@ -57,5 +78,27 @@ Texture::handle_t Texture::createEmpty(int32_t internalFormat, int32_t width, in
|
|||||||
return handle_t(new Texture(id, width, height, internalFormat, format, type));
|
return handle_t(new Texture(id, width, height, internalFormat, format, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture::handle_t Texture::createEmptyMultiSampled(int32_t internalFormat, int32_t width, int32_t height, uint32_t samples) {
|
||||||
|
#ifndef MM_OPENGL_3_GLES
|
||||||
|
uint32_t id;
|
||||||
|
glGenTextures(1, &id);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, id);
|
||||||
|
|
||||||
|
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, internalFormat, width, height, GL_TRUE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
|
||||||
|
|
||||||
|
// HACK: format + type?
|
||||||
|
return handle_t(new Texture(id, width, height, internalFormat, 0, 0, samples));
|
||||||
|
#else
|
||||||
|
(void)internalFormat;
|
||||||
|
(void)width;
|
||||||
|
(void)height;
|
||||||
|
(void)samples;
|
||||||
|
assert(false && "GLES has no multisampling support");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // MM::OpenGL
|
} // MM::OpenGL
|
||||||
|
|
||||||
|
@ -20,7 +20,8 @@ namespace MM::OpenGL {
|
|||||||
Texture(
|
Texture(
|
||||||
uint32_t handle,
|
uint32_t handle,
|
||||||
int32_t width_, int32_t height_,
|
int32_t width_, int32_t height_,
|
||||||
int32_t internalFormat, int32_t format, int32_t type
|
int32_t internalFormat, int32_t format, int32_t type,
|
||||||
|
uint32_t samples = 0u
|
||||||
);
|
);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -29,6 +30,8 @@ namespace MM::OpenGL {
|
|||||||
int32_t const width;
|
int32_t const width;
|
||||||
int32_t const height;
|
int32_t const height;
|
||||||
//int32_t const bpp; // bits per pixel
|
//int32_t const bpp; // bits per pixel
|
||||||
|
uint32_t const samples{0u}; // sample count, 0 == off
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32_t const _internalFormat;
|
int32_t const _internalFormat;
|
||||||
int32_t const _format;
|
int32_t const _format;
|
||||||
@ -45,6 +48,7 @@ namespace MM::OpenGL {
|
|||||||
void resize(int32_t new_width, int32_t new_height);
|
void resize(int32_t new_width, int32_t new_height);
|
||||||
|
|
||||||
static handle_t createEmpty(int32_t internalFormat, int32_t width, int32_t height, int32_t format, int32_t type);
|
static handle_t createEmpty(int32_t internalFormat, int32_t width, int32_t height, int32_t format, int32_t type);
|
||||||
|
static handle_t createEmptyMultiSampled(int32_t internalFormat, int32_t width, int32_t height, uint32_t samples);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // MM::OpenGL
|
} // MM::OpenGL
|
||||||
|
@ -31,5 +31,12 @@ namespace MM::OpenGL {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TextureLoaderEmptyMultiSampled final {
|
||||||
|
template<typename... Args>
|
||||||
|
std::shared_ptr<Texture> load(Args&& ... args) const {
|
||||||
|
return Texture::createEmptyMultiSampled(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // MM::OpenGL
|
} // MM::OpenGL
|
||||||
|
|
||||||
|
@ -9,6 +9,9 @@ add_library(opengl_renderer_s
|
|||||||
|
|
||||||
src/mm/opengl/camera_3d.hpp
|
src/mm/opengl/camera_3d.hpp
|
||||||
src/mm/opengl/camera_3d.cpp
|
src/mm/opengl/camera_3d.cpp
|
||||||
|
|
||||||
|
src/mm/opengl/res/shaders_builtin.hpp
|
||||||
|
src/mm/opengl/res/shaders_builtin.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(opengl_renderer_s PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
target_include_directories(opengl_renderer_s PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
@ -176,6 +179,49 @@ target_link_libraries(blur_render_task
|
|||||||
engine
|
engine
|
||||||
)
|
)
|
||||||
|
|
||||||
|
############# bloom_extraction render task ###########
|
||||||
|
|
||||||
|
add_library(bloom_extraction_render_task
|
||||||
|
src/mm/opengl/render_tasks/bloom_extraction.hpp
|
||||||
|
src/mm/opengl/render_tasks/bloom_extraction.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(bloom_extraction_render_task PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
|
||||||
|
target_link_libraries(bloom_extraction_render_task
|
||||||
|
opengl_renderer_s
|
||||||
|
engine
|
||||||
|
)
|
||||||
|
|
||||||
|
############# bloom_combine render task ###########
|
||||||
|
|
||||||
|
add_library(bloom_combine_render_task
|
||||||
|
src/mm/opengl/render_tasks/bloom_combine.hpp
|
||||||
|
src/mm/opengl/render_tasks/bloom_combine.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(bloom_combine_render_task PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
|
||||||
|
target_link_libraries(bloom_combine_render_task
|
||||||
|
opengl_renderer_s
|
||||||
|
engine
|
||||||
|
)
|
||||||
|
|
||||||
|
############# composition render task ###########
|
||||||
|
# intendet for bloom compositing and tonemapping
|
||||||
|
|
||||||
|
add_library(composition_render_task
|
||||||
|
src/mm/opengl/render_tasks/composition.hpp
|
||||||
|
src/mm/opengl/render_tasks/composition.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(composition_render_task PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
|
||||||
|
target_link_libraries(composition_render_task
|
||||||
|
opengl_renderer_s
|
||||||
|
engine
|
||||||
|
)
|
||||||
|
|
||||||
############# tilemap renderer ###########
|
############# tilemap renderer ###########
|
||||||
|
|
||||||
add_library(tilemap_render_task
|
add_library(tilemap_render_task
|
||||||
@ -207,6 +253,42 @@ target_link_libraries(fast_sky_render_task
|
|||||||
engine
|
engine
|
||||||
)
|
)
|
||||||
|
|
||||||
|
############# bloom ###########
|
||||||
|
|
||||||
|
add_library(bloom
|
||||||
|
src/mm/opengl/bloom.hpp
|
||||||
|
src/mm/opengl/bloom.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(bloom PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
|
||||||
|
target_link_libraries(bloom
|
||||||
|
bloom_extraction_render_task
|
||||||
|
blur_render_task
|
||||||
|
bloom_combine_render_task
|
||||||
|
)
|
||||||
|
|
||||||
|
############# lite_particles2d ###########
|
||||||
|
|
||||||
|
add_library(lite_particles2d
|
||||||
|
src/mm/opengl/lite_particles2d_type.hpp
|
||||||
|
src/mm/opengl/lite_particles2d_type_loader.hpp
|
||||||
|
src/mm/opengl/lite_particles2d_type_loader.cpp
|
||||||
|
|
||||||
|
src/mm/opengl/components/lite_particles2d.hpp
|
||||||
|
|
||||||
|
src/mm/opengl/render_tasks/lite_particles2d.hpp
|
||||||
|
src/mm/opengl/render_tasks/lite_particles2d.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(lite_particles2d PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
|
||||||
|
target_link_libraries(lite_particles2d
|
||||||
|
engine
|
||||||
|
opengl_renderer_s
|
||||||
|
common_components_serialize_json # glm serl
|
||||||
|
)
|
||||||
|
|
||||||
########################
|
########################
|
||||||
|
|
||||||
if (BUILD_TESTING)
|
if (BUILD_TESTING)
|
||||||
|
160
framework/opengl_renderer/src/mm/opengl/bloom.cpp
Normal file
160
framework/opengl_renderer/src/mm/opengl/bloom.cpp
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#include "./bloom.hpp"
|
||||||
|
|
||||||
|
#include <mm/opengl/render_tasks/bloom_extraction.hpp>
|
||||||
|
#include <mm/opengl/render_tasks/blur.hpp>
|
||||||
|
#include <mm/opengl/render_tasks/bloom_combine.hpp>
|
||||||
|
|
||||||
|
#include <mm/opengl/fbo_builder.hpp>
|
||||||
|
#include <mm/opengl/texture_loader.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL {
|
||||||
|
|
||||||
|
using namespace entt::literals;
|
||||||
|
|
||||||
|
void setup_bloom(
|
||||||
|
MM::Engine& engine,
|
||||||
|
const std::string color_src_tex,
|
||||||
|
const size_t bloom_phases,
|
||||||
|
const float bloom_in_scale,
|
||||||
|
const float bloom_phase_scale
|
||||||
|
) {
|
||||||
|
assert(bloom_phases > 1);
|
||||||
|
auto& rs = engine.getService<MM::Services::OpenGLRenderer>();
|
||||||
|
auto& rm_t = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||||
|
auto [w, h] = engine.getService<MM::Services::SDLService>().getWindowSize();
|
||||||
|
|
||||||
|
#ifdef MM_OPENGL_3_GLES
|
||||||
|
#if 0 // NOPE!!
|
||||||
|
// TODO: caps at 1, invest in half float?
|
||||||
|
const auto bloom_internal_format = GL_RGB565; // prolly fine. NOPE its not. it causes green pixely halos
|
||||||
|
const auto bloom_format_type = GL_UNSIGNED_BYTE;
|
||||||
|
#else
|
||||||
|
//const auto bloom_internal_format = GL_RGBA16F;
|
||||||
|
const auto bloom_internal_format = GL_R11F_G11F_B10F;
|
||||||
|
const auto bloom_format_type = GL_FLOAT;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
//const auto bloom_internal_format = GL_RGB16F;
|
||||||
|
const auto bloom_internal_format = GL_R11F_G11F_B10F;
|
||||||
|
const auto bloom_format_type = GL_FLOAT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{ // bloom in (bloom extraction)
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"bloom_in",
|
||||||
|
bloom_internal_format,
|
||||||
|
w * bloom_in_scale, h * bloom_in_scale,
|
||||||
|
GL_RGB, bloom_format_type
|
||||||
|
);
|
||||||
|
{ // filter
|
||||||
|
rm_t.get("bloom_in"_hs)->bind(0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
rs.targets["bloom_extraction"] = MM::OpenGL::FBOBuilder::start()
|
||||||
|
.attachTexture(rm_t.get("bloom_in"_hs), GL_COLOR_ATTACHMENT0)
|
||||||
|
.setResizeFactors(bloom_in_scale, bloom_in_scale)
|
||||||
|
.setResize(true)
|
||||||
|
.finish();
|
||||||
|
assert(rs.targets["bloom_extraction"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// blur textures and fbos
|
||||||
|
for (size_t i = 1; i <= bloom_phases; i++) {
|
||||||
|
// TODO: further dedup
|
||||||
|
std::string tex_out_name {"blur_out" + std::to_string(i)};
|
||||||
|
auto tex_out_id = entt::hashed_string::value(tex_out_name.c_str());
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
tex_out_id,
|
||||||
|
bloom_internal_format,
|
||||||
|
w * bloom_in_scale * glm::pow(bloom_phase_scale, i), h * bloom_in_scale * glm::pow(bloom_phase_scale, i),
|
||||||
|
GL_RGB, bloom_format_type
|
||||||
|
);
|
||||||
|
{ // filter
|
||||||
|
rm_t.get(tex_out_id)->bind(0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string tex_tmp_name {"blur_tmp" + std::to_string(i)};
|
||||||
|
auto tex_tmp_id = entt::hashed_string::value(tex_tmp_name.c_str());
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
tex_tmp_id,
|
||||||
|
bloom_internal_format,
|
||||||
|
w * bloom_in_scale * glm::pow(bloom_phase_scale, i), h * bloom_in_scale * glm::pow(bloom_phase_scale, i),
|
||||||
|
GL_RGB, bloom_format_type
|
||||||
|
);
|
||||||
|
{ // filter
|
||||||
|
rm_t.get(tex_tmp_id)->bind(0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
rs.targets[tex_out_name] = MM::OpenGL::FBOBuilder::start()
|
||||||
|
.attachTexture(rm_t.get(tex_out_id), GL_COLOR_ATTACHMENT0)
|
||||||
|
.setResizeFactors(bloom_in_scale * glm::pow(bloom_phase_scale, i), bloom_in_scale * glm::pow(bloom_phase_scale, i))
|
||||||
|
.setResize(true)
|
||||||
|
.finish();
|
||||||
|
assert(rs.targets[tex_out_name]);
|
||||||
|
|
||||||
|
rs.targets[tex_tmp_name] = MM::OpenGL::FBOBuilder::start()
|
||||||
|
.attachTexture(rm_t.get(tex_tmp_id), GL_COLOR_ATTACHMENT0)
|
||||||
|
.setResizeFactors(bloom_in_scale * glm::pow(bloom_phase_scale, i), bloom_in_scale * glm::pow(bloom_phase_scale, i))
|
||||||
|
.setResize(true)
|
||||||
|
.finish();
|
||||||
|
assert(rs.targets[tex_tmp_name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // render tasks
|
||||||
|
auto& extraction = rs.addRenderTask<MM::OpenGL::RenderTasks::BloomExtraction>(engine);
|
||||||
|
extraction.src_tex = color_src_tex;
|
||||||
|
extraction.target_fbo = "bloom_extraction";
|
||||||
|
|
||||||
|
const glm::vec2 blur_factor {1.f, 1.f};
|
||||||
|
|
||||||
|
{ // blur rt
|
||||||
|
std::string prev_out_tex = "bloom_in";
|
||||||
|
for (size_t i = 1; i <= bloom_phases; i++) {
|
||||||
|
auto& blur = rs.addRenderTask<MM::OpenGL::RenderTasks::Blur>(engine);
|
||||||
|
// h
|
||||||
|
blur.in_tex = prev_out_tex;
|
||||||
|
blur.temp_fbo = "blur_tmp" + std::to_string(i);
|
||||||
|
// v
|
||||||
|
blur.temp_tex = "blur_tmp" + std::to_string(i);
|
||||||
|
blur.out_fbo = "blur_out" + std::to_string(i);
|
||||||
|
blur.out_tex = "blur_out" + std::to_string(i);
|
||||||
|
blur.tex_offset_factor = blur_factor * glm::vec2{2.f, 1.f}; // the input texture is double the size
|
||||||
|
|
||||||
|
// old blur:
|
||||||
|
//blur.tex_offset = {1.f/(w * bloom_in_scale * bloom_in_scale), 1.f/(h * bloom_in_scale * bloom_in_scale)};
|
||||||
|
|
||||||
|
prev_out_tex = blur.out_tex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// combine passes
|
||||||
|
for (size_t i = bloom_phases; i > 1; i--) {
|
||||||
|
auto& combine = rs.addRenderTask<MM::OpenGL::RenderTasks::BloomCombine>(engine);
|
||||||
|
if (i == bloom_phases) {
|
||||||
|
combine.tex0 = "blur_out" + std::to_string(i);
|
||||||
|
} else {
|
||||||
|
combine.tex0 = "blur_tmp" + std::to_string(i);
|
||||||
|
}
|
||||||
|
combine.tex1 = "blur_out" + std::to_string(i-1);
|
||||||
|
combine.target_fbo = "blur_tmp" + std::to_string(i-1); // -> blur_tmpi-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // MM::OpenGL
|
||||||
|
|
27
framework/opengl_renderer/src/mm/opengl/bloom.hpp
Normal file
27
framework/opengl_renderer/src/mm/opengl/bloom.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "./render_task.hpp"
|
||||||
|
|
||||||
|
namespace MM::OpenGL {
|
||||||
|
|
||||||
|
// helper function to setup a bloom blur and recombine chain
|
||||||
|
// creates (texture) rendertarget, fbos and rendertasks
|
||||||
|
// outputs blur to "blur_tmp1" texture
|
||||||
|
//
|
||||||
|
// you still need to add the Composition rendertask (or eqv) your self, eg:
|
||||||
|
// auto& comp = rs.addRenderTask<MM::OpenGL::RenderTasks::Composition>(engine);
|
||||||
|
// comp.color_tex = "hdr_color";
|
||||||
|
// comp.bloom_tex = "blur_tmp1";
|
||||||
|
// comp.target_fbo = "display";
|
||||||
|
void setup_bloom(
|
||||||
|
MM::Engine& engine,
|
||||||
|
const std::string color_src_tex = "hdr_color", // texture to extract color from
|
||||||
|
const size_t bloom_phases = 5, // number of downsampled blurs (4 prob fine for 720, 5 for 1080)
|
||||||
|
const float bloom_in_scale = 0.5f, // scale of bloom extraction layer (1 - 0.5 best, lower for more perf)
|
||||||
|
const float bloom_phase_scale = 0.5f // ammount of scaling per downsampling
|
||||||
|
);
|
||||||
|
|
||||||
|
} // MM::OpenGL
|
||||||
|
|
@ -51,20 +51,7 @@ void Camera3D::updateView(void) {
|
|||||||
pitch = glm::clamp(pitch, -(glm::pi<float>()/2 - 0.00001f), glm::pi<float>()/2 - 0.00001f);
|
pitch = glm::clamp(pitch, -(glm::pi<float>()/2 - 0.00001f), glm::pi<float>()/2 - 0.00001f);
|
||||||
yaw = glm::mod(yaw, 2*glm::pi<float>());
|
yaw = glm::mod(yaw, 2*glm::pi<float>());
|
||||||
|
|
||||||
glm::vec3 front {0,0,0};
|
glm::vec3 front = getViewDir();
|
||||||
{ // TODO: optimize
|
|
||||||
// if y up/down
|
|
||||||
front.x += up.y * glm::cos(pitch) * glm::cos(-yaw); // TODO: y is yaw inverted??
|
|
||||||
front.y += up.y * glm::sin(pitch);
|
|
||||||
front.z += up.y * glm::cos(pitch) * glm::sin(-yaw);
|
|
||||||
|
|
||||||
// if z up/down
|
|
||||||
front.x += up.z * glm::cos(pitch) * glm::cos(yaw);
|
|
||||||
front.y += up.z * glm::cos(pitch) * glm::sin(yaw);
|
|
||||||
front.z += up.z * glm::sin(pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
front = glm::normalize(front);
|
|
||||||
|
|
||||||
_view = glm::lookAt(translation, translation + front, up);
|
_view = glm::lookAt(translation, translation + front, up);
|
||||||
}
|
}
|
||||||
@ -82,6 +69,28 @@ glm::mat4 Camera3D::getProjection() const {
|
|||||||
return _projection;
|
return _projection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 Camera3D::getViewDir(void) const {
|
||||||
|
glm::vec3 front {0,0,0};
|
||||||
|
{ // TODO: optimize
|
||||||
|
if (up.y != 0.f) {
|
||||||
|
// if y up/down
|
||||||
|
front.x += up.y * glm::cos(pitch) * glm::cos(-yaw); // TODO: y is yaw inverted??
|
||||||
|
front.y += up.y * glm::sin(pitch);
|
||||||
|
front.z += up.y * glm::cos(pitch) * glm::sin(-yaw);
|
||||||
|
}
|
||||||
|
if (up.z != 0.f) {
|
||||||
|
// if z up/down
|
||||||
|
front.x += up.z * glm::cos(pitch) * glm::cos(yaw);
|
||||||
|
front.y += up.z * glm::cos(pitch) * glm::sin(yaw);
|
||||||
|
front.z += up.z * glm::sin(pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
front = glm::normalize(front);
|
||||||
|
|
||||||
|
return front;
|
||||||
|
}
|
||||||
|
|
||||||
std::array<glm::vec4, 6> Camera3D::getFrustumPlanes(void) const {
|
std::array<glm::vec4, 6> Camera3D::getFrustumPlanes(void) const {
|
||||||
ZoneScopedN("Camera3D::getFrustumPlanes")
|
ZoneScopedN("Camera3D::getFrustumPlanes")
|
||||||
|
|
||||||
|
@ -47,6 +47,8 @@ namespace MM::OpenGL {
|
|||||||
glm::mat4 getView(void) const;
|
glm::mat4 getView(void) const;
|
||||||
glm::mat4 getProjection(void) const;
|
glm::mat4 getProjection(void) const;
|
||||||
|
|
||||||
|
glm::vec3 getViewDir(void) const;
|
||||||
|
|
||||||
// call updateView beforehand, does not cache
|
// call updateView beforehand, does not cache
|
||||||
std::array<glm::vec4, 6> getFrustumPlanes(void) const;
|
std::array<glm::vec4, 6> getFrustumPlanes(void) const;
|
||||||
|
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/vec2.hpp>
|
||||||
|
|
||||||
|
#include <queue> // tmp
|
||||||
|
|
||||||
|
namespace MM::Components {
|
||||||
|
|
||||||
|
// not intended to be a component
|
||||||
|
// see LiteParticles2DUploadQueue
|
||||||
|
struct LiteParticle2D {
|
||||||
|
uint32_t type_id {0u}; // entt::hashed_string, ResourceManager
|
||||||
|
|
||||||
|
glm::vec2 pos {0.f, 0.f};
|
||||||
|
glm::vec2 vel {0.f, 0.f};
|
||||||
|
|
||||||
|
float age {0.f};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LiteParticles2DUploadQueue {
|
||||||
|
// TODO: vector
|
||||||
|
std::queue<LiteParticle2D> queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // MM::Components
|
||||||
|
|
@ -0,0 +1,95 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <mm/components/serialize/json_glm.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace MM::OpenGL {
|
||||||
|
|
||||||
|
struct LiteParticles2DType {
|
||||||
|
struct Compute {
|
||||||
|
float age_delta;
|
||||||
|
|
||||||
|
glm::vec2 force_vec;
|
||||||
|
|
||||||
|
float turbulence;
|
||||||
|
float turbulence_noise_scale;
|
||||||
|
float turbulence_individuality;
|
||||||
|
float turbulence_time_scale;
|
||||||
|
|
||||||
|
float dampening;
|
||||||
|
|
||||||
|
static constexpr size_t _member_count = 8;
|
||||||
|
} compute;
|
||||||
|
|
||||||
|
struct Render {
|
||||||
|
glm::vec4 color_start;
|
||||||
|
glm::vec4 color_end;
|
||||||
|
|
||||||
|
float size_start;
|
||||||
|
float size_end;
|
||||||
|
|
||||||
|
static constexpr size_t _member_count = 10;
|
||||||
|
} render;
|
||||||
|
|
||||||
|
// naive, prob fine, not time critical
|
||||||
|
void upload(std::vector<float>& comp_vec, std::vector<float>& rend_vec) const {
|
||||||
|
{
|
||||||
|
comp_vec.push_back(compute.age_delta);
|
||||||
|
|
||||||
|
comp_vec.push_back(compute.force_vec.x);
|
||||||
|
comp_vec.push_back(compute.force_vec.y);
|
||||||
|
|
||||||
|
comp_vec.push_back(compute.turbulence);
|
||||||
|
comp_vec.push_back(compute.turbulence_noise_scale);
|
||||||
|
comp_vec.push_back(compute.turbulence_individuality);
|
||||||
|
comp_vec.push_back(compute.turbulence_time_scale);
|
||||||
|
|
||||||
|
comp_vec.push_back(compute.dampening);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
rend_vec.push_back(render.color_start.r);
|
||||||
|
rend_vec.push_back(render.color_start.g);
|
||||||
|
rend_vec.push_back(render.color_start.b);
|
||||||
|
rend_vec.push_back(render.color_start.a);
|
||||||
|
|
||||||
|
rend_vec.push_back(render.color_end.r);
|
||||||
|
rend_vec.push_back(render.color_end.g);
|
||||||
|
rend_vec.push_back(render.color_end.b);
|
||||||
|
rend_vec.push_back(render.color_end.a);
|
||||||
|
|
||||||
|
rend_vec.push_back(render.size_start);
|
||||||
|
rend_vec.push_back(render.size_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LiteParticles2DType::Compute,
|
||||||
|
age_delta,
|
||||||
|
|
||||||
|
force_vec,
|
||||||
|
|
||||||
|
turbulence,
|
||||||
|
turbulence_noise_scale,
|
||||||
|
turbulence_individuality,
|
||||||
|
turbulence_time_scale,
|
||||||
|
|
||||||
|
dampening
|
||||||
|
)
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LiteParticles2DType::Render,
|
||||||
|
color_start,
|
||||||
|
color_end,
|
||||||
|
|
||||||
|
size_start,
|
||||||
|
size_end
|
||||||
|
)
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LiteParticles2DType, compute, render)
|
||||||
|
|
||||||
|
} // MM::OpenGL
|
||||||
|
|
@ -0,0 +1,39 @@
|
|||||||
|
#include "./lite_particles2d_type_loader.hpp"
|
||||||
|
|
||||||
|
#include <mm/services/filesystem.hpp>
|
||||||
|
|
||||||
|
#include <mm/logger.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL {
|
||||||
|
|
||||||
|
std::shared_ptr<LiteParticles2DType> LiteParticles2DTypeLoaderJson::load(const nlohmann::json& j) const {
|
||||||
|
auto new_type = std::make_shared<LiteParticles2DType>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
*new_type = j;
|
||||||
|
} catch (...) {
|
||||||
|
SPDLOG_ERROR("failed parsing particle type json:\n{}", j.dump(2));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<LiteParticles2DType> LiteParticles2DTypeLoaderFile::load(MM::Engine& engine, const std::string& path) const {
|
||||||
|
auto* fs = engine.tryService<MM::Services::FilesystemService>();
|
||||||
|
if (fs == nullptr) {
|
||||||
|
// TODO: error
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto new_particle = LiteParticles2DTypeLoaderJson{}.load(fs->readJson(path.c_str()));
|
||||||
|
|
||||||
|
if (!new_particle) {
|
||||||
|
SPDLOG_ERROR("particle type file: '{}'", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_particle;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // MM::OpenGL
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "./lite_particles2d_type.hpp"
|
||||||
|
|
||||||
|
#include <mm/engine_fwd.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL {
|
||||||
|
|
||||||
|
struct LiteParticles2DTypeLoaderJson final {
|
||||||
|
std::shared_ptr<LiteParticles2DType> load(const nlohmann::json& j) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LiteParticles2DTypeLoaderFile final {
|
||||||
|
std::shared_ptr<LiteParticles2DType> load(MM::Engine& engine, const std::string& path) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // MM::OpenGL
|
||||||
|
|
@ -30,5 +30,5 @@ namespace MM::OpenGL {
|
|||||||
//virtual void reload(void) {} // TODO: remove
|
//virtual void reload(void) {} // TODO: remove
|
||||||
//virtual std::vector<const char*> getShaderPaths(void) {return {};} // TODO: remove
|
//virtual std::vector<const char*> getShaderPaths(void) {return {};} // TODO: remove
|
||||||
};
|
};
|
||||||
}
|
} // MM:OpenGL
|
||||||
|
|
||||||
|
@ -27,9 +27,6 @@
|
|||||||
namespace MM::OpenGL::RenderTasks {
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
BatchedSpriteSheet::BatchedSpriteSheet(Engine& engine) {
|
BatchedSpriteSheet::BatchedSpriteSheet(Engine& engine) {
|
||||||
default_cam.setOrthographic();
|
|
||||||
default_cam.updateView();
|
|
||||||
|
|
||||||
float vertices[] = {
|
float vertices[] = {
|
||||||
-0.5f, 0.5f,
|
-0.5f, 0.5f,
|
||||||
-0.5f, -0.5f,
|
-0.5f, -0.5f,
|
||||||
@ -70,6 +67,10 @@ void BatchedSpriteSheet::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
|||||||
|
|
||||||
auto& scene = ssi->getScene();
|
auto& scene = ssi->getScene();
|
||||||
|
|
||||||
|
if (!scene.ctx().contains<Camera3D>()) {
|
||||||
|
return; // nothing to draw
|
||||||
|
}
|
||||||
|
|
||||||
struct sp_data {
|
struct sp_data {
|
||||||
SpriteSheet sp;
|
SpriteSheet sp;
|
||||||
struct instance_data {
|
struct instance_data {
|
||||||
@ -116,12 +117,9 @@ void BatchedSpriteSheet::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
|||||||
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
_vao->bind();
|
_vao->bind();
|
||||||
|
|
||||||
auto* cam = scene.try_ctx<Camera3D>();
|
auto& cam = scene.ctx().at<Camera3D>();
|
||||||
if (!cam) {
|
|
||||||
cam = &default_cam;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vp = cam->getViewProjection();
|
auto vp = cam.getViewProjection();
|
||||||
_shader->setUniformMat4f("_VP", vp);
|
_shader->setUniformMat4f("_VP", vp);
|
||||||
|
|
||||||
for (auto& sp_ent : batch_map) {
|
for (auto& sp_ent : batch_map) {
|
||||||
|
@ -37,8 +37,6 @@ namespace MM::OpenGL::RenderTasks {
|
|||||||
public:
|
public:
|
||||||
glm::vec4 default_color {1.f, 1.f, 1.f, 1.f};
|
glm::vec4 default_color {1.f, 1.f, 1.f, 1.f};
|
||||||
|
|
||||||
OpenGL::Camera3D default_cam;
|
|
||||||
|
|
||||||
BatchedSpriteSheet(Engine& engine);
|
BatchedSpriteSheet(Engine& engine);
|
||||||
~BatchedSpriteSheet(void);
|
~BatchedSpriteSheet(void);
|
||||||
|
|
||||||
|
@ -0,0 +1,161 @@
|
|||||||
|
#include "./bloom_combine.hpp"
|
||||||
|
|
||||||
|
#include <mm/fs_const_archiver.hpp>
|
||||||
|
#include <mm/services/opengl_renderer.hpp>
|
||||||
|
#include <mm/opengl/texture.hpp>
|
||||||
|
|
||||||
|
#include <tracy/Tracy.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
|
BloomCombine::BloomCombine(Engine& engine) {
|
||||||
|
float vertices[] = {
|
||||||
|
-1.f, 1.f,
|
||||||
|
-1.f, -1.f,
|
||||||
|
1.f, -1.f,
|
||||||
|
1.f, -1.f,
|
||||||
|
1.f, 1.f,
|
||||||
|
-1.f, 1.f,
|
||||||
|
};
|
||||||
|
|
||||||
|
_vertexBuffer = std::make_unique<Buffer>(vertices, 2 * 6 * sizeof(float), GL_STATIC_DRAW);
|
||||||
|
_vao = std::make_unique<VertexArrayObject>();
|
||||||
|
_vao->bind();
|
||||||
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
|
||||||
|
|
||||||
|
_vertexBuffer->unbind(GL_ARRAY_BUFFER);
|
||||||
|
_vao->unbind();
|
||||||
|
|
||||||
|
setupShaderFiles();
|
||||||
|
_shader = Shader::createF(engine, vertexPath, fragmentPath);
|
||||||
|
assert(_shader != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
BloomCombine::~BloomCombine(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BloomCombine::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
||||||
|
ZoneScopedN("RenderTasks::BloomCombine::render");
|
||||||
|
|
||||||
|
rs.targets[target_fbo]->bind(FrameBufferObject::W);
|
||||||
|
{ // TODO: move to fbo
|
||||||
|
GLsizei width {0};
|
||||||
|
GLsizei height {0};
|
||||||
|
{ // get size of fb <.<
|
||||||
|
auto& fbo_tex_arr = rs.targets[target_fbo]->_texAttachments;
|
||||||
|
if (fbo_tex_arr.empty()) {
|
||||||
|
//GLint o_type {0};
|
||||||
|
//glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &o_type);
|
||||||
|
//if (o_type == GL_NONE) {
|
||||||
|
//// default framebuffer or error
|
||||||
|
//SPDLOG_INFO("gl none");
|
||||||
|
//}
|
||||||
|
|
||||||
|
// nah, just assume screen res
|
||||||
|
std::tie(width, height) = engine.getService<Services::SDLService>().getWindowSize();
|
||||||
|
} else {
|
||||||
|
auto& target_fbo_tex = rs.targets[target_fbo]->_texAttachments.front();
|
||||||
|
width = target_fbo_tex->width;
|
||||||
|
height = target_fbo_tex->height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
_shader->bind();
|
||||||
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
|
_vao->bind();
|
||||||
|
|
||||||
|
auto& rm = MM::ResourceManager<Texture>::ref();
|
||||||
|
|
||||||
|
auto tex_0 = rm.get(entt::hashed_string::value(tex0.c_str()));
|
||||||
|
tex_0->bind(0);
|
||||||
|
|
||||||
|
auto tex_1 = rm.get(entt::hashed_string::value(tex1.c_str()));
|
||||||
|
tex_1->bind(1);
|
||||||
|
|
||||||
|
// assign image units
|
||||||
|
_shader->setUniform1i("_tex0", 0);
|
||||||
|
_shader->setUniform1i("_tex1", 1);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
_vao->unbind();
|
||||||
|
_vertexBuffer->unbind(GL_ARRAY_BUFFER);
|
||||||
|
_shader->unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BloomCombine::reloadShaders(Engine& engine) {
|
||||||
|
auto tmp_shader = Shader::createF(engine, vertexPath, fragmentPath);
|
||||||
|
if (tmp_shader) {
|
||||||
|
_shader = tmp_shader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BloomCombine::setupShaderFiles(void) {
|
||||||
|
FS_CONST_MOUNT_FILE(vertexPath,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
in vec2 _vertexPosition;
|
||||||
|
out vec2 _uv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(_vertexPosition, 0, 1);
|
||||||
|
_uv = vec2(_vertexPosition.x * 0.5 + 0.5, _vertexPosition.y * 0.5 + 0.5);
|
||||||
|
})")
|
||||||
|
|
||||||
|
FS_CONST_MOUNT_FILE(fragmentPath,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// tent sampling
|
||||||
|
#include "/shaders/builtin/sampling.glsl"
|
||||||
|
|
||||||
|
uniform sampler2D _tex0;
|
||||||
|
uniform sampler2D _tex1;
|
||||||
|
|
||||||
|
in vec2 _uv;
|
||||||
|
|
||||||
|
out vec3 _out_color;
|
||||||
|
|
||||||
|
vec3 tentSampling() {
|
||||||
|
// i hope the pipeline caches this
|
||||||
|
ivec2 tex0_size = textureSize(_tex0, 0); // TODO: lod
|
||||||
|
vec2 tex0_texel_step = vec2(1.0) / vec2(tex0_size);
|
||||||
|
|
||||||
|
return sampling2D_tent3x3_vec3(
|
||||||
|
_tex0,
|
||||||
|
_uv,
|
||||||
|
tex0_texel_step
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 simpleSampling() {
|
||||||
|
return texture(_tex0, _uv).rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
#ifdef SIMPLE_SAMPLING
|
||||||
|
_out_color = texture(_tex1, _uv).rgb + simpleSampling();
|
||||||
|
#else
|
||||||
|
_out_color = texture(_tex1, _uv).rgb + tentSampling();
|
||||||
|
#endif
|
||||||
|
})")
|
||||||
|
}
|
||||||
|
|
||||||
|
} // MM::OpenGL::RenderTasks
|
||||||
|
|
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mm/opengl/render_task.hpp>
|
||||||
|
#include <mm/opengl/shader.hpp>
|
||||||
|
#include <mm/opengl/buffer.hpp>
|
||||||
|
#include <mm/opengl/vertex_array_object.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
|
class BloomCombine : public RenderTask {
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Shader> _shader;
|
||||||
|
std::unique_ptr<Buffer> _vertexBuffer;
|
||||||
|
std::unique_ptr<VertexArrayObject> _vao;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BloomCombine(Engine& engine);
|
||||||
|
~BloomCombine(void);
|
||||||
|
|
||||||
|
const char* name(void) override { return "BloomCombine"; }
|
||||||
|
|
||||||
|
void render(Services::OpenGLRenderer& rs, Engine& engine) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const char* vertexPath {"shader/combine_render_task/vert.glsl"};
|
||||||
|
const char* fragmentPath {"shader/combine_render_task/frag.glsl"};
|
||||||
|
|
||||||
|
std::string target_fbo {"display"};
|
||||||
|
|
||||||
|
std::string tex0 {"tex0"}; // lower res
|
||||||
|
std::string tex1 {"tex1"};
|
||||||
|
|
||||||
|
void reloadShaders(Engine& engine);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupShaderFiles(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // MM::OpenGL::RenderTasks
|
||||||
|
|
@ -0,0 +1,114 @@
|
|||||||
|
#include "./bloom_extraction.hpp"
|
||||||
|
|
||||||
|
#include <mm/services/opengl_renderer.hpp>
|
||||||
|
#include <mm/fs_const_archiver.hpp>
|
||||||
|
#include <mm/opengl/texture.hpp>
|
||||||
|
|
||||||
|
#include <tracy/Tracy.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
|
BloomExtraction::BloomExtraction(Engine& engine) {
|
||||||
|
float vertices[] = {
|
||||||
|
-1.f, 1.f,
|
||||||
|
-1.f, -1.f,
|
||||||
|
1.f, -1.f,
|
||||||
|
1.f, -1.f,
|
||||||
|
1.f, 1.f,
|
||||||
|
-1.f, 1.f,
|
||||||
|
};
|
||||||
|
|
||||||
|
_vertexBuffer = std::make_unique<Buffer>(vertices, 2 * 6 * sizeof(float), GL_STATIC_DRAW);
|
||||||
|
_vao = std::make_unique<VertexArrayObject>();
|
||||||
|
_vao->bind();
|
||||||
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
|
||||||
|
|
||||||
|
_vertexBuffer->unbind(GL_ARRAY_BUFFER);
|
||||||
|
_vao->unbind();
|
||||||
|
|
||||||
|
setupShaderFiles();
|
||||||
|
_shader = Shader::createF(engine, vertexPath, fragmentPath);
|
||||||
|
assert(_shader != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
BloomExtraction::~BloomExtraction(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BloomExtraction::render(Services::OpenGLRenderer& rs, Engine&) {
|
||||||
|
ZoneScopedN("RenderTasks::BloomExtraction::render");
|
||||||
|
|
||||||
|
auto& target_fbo_ = rs.targets[target_fbo];
|
||||||
|
target_fbo_->bind(FrameBufferObject::W);
|
||||||
|
auto& target_fbo_tex = target_fbo_->_texAttachments.front();
|
||||||
|
glViewport(0, 0, target_fbo_tex->width, target_fbo_tex->height);
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
_shader->bind();
|
||||||
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
|
_vao->bind();
|
||||||
|
|
||||||
|
auto& rm = MM::ResourceManager<Texture>::ref();
|
||||||
|
|
||||||
|
auto tex = rm.get(entt::hashed_string::value(src_tex.c_str()));
|
||||||
|
tex->bind(0);
|
||||||
|
|
||||||
|
_shader->setUniform1i("color_tex", 0);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
_vao->unbind();
|
||||||
|
_vertexBuffer->unbind(GL_ARRAY_BUFFER);
|
||||||
|
_shader->unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BloomExtraction::reloadShaders(Engine& engine) {
|
||||||
|
auto tmp_shader = Shader::createF(engine, vertexPath, fragmentPath);
|
||||||
|
if (tmp_shader) {
|
||||||
|
_shader = tmp_shader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BloomExtraction::setupShaderFiles(void) {
|
||||||
|
FS_CONST_MOUNT_FILE(vertexPath,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
in vec2 _vertexPosition;
|
||||||
|
out vec2 _uv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(_vertexPosition, 0, 1);
|
||||||
|
_uv = vec2(_vertexPosition.x * 0.5 + 0.5, _vertexPosition.y * 0.5 + 0.5);
|
||||||
|
})")
|
||||||
|
|
||||||
|
FS_CONST_MOUNT_FILE(fragmentPath,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform sampler2D color_tex;
|
||||||
|
|
||||||
|
in vec2 _uv;
|
||||||
|
|
||||||
|
out vec3 _out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 color = texture(color_tex, _uv).rgb;
|
||||||
|
|
||||||
|
// TODO: expose threshold
|
||||||
|
_out_color = max(vec3(0.0), color - vec3(1.0));
|
||||||
|
})")
|
||||||
|
}
|
||||||
|
|
||||||
|
} // MM::OpenGL::RenderTasks
|
||||||
|
|
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mm/opengl/render_task.hpp>
|
||||||
|
#include <mm/opengl/shader.hpp>
|
||||||
|
#include <mm/opengl/buffer.hpp>
|
||||||
|
#include <mm/opengl/vertex_array_object.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
|
class BloomExtraction : public RenderTask {
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Shader> _shader;
|
||||||
|
std::unique_ptr<Buffer> _vertexBuffer;
|
||||||
|
std::unique_ptr<VertexArrayObject> _vao;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BloomExtraction(Engine& engine);
|
||||||
|
~BloomExtraction(void);
|
||||||
|
|
||||||
|
const char* name(void) override { return "BloomExtraction"; }
|
||||||
|
|
||||||
|
void render(Services::OpenGLRenderer& rs, Engine& engine) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const char* vertexPath {"shader/bloom_extraction_render_task/vert.glsl"};
|
||||||
|
const char* fragmentPath {"shader/bloom_extraction_render_task/frag.glsl"};
|
||||||
|
|
||||||
|
std::string target_fbo {"display"};
|
||||||
|
|
||||||
|
std::string src_tex {"hdr_color"};
|
||||||
|
|
||||||
|
void reloadShaders(Engine& engine);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupShaderFiles(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // MM::OpenGL::RenderTasks
|
||||||
|
|
@ -36,10 +36,8 @@ Blur::Blur(Engine& engine) {
|
|||||||
_vao->unbind();
|
_vao->unbind();
|
||||||
|
|
||||||
setupShaderFiles();
|
setupShaderFiles();
|
||||||
_hShader = Shader::createF(engine, vertexPath, fragmentHPath);
|
_shader = Shader::createF(engine, vertexPath, fragmentPath);
|
||||||
assert(_hShader != nullptr);
|
assert(_shader != nullptr);
|
||||||
_vShader = Shader::createF(engine, vertexPath, fragmentVPath);
|
|
||||||
assert(_vShader != nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Blur::~Blur(void) {
|
Blur::~Blur(void) {
|
||||||
@ -48,47 +46,44 @@ Blur::~Blur(void) {
|
|||||||
void Blur::render(Services::OpenGLRenderer& rs, Engine&) {
|
void Blur::render(Services::OpenGLRenderer& rs, Engine&) {
|
||||||
ZoneScopedN("MM::OpenGL::RenderTasks::Blur::render");
|
ZoneScopedN("MM::OpenGL::RenderTasks::Blur::render");
|
||||||
|
|
||||||
rs.targets[io_fbo]->bind(FrameBufferObject::W);
|
//rs.targets[io_fbo]->bind(FrameBufferObject::W);
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_BLEND); // TODO: test
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
auto& rm_t = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
auto& rm_t = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||||
auto tex_io = rm_t.get(entt::hashed_string::value(io_tex.c_str())); // TODO: perf problems
|
auto tex_in = rm_t.get(entt::hashed_string::value(in_tex.c_str())); // TODO: perf problems
|
||||||
|
auto tex_out = rm_t.get(entt::hashed_string::value(out_tex.c_str())); // TODO: perf problems
|
||||||
auto tex_temp = rm_t.get(entt::hashed_string::value(temp_tex.c_str())); // TODO: perf problems
|
auto tex_temp = rm_t.get(entt::hashed_string::value(temp_tex.c_str())); // TODO: perf problems
|
||||||
|
|
||||||
|
_shader->bind();
|
||||||
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
|
_vao->bind();
|
||||||
|
|
||||||
|
_shader->setUniform2f("tex_offset_factor", tex_offset_factor);
|
||||||
|
|
||||||
{ // horizontal
|
{ // horizontal
|
||||||
rs.targets[temp_fbo]->bind(FrameBufferObject::W);
|
rs.targets[temp_fbo]->bind(FrameBufferObject::W);
|
||||||
|
|
||||||
_hShader->bind();
|
|
||||||
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
|
||||||
_vao->bind();
|
|
||||||
|
|
||||||
glViewport(0, 0, tex_temp->width, tex_temp->height);
|
glViewport(0, 0, tex_temp->width, tex_temp->height);
|
||||||
tex_io->bind(0); // read
|
tex_in->bind(0); // read
|
||||||
|
|
||||||
_hShader->setUniform2f("tex_offset", tex_offset);
|
_shader->setUniform1i("horizontal", 1);
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // vertical
|
{ // vertical
|
||||||
rs.targets[io_fbo]->bind(FrameBufferObject::W);
|
rs.targets[out_fbo]->bind(FrameBufferObject::W);
|
||||||
|
|
||||||
_vShader->bind();
|
glViewport(0, 0, tex_out->width, tex_out->height);
|
||||||
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
|
||||||
_vao->bind();
|
|
||||||
|
|
||||||
glViewport(0, 0, tex_io->width, tex_io->height);
|
|
||||||
tex_temp->bind(0); // read
|
tex_temp->bind(0); // read
|
||||||
|
|
||||||
_vShader->setUniform2f("tex_offset", tex_offset);
|
_shader->setUniform1i("horizontal", 0);
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
_vao->unbind();
|
_vao->unbind();
|
||||||
_vertexBuffer->unbind(GL_ARRAY_BUFFER);
|
|
||||||
_vShader->unbind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blur::setupShaderFiles(void) {
|
void Blur::setupShaderFiles(void) {
|
||||||
@ -107,9 +102,7 @@ void main() {
|
|||||||
_tex_uv = _vertexPosition * 0.5 + 0.5;
|
_tex_uv = _vertexPosition * 0.5 + 0.5;
|
||||||
})")
|
})")
|
||||||
|
|
||||||
// TODO: deduplicate
|
FS_CONST_MOUNT_FILE(fragmentPath,
|
||||||
|
|
||||||
FS_CONST_MOUNT_FILE(fragmentHPath,
|
|
||||||
GLSL_VERSION_STRING
|
GLSL_VERSION_STRING
|
||||||
R"(
|
R"(
|
||||||
#ifdef GL_ES
|
#ifdef GL_ES
|
||||||
@ -119,54 +112,19 @@ R"(
|
|||||||
uniform sampler2D tex0;
|
uniform sampler2D tex0;
|
||||||
in vec2 _tex_uv;
|
in vec2 _tex_uv;
|
||||||
|
|
||||||
//uniform bool horizontal;
|
uniform bool horizontal;
|
||||||
const bool horizontal = true;
|
//const bool horizontal = true;
|
||||||
uniform vec2 tex_offset;
|
uniform vec2 tex_offset_factor;
|
||||||
|
|
||||||
const float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
|
const float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
|
||||||
|
|
||||||
out vec4 _out_color;
|
out vec4 _out_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
//vec2 tex_offset = vec2(1.0) / vec2(textureSize(tex0, 0)); // gets size of single texel
|
|
||||||
vec3 result = texture(tex0, _tex_uv).rgb * weight[0]; // current fragment's contribution
|
vec3 result = texture(tex0, _tex_uv).rgb * weight[0]; // current fragment's contribution
|
||||||
|
|
||||||
if (horizontal) {
|
vec2 tex_offset = vec2(1.0) / vec2(textureSize(tex0, 0).xy); // gets size of single texel
|
||||||
for (int i = 1; i < 5; i++) {
|
tex_offset *= tex_offset_factor;
|
||||||
result += texture(tex0, _tex_uv + vec2(tex_offset.x * float(i), 0.0)).rgb * weight[i];
|
|
||||||
result += texture(tex0, _tex_uv - vec2(tex_offset.x * float(i), 0.0)).rgb * weight[i];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i = 1; i < 5; i++) {
|
|
||||||
result += texture(tex0, _tex_uv + vec2(0.0, tex_offset.y * float(i))).rgb * weight[i];
|
|
||||||
result += texture(tex0, _tex_uv - vec2(0.0, tex_offset.y * float(i))).rgb * weight[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_out_color = vec4(result, 1.0);
|
|
||||||
})")
|
|
||||||
|
|
||||||
FS_CONST_MOUNT_FILE(fragmentVPath,
|
|
||||||
GLSL_VERSION_STRING
|
|
||||||
R"(
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision mediump float;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uniform sampler2D tex0;
|
|
||||||
in vec2 _tex_uv;
|
|
||||||
|
|
||||||
//uniform bool horizontal;
|
|
||||||
const bool horizontal = false;
|
|
||||||
uniform vec2 tex_offset;
|
|
||||||
|
|
||||||
const float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
|
|
||||||
|
|
||||||
out vec4 _out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
//vec2 tex_offset = vec2(1.0) / vec2(textureSize(tex0, 0)); // gets size of single texel
|
|
||||||
vec3 result = texture(tex0, _tex_uv).rgb * weight[0]; // current fragment's contribution
|
|
||||||
|
|
||||||
if (horizontal) {
|
if (horizontal) {
|
||||||
for (int i = 1; i < 5; i++) {
|
for (int i = 1; i < 5; i++) {
|
||||||
|
@ -17,8 +17,7 @@ namespace MM::OpenGL::RenderTasks {
|
|||||||
// this task expects to read and write to textures
|
// this task expects to read and write to textures
|
||||||
class Blur : public RenderTask {
|
class Blur : public RenderTask {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Shader> _hShader;
|
std::shared_ptr<Shader> _shader;
|
||||||
std::shared_ptr<Shader> _vShader;
|
|
||||||
std::unique_ptr<Buffer> _vertexBuffer;
|
std::unique_ptr<Buffer> _vertexBuffer;
|
||||||
std::unique_ptr<VertexArrayObject> _vao;
|
std::unique_ptr<VertexArrayObject> _vao;
|
||||||
|
|
||||||
@ -31,19 +30,19 @@ namespace MM::OpenGL::RenderTasks {
|
|||||||
void render(Services::OpenGLRenderer& rs, Engine& engine) override;
|
void render(Services::OpenGLRenderer& rs, Engine& engine) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const char* vertexPath = "shader/blur_render_task/vert.glsl";
|
const char* vertexPath {"shader/blur_render_task/vert.glsl"};
|
||||||
const char* fragmentHPath = "shader/blur_render_task/frag_h.glsl";
|
const char* fragmentPath {"shader/blur_render_task/frag_h.glsl"};
|
||||||
const char* fragmentVPath = "shader/blur_render_task/frag_v.glsl";
|
|
||||||
|
|
||||||
std::string io_fbo = "blur_io";
|
std::string out_fbo {"blur_io"};
|
||||||
std::string temp_fbo = "blur_temp";
|
std::string temp_fbo {"blur_temp"};
|
||||||
|
|
||||||
// bc of it beeing a 2 pass, we need to flipflop
|
// bc of it beeing a 2 pass, we need to flipflop
|
||||||
std::string io_tex = "blur_io";
|
std::string in_tex {"blur_io"};
|
||||||
std::string temp_tex = "blur_temp";
|
std::string out_tex {"blur_io"};
|
||||||
|
std::string temp_tex {"blur_temp"};
|
||||||
|
|
||||||
// determines the kernel lookup offset. "ideal" is 1/tex_size
|
// kernel lookup offset factor
|
||||||
glm::vec2 tex_offset {0.001f, 0.001f};
|
glm::vec2 tex_offset_factor {1.f, 1.f};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupShaderFiles(void);
|
void setupShaderFiles(void);
|
||||||
|
@ -0,0 +1,168 @@
|
|||||||
|
#include "./composition.hpp"
|
||||||
|
|
||||||
|
#include <mm/fs_const_archiver.hpp>
|
||||||
|
#include <mm/services/opengl_renderer.hpp>
|
||||||
|
#include <mm/opengl/texture.hpp>
|
||||||
|
|
||||||
|
#include <tracy/Tracy.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
|
Composition::Composition(MM::Engine& engine) {
|
||||||
|
float vertices[] = {
|
||||||
|
-1.f, 1.f,
|
||||||
|
-1.f, -1.f,
|
||||||
|
1.f, -1.f,
|
||||||
|
1.f, -1.f,
|
||||||
|
1.f, 1.f,
|
||||||
|
-1.f, 1.f,
|
||||||
|
};
|
||||||
|
|
||||||
|
_vertexBuffer = std::make_unique<MM::OpenGL::Buffer>(vertices, 2 * 6 * sizeof(float), GL_STATIC_DRAW);
|
||||||
|
_vao = std::make_unique<MM::OpenGL::VertexArrayObject>();
|
||||||
|
_vao->bind();
|
||||||
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
|
||||||
|
|
||||||
|
_vertexBuffer->unbind(GL_ARRAY_BUFFER);
|
||||||
|
_vao->unbind();
|
||||||
|
|
||||||
|
setupShaderFiles();
|
||||||
|
_shader = MM::OpenGL::Shader::createF(engine, vertexPath, fragmentPath);
|
||||||
|
assert(_shader != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Composition::~Composition(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Composition::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
|
||||||
|
ZoneScopedN("RenderTasks::Composition::render");
|
||||||
|
|
||||||
|
rs.targets[target_fbo]->bind(MM::OpenGL::FrameBufferObject::W);
|
||||||
|
{ // TODO: move to fbo
|
||||||
|
GLsizei width {0};
|
||||||
|
GLsizei height {0};
|
||||||
|
{ // get size of fb <.<
|
||||||
|
auto& fbo_tex_arr = rs.targets[target_fbo]->_texAttachments;
|
||||||
|
if (fbo_tex_arr.empty()) {
|
||||||
|
//GLint o_type {0};
|
||||||
|
//glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &o_type);
|
||||||
|
//if (o_type == GL_NONE) {
|
||||||
|
//// default framebuffer or error
|
||||||
|
//SPDLOG_INFO("gl none");
|
||||||
|
//}
|
||||||
|
|
||||||
|
// nah, just assume screen res
|
||||||
|
std::tie(width, height) = engine.getService<MM::Services::SDLService>().getWindowSize();
|
||||||
|
} else {
|
||||||
|
auto& target_fbo_tex = rs.targets[target_fbo]->_texAttachments.front();
|
||||||
|
width = target_fbo_tex->width;
|
||||||
|
height = target_fbo_tex->height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
_shader->bind();
|
||||||
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
|
_vao->bind();
|
||||||
|
|
||||||
|
auto& rm = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||||
|
|
||||||
|
auto tex_a = rm.get(entt::hashed_string::value(color_tex.c_str()));
|
||||||
|
tex_a->bind(0);
|
||||||
|
|
||||||
|
auto tex_n = rm.get(entt::hashed_string::value(bloom_tex.c_str()));
|
||||||
|
tex_n->bind(1);
|
||||||
|
|
||||||
|
// assign image units
|
||||||
|
_shader->setUniform1i("color_tex", 0);
|
||||||
|
_shader->setUniform1i("bloom_tex", 1);
|
||||||
|
|
||||||
|
_shader->setUniform1f("bloom_factor", bloom_factor);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
_vao->unbind();
|
||||||
|
_vertexBuffer->unbind(GL_ARRAY_BUFFER);
|
||||||
|
_shader->unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Composition::reloadShaders(MM::Engine& engine) {
|
||||||
|
auto tmp_shader = MM::OpenGL::Shader::createF(engine, vertexPath, fragmentPath);
|
||||||
|
if (tmp_shader) {
|
||||||
|
_shader = tmp_shader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Composition::setupShaderFiles(void) {
|
||||||
|
FS_CONST_MOUNT_FILE(vertexPath,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
in vec2 _vertexPosition;
|
||||||
|
out vec2 _uv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(_vertexPosition, 0, 1);
|
||||||
|
_uv = vec2(_vertexPosition.x * 0.5 + 0.5, _vertexPosition.y * 0.5 + 0.5);
|
||||||
|
})")
|
||||||
|
|
||||||
|
FS_CONST_MOUNT_FILE(fragmentPath,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "/shaders/builtin/tonemapping.glsl"
|
||||||
|
#include "/shaders/builtin/hashing.glsl"
|
||||||
|
|
||||||
|
uniform sampler2D color_tex;
|
||||||
|
uniform sampler2D bloom_tex;
|
||||||
|
|
||||||
|
// high bc 32bit on cpu
|
||||||
|
uniform highp float bloom_factor;
|
||||||
|
|
||||||
|
in vec2 _uv;
|
||||||
|
|
||||||
|
out vec3 _out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 color = texture(color_tex, _uv).rgb;
|
||||||
|
vec3 bloom = texture(bloom_tex, _uv).rgb;
|
||||||
|
|
||||||
|
vec3 comp = color + bloom * vec3(bloom_factor);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
const vec3 tint = vec3(1.5, 0.8, 1.1);
|
||||||
|
comp *= tint;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//// reinhart + gamma
|
||||||
|
//_out_color = pow(comp / (comp + vec3(1.0)), vec3(1.0 / 2.2));
|
||||||
|
|
||||||
|
// makes more sense pre bloom
|
||||||
|
//comp *= vec3(pow(2.0, -1.0)); // pre expose, -1 fstops
|
||||||
|
|
||||||
|
//_out_color = tonemapReinhard(comp);
|
||||||
|
_out_color = tonemapACESFilm(comp); // looks right
|
||||||
|
//_out_color = pow(tonemapACESFilm(pow(comp, vec3(2.2))), vec3(1.0/2.2)); // insane saturation o.O
|
||||||
|
//_out_color = pow(tonemapACESFilm(comp), vec3(1.0/2.2)); // looks just wrong
|
||||||
|
|
||||||
|
// noise dither for 8bit displays
|
||||||
|
_out_color += (hash32(gl_FragCoord.xy) * vec3(2.0) - vec3(1.0)) / vec3(255.0);
|
||||||
|
})")
|
||||||
|
}
|
||||||
|
|
||||||
|
} // MM::OpenGL::RenderTasks
|
||||||
|
|
@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mm/opengl/render_task.hpp>
|
||||||
|
#include <mm/opengl/shader.hpp>
|
||||||
|
#include <mm/opengl/buffer.hpp>
|
||||||
|
#include <mm/opengl/vertex_array_object.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
|
class Composition : public MM::OpenGL::RenderTask {
|
||||||
|
private:
|
||||||
|
std::shared_ptr<MM::OpenGL::Shader> _shader;
|
||||||
|
std::unique_ptr<MM::OpenGL::Buffer> _vertexBuffer;
|
||||||
|
std::unique_ptr<MM::OpenGL::VertexArrayObject> _vao;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Composition(MM::Engine& engine);
|
||||||
|
~Composition(void);
|
||||||
|
|
||||||
|
const char* name(void) override { return "Composition"; }
|
||||||
|
|
||||||
|
void render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const char* vertexPath {"shader/composition_render_task/vert.glsl"};
|
||||||
|
const char* fragmentPath {"shader/composition_render_task/frag.glsl"};
|
||||||
|
|
||||||
|
std::string target_fbo {"display"};
|
||||||
|
|
||||||
|
std::string color_tex {"hdr_color"};
|
||||||
|
std::string bloom_tex {"bloom"};
|
||||||
|
|
||||||
|
float bloom_factor {1.f};
|
||||||
|
|
||||||
|
void reloadShaders(MM::Engine& engine);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupShaderFiles(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // MM::OpenGL::RenderTasks
|
||||||
|
|
@ -47,7 +47,6 @@ FastSky::FastSky(MM::Engine& engine) {
|
|||||||
|
|
||||||
_vertexBuffer->unbind(GL_ARRAY_BUFFER);
|
_vertexBuffer->unbind(GL_ARRAY_BUFFER);
|
||||||
_vao->unbind();
|
_vao->unbind();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FastSky::~FastSky(void) {
|
FastSky::~FastSky(void) {
|
||||||
@ -56,6 +55,17 @@ FastSky::~FastSky(void) {
|
|||||||
void FastSky::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
|
void FastSky::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
|
||||||
ZoneScopedN("MM::OpenGL::RenderTasks::FastSky::render");
|
ZoneScopedN("MM::OpenGL::RenderTasks::FastSky::render");
|
||||||
|
|
||||||
|
auto* ssi = engine.tryService<MM::Services::SceneServiceInterface>();
|
||||||
|
if (ssi == nullptr) {
|
||||||
|
return; // nothing to draw
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& scene = ssi->getScene();
|
||||||
|
|
||||||
|
if (!scene.ctx().contains<Camera3D>()) {
|
||||||
|
return; // nothing to draw
|
||||||
|
}
|
||||||
|
|
||||||
rs.targets[target_fbo]->bind(MM::OpenGL::FrameBufferObject::W);
|
rs.targets[target_fbo]->bind(MM::OpenGL::FrameBufferObject::W);
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
@ -67,9 +77,8 @@ void FastSky::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
|
|||||||
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
_vao->bind();
|
_vao->bind();
|
||||||
|
|
||||||
auto& scene = engine.tryService<MM::Services::SceneServiceInterface>()->getScene();
|
|
||||||
{
|
{
|
||||||
auto& cam = scene.ctx<MM::OpenGL::Camera3D>();
|
auto& cam = scene.ctx().at<MM::OpenGL::Camera3D>();
|
||||||
MM::OpenGL::Camera3D tmp_cam = cam;
|
MM::OpenGL::Camera3D tmp_cam = cam;
|
||||||
// create cam with y up, bc shader says so
|
// create cam with y up, bc shader says so
|
||||||
tmp_cam.up = {0, 1, 0};
|
tmp_cam.up = {0, 1, 0};
|
||||||
@ -80,9 +89,13 @@ void FastSky::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto* ctx_ptr = scene.try_ctx<FastSkyContext>();
|
//auto* ctx_ptr = scene.try_ctx<FastSkyContext>();
|
||||||
if (!ctx_ptr) {
|
//if (!ctx_ptr) {
|
||||||
ctx_ptr = &_default_context;
|
//ctx_ptr = &_default_context;
|
||||||
|
//}
|
||||||
|
auto* ctx_ptr = &_default_context;
|
||||||
|
if (scene.ctx().contains<FastSkyContext>()) {
|
||||||
|
ctx_ptr = &scene.ctx().at<FastSkyContext>();
|
||||||
}
|
}
|
||||||
|
|
||||||
_shader->setUniform1f("time", ctx_ptr->time);
|
_shader->setUniform1f("time", ctx_ptr->time);
|
||||||
|
@ -0,0 +1,785 @@
|
|||||||
|
#include "./lite_particles2d.hpp"
|
||||||
|
|
||||||
|
#include <mm/opengl/shader.hpp>
|
||||||
|
#include <mm/opengl/shader_builder.hpp>
|
||||||
|
#include <mm/opengl/buffer.hpp>
|
||||||
|
#include <mm/opengl/instance_buffer.hpp>
|
||||||
|
#include <mm/opengl/vertex_array_object.hpp>
|
||||||
|
|
||||||
|
#include <mm/fs_const_archiver.hpp>
|
||||||
|
|
||||||
|
#include <mm/services/scene_service_interface.hpp>
|
||||||
|
#include <entt/entity/registry.hpp>
|
||||||
|
#include <mm/components/time_delta.hpp>
|
||||||
|
#include <mm/opengl/camera_3d.hpp>
|
||||||
|
|
||||||
|
#include "../components/lite_particles2d.hpp"
|
||||||
|
|
||||||
|
#include <mm/resource_manager.hpp>
|
||||||
|
#include "../lite_particles2d_type.hpp"
|
||||||
|
#include <mm/opengl/texture.hpp>
|
||||||
|
#include <mm/opengl/texture_loader.hpp>
|
||||||
|
|
||||||
|
#include <glm/common.hpp>
|
||||||
|
|
||||||
|
#include <tracy/Tracy.hpp>
|
||||||
|
#ifndef MM_OPENGL_3_GLES
|
||||||
|
#include <tracy/TracyOpenGL.hpp>
|
||||||
|
#else
|
||||||
|
#define TracyGpuContext
|
||||||
|
#define TracyGpuCollect
|
||||||
|
#define TracyGpuZone(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <mm/logger.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
|
// this was glsl code
|
||||||
|
// TODO: refactor this
|
||||||
|
// packing helper
|
||||||
|
static uint16_t pack_float_16bit(const float a, const float pack_mult) {
|
||||||
|
uint32_t a_bits = uint32_t(abs(a*pack_mult));
|
||||||
|
return (a_bits & 0x7fffu) | (uint16_t(a>=0.0 ? 0u : 1u) << 15u);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float pack_vel_multiplier = 1000.0;
|
||||||
|
|
||||||
|
static float pack_vel(const glm::vec2 vel) {
|
||||||
|
// ez just mult and save as shorts
|
||||||
|
return glm::uintBitsToFloat(
|
||||||
|
(pack_float_16bit(vel.x, pack_vel_multiplier) << 16u)
|
||||||
|
| pack_float_16bit(vel.y, pack_vel_multiplier)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float pack_age_multiplier = 10000.0;
|
||||||
|
|
||||||
|
static float pack_age_type(const float age, const uint16_t type) {
|
||||||
|
return glm::uintBitsToFloat((pack_float_16bit(age, pack_age_multiplier) << 16u) | (type & 0xffffu));
|
||||||
|
}
|
||||||
|
|
||||||
|
LiteParticles2D::LiteParticles2D(Engine& engine) {
|
||||||
|
_particles_0_buffers[0] = std::make_unique<InstanceBuffer<glm::vec4>>();
|
||||||
|
_particles_0_buffers[1] = std::make_unique<InstanceBuffer<glm::vec4>>();
|
||||||
|
|
||||||
|
resetBuffers();
|
||||||
|
|
||||||
|
_tf_vao[0] = std::make_unique<VertexArrayObject>();
|
||||||
|
_tf_vao[1] = std::make_unique<VertexArrayObject>();
|
||||||
|
|
||||||
|
auto setup_tf_vao = [this](size_t i) {
|
||||||
|
_tf_vao[i]->bind();
|
||||||
|
_particles_0_buffers[i]->bind();
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
|
_particles_0_buffers[i]->unbind();
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
_tf_vao[i]->unbind();
|
||||||
|
};
|
||||||
|
|
||||||
|
setup_tf_vao(0);
|
||||||
|
setup_tf_vao(1);
|
||||||
|
|
||||||
|
|
||||||
|
// rendering
|
||||||
|
|
||||||
|
_render_vao[0] = std::make_unique<VertexArrayObject>();
|
||||||
|
_render_vao[1] = std::make_unique<VertexArrayObject>();
|
||||||
|
|
||||||
|
auto setup_rend_vao = [this](size_t i) {
|
||||||
|
size_t next_index = i == 0 ? 1 : 0;
|
||||||
|
|
||||||
|
_render_vao[i]->bind();
|
||||||
|
// bc we computed into the other one 0->1
|
||||||
|
_particles_0_buffers[next_index]->bind();
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
|
_particles_0_buffers[next_index]->unbind();
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
_render_vao[i]->unbind();
|
||||||
|
};
|
||||||
|
|
||||||
|
setup_rend_vao(0);
|
||||||
|
setup_rend_vao(1);
|
||||||
|
|
||||||
|
resetTypeBuffers();
|
||||||
|
|
||||||
|
setupShaderFiles();
|
||||||
|
|
||||||
|
_tf_shader = ShaderBuilder::start()
|
||||||
|
.addStageVertexF(engine, vertexPathTF)
|
||||||
|
.addTransformFeedbackVarying("_out_0")
|
||||||
|
.addStageFragmentF(engine, fragmentPathTF) // empty stage
|
||||||
|
.finish();
|
||||||
|
assert(static_cast<bool>(_tf_shader));
|
||||||
|
|
||||||
|
_points_shader = ShaderBuilder::start()
|
||||||
|
.addStageVertexF(engine, vertexPathPoints)
|
||||||
|
.addStageFragmentF(engine, fragmentPathPoints)
|
||||||
|
.finish();
|
||||||
|
assert(static_cast<bool>(_points_shader));
|
||||||
|
|
||||||
|
_last_time = clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
LiteParticles2D::~LiteParticles2D(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteParticles2D::uploadParticles(Services::OpenGLRenderer&, Scene& scene) {
|
||||||
|
ZoneScopedN("MM::OpenGL::RenderTasks::LiteParticles2D::uploadParticles");
|
||||||
|
|
||||||
|
if (!scene.ctx().contains<Components::LiteParticles2DUploadQueue>()) {
|
||||||
|
// TODO: warn?
|
||||||
|
return; // nothing to upload
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& queue = scene.ctx().at<Components::LiteParticles2DUploadQueue>();
|
||||||
|
|
||||||
|
while (!queue.queue.empty()) {
|
||||||
|
// get range
|
||||||
|
auto range_size = queue.queue.size();
|
||||||
|
size_t range_first = _particle_buffer_next_index;
|
||||||
|
if (_particle_buffer_next_index + (range_size - 1) >= _particle_buffer_size) { // wrap
|
||||||
|
range_size = _particle_buffer_size - range_first;
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::cerr << "s:" << range_size << " f:" << range_first << "\n";
|
||||||
|
|
||||||
|
//assert(range_first <= range_last);
|
||||||
|
assert(range_size >= 1);
|
||||||
|
|
||||||
|
size_t curr_buff_index = first_particles_buffer ? 0 : 1;
|
||||||
|
|
||||||
|
#ifdef MM_OPENGL_3_GLES
|
||||||
|
// i think invalidating the whole buffer, instead of only the range results in undefined behaviour, but webgl wont let me otherwise and it seems to work
|
||||||
|
const auto gl_access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT;
|
||||||
|
#else
|
||||||
|
// turns out, amd desktop opengl drivers dont like invalidate buffer (everyone else seems to be ok)
|
||||||
|
const auto gl_access = GL_MAP_WRITE_BIT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto* data_0 = _particles_0_buffers[curr_buff_index]->mapRange(range_first, range_size, gl_access);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < range_size; i++) {
|
||||||
|
auto& p = queue.queue.front();
|
||||||
|
|
||||||
|
uint16_t type = 0u;
|
||||||
|
if (_type_map.count(p.type_id)) {
|
||||||
|
type = _type_map.at(p.type_id);
|
||||||
|
} else {
|
||||||
|
SPDLOG_ERROR("unknown type {}, defaulting to zero.", p.type_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_0[i] = glm::vec4(
|
||||||
|
p.pos.x, p.pos.y,
|
||||||
|
pack_vel(p.vel),
|
||||||
|
pack_age_type(p.age, type)
|
||||||
|
);
|
||||||
|
|
||||||
|
queue.queue.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
_particles_0_buffers[curr_buff_index]->unmap();
|
||||||
|
|
||||||
|
_particle_buffer_next_index = (range_first + range_size) % (_particle_buffer_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteParticles2D::computeParticles(Services::OpenGLRenderer&, Scene& scene) {
|
||||||
|
ZoneScopedN("MM::OpenGL::RenderTasks::LiteParticles2D::computeParticles");
|
||||||
|
using namespace entt::literals;
|
||||||
|
_tf_shader->bind();
|
||||||
|
|
||||||
|
{ // time
|
||||||
|
auto newNow = clock::now();
|
||||||
|
std::chrono::duration<double, std::ratio<1, 1>> deltaTime = newNow - _last_time;
|
||||||
|
_last_time = newNow;
|
||||||
|
|
||||||
|
float time_delta = deltaTime.count() * scene.ctx().at<MM::Components::TimeDelta>().deltaFactor;
|
||||||
|
_time += time_delta;
|
||||||
|
_tf_shader->setUniform1f("_time_delta", time_delta);
|
||||||
|
_tf_shader->setUniform1f("_time", _time);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& rm_t = MM::ResourceManager<Texture>::ref();
|
||||||
|
rm_t.get("MM::LiteParticles2DTypes::Compute"_hs)->bind(0);
|
||||||
|
|
||||||
|
//_tf_shader->setUniform3f("_env_vec", env_vec * env_force);
|
||||||
|
//_tf_shader->setUniform1f("_noise_force", noise_force);
|
||||||
|
//_tf_shader->setUniform1f("_dampening", dampening);
|
||||||
|
|
||||||
|
const size_t curr_index = first_particles_buffer ? 0 : 1;
|
||||||
|
const size_t next_index = first_particles_buffer ? 1 : 0;
|
||||||
|
|
||||||
|
// bind in particles
|
||||||
|
_tf_vao[curr_index]->bind();
|
||||||
|
|
||||||
|
// bind out particles
|
||||||
|
// the order is the same as given to the ShaderBuilder
|
||||||
|
_particles_0_buffers[next_index]->bindBase(0);
|
||||||
|
|
||||||
|
glEnable(GL_RASTERIZER_DISCARD); // compute only rn
|
||||||
|
|
||||||
|
glBeginTransformFeedback(GL_POINTS);
|
||||||
|
glDrawArrays(GL_POINTS, 0, _particle_buffer_size);
|
||||||
|
glEndTransformFeedback();
|
||||||
|
|
||||||
|
glDisable(GL_RASTERIZER_DISCARD);
|
||||||
|
|
||||||
|
// TODO: move this
|
||||||
|
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
|
||||||
|
//glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, 0);
|
||||||
|
|
||||||
|
_tf_vao[curr_index]->unbind();
|
||||||
|
_tf_shader->unbind();
|
||||||
|
|
||||||
|
// TODO: do i need this??
|
||||||
|
glFlush();
|
||||||
|
|
||||||
|
first_particles_buffer = !first_particles_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteParticles2D::renderParticles(Services::OpenGLRenderer& rs, Scene& scene) {
|
||||||
|
using namespace entt::literals;
|
||||||
|
ZoneScopedN("MM::OpenGL::RenderTasks::LiteParticles2D::renderParticles");
|
||||||
|
|
||||||
|
if (!scene.ctx().contains<Camera3D>()) {
|
||||||
|
return; // nothing to draw
|
||||||
|
}
|
||||||
|
|
||||||
|
//glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthMask(GL_FALSE); // dont write to depth
|
||||||
|
//glEnable(GL_BLEND);
|
||||||
|
|
||||||
|
#ifndef MM_OPENGL_3_GLES
|
||||||
|
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rs.targets[target_fbo]->bind(FrameBufferObject::RW);
|
||||||
|
|
||||||
|
_points_shader->bind();
|
||||||
|
|
||||||
|
auto& rm_t = MM::ResourceManager<Texture>::ref();
|
||||||
|
rm_t.get("MM::LiteParticles2DTypes::Render"_hs)->bind(0);
|
||||||
|
|
||||||
|
Camera3D& cam = scene.ctx().at<Camera3D>();
|
||||||
|
_points_shader->setUniformMat4f("_vp", cam.getViewProjection());
|
||||||
|
|
||||||
|
GLint view_port[4];
|
||||||
|
glGetIntegerv(GL_VIEWPORT, view_port);
|
||||||
|
|
||||||
|
// width
|
||||||
|
_points_shader->setUniform1f("_point_size", view_port[2]/cam.horizontalViewPortSize);
|
||||||
|
|
||||||
|
const size_t curr_index = first_particles_buffer; // 0->1 / 1->0 bc compute phase also switches
|
||||||
|
_render_vao[curr_index]->bind();
|
||||||
|
|
||||||
|
glDrawArrays(GL_POINTS, 0, _particle_buffer_size);
|
||||||
|
|
||||||
|
_render_vao[curr_index]->unbind();
|
||||||
|
_points_shader->unbind();
|
||||||
|
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteParticles2D::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
||||||
|
ZoneScopedN("MM::OpenGL::RenderTasks::LiteParticles2D::render");
|
||||||
|
|
||||||
|
auto* scene_service = engine.tryService<MM::Services::SceneServiceInterface>();
|
||||||
|
if (scene_service == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene& scene = scene_service->getScene();
|
||||||
|
|
||||||
|
uploadParticles(rs, scene);
|
||||||
|
computeParticles(rs, scene);
|
||||||
|
renderParticles(rs, scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteParticles2D::setParticleBufferSize(uint32_t new_buffer_size) {
|
||||||
|
_particle_buffer_size = new_buffer_size;
|
||||||
|
|
||||||
|
resetBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteParticles2D::resetBuffers(void) {
|
||||||
|
const auto gl_buffer_type = GL_DYNAMIC_COPY;
|
||||||
|
auto reset_buffer_0 = [this](size_t i) {
|
||||||
|
auto* data = _particles_0_buffers[i]->map(_particle_buffer_size, gl_buffer_type);
|
||||||
|
for (size_t x = 0; x < _particle_buffer_size; x++) {
|
||||||
|
data[x] = glm::vec4{
|
||||||
|
0.f, 0.f, // pos
|
||||||
|
0, // vel (pack, but 0 should mean 0)
|
||||||
|
pack_age_type(2.f, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_particles_0_buffers[i]->unmap();
|
||||||
|
};
|
||||||
|
|
||||||
|
reset_buffer_0(0);
|
||||||
|
reset_buffer_0(1);
|
||||||
|
|
||||||
|
_particle_buffer_next_index = 0; // only matters if resize
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteParticles2D::resetTypeBuffers(void) {
|
||||||
|
using namespace entt::literals;
|
||||||
|
|
||||||
|
// clear
|
||||||
|
_type_map.clear();
|
||||||
|
|
||||||
|
// build data
|
||||||
|
std::vector<float> type_compute_upload_buffer {};
|
||||||
|
std::vector<float> type_render_upload_buffer {};
|
||||||
|
|
||||||
|
// TODO: replace with "default"
|
||||||
|
{ // 0
|
||||||
|
// TODO: propper 0 particle
|
||||||
|
LiteParticles2DType {
|
||||||
|
{
|
||||||
|
0.04f, //age_delta;
|
||||||
|
|
||||||
|
{0.f, 0.f}, //force_vec
|
||||||
|
|
||||||
|
5.f, //turbulence;
|
||||||
|
0.1f, //turbulence_noise_scale;
|
||||||
|
0.01f, //turbulence_individuality;
|
||||||
|
0.5f, //turbulence_time_scale;
|
||||||
|
|
||||||
|
1.0f, //dampening;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{1.8f, 3.f, 6.f, 1.f}, //color_start;
|
||||||
|
{2.3f, 1.2f, 0.5f, 1.f}, //color_end;
|
||||||
|
|
||||||
|
0.1f, //size_start;
|
||||||
|
0.02f //size_end;
|
||||||
|
}
|
||||||
|
}.upload(type_compute_upload_buffer, type_render_upload_buffer);
|
||||||
|
}
|
||||||
|
// defaults
|
||||||
|
_type_map[0u] = 0u;
|
||||||
|
_type_map[""_hs] = 0u;
|
||||||
|
_type_map["0"_hs] = 0u;
|
||||||
|
_type_map["default"_hs] = 0u;
|
||||||
|
|
||||||
|
auto& rm_lpt = MM::ResourceManager<LiteParticles2DType>::ref();
|
||||||
|
uint16_t curr_idx = 1; // 0 is reserved for now :P
|
||||||
|
rm_lpt.each([this, &curr_idx, &type_compute_upload_buffer, &type_render_upload_buffer](const auto type_id, const auto& res) {
|
||||||
|
_type_map[type_id] = curr_idx++;
|
||||||
|
res->upload(type_compute_upload_buffer, type_render_upload_buffer);
|
||||||
|
});
|
||||||
|
SPDLOG_INFO("have {} LiteParticles2D types.", curr_idx);
|
||||||
|
|
||||||
|
// upload / create textures
|
||||||
|
// HACK: refactor loader
|
||||||
|
auto& rm_t = MM::ResourceManager<Texture>::ref();
|
||||||
|
{ // compute
|
||||||
|
auto r = rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"MM::LiteParticles2DTypes::Compute",
|
||||||
|
GL_R32F,
|
||||||
|
LiteParticles2DType::Compute::_member_count, curr_idx,
|
||||||
|
GL_RED,
|
||||||
|
GL_FLOAT
|
||||||
|
);
|
||||||
|
assert(r);
|
||||||
|
|
||||||
|
// and re-"create"
|
||||||
|
rm_t.get("MM::LiteParticles2DTypes::Compute"_hs)->bind(0); // hack
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_R32F,
|
||||||
|
LiteParticles2DType::Compute::_member_count, curr_idx,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
GL_FLOAT,
|
||||||
|
type_compute_upload_buffer.data()
|
||||||
|
);
|
||||||
|
// just in case
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // render
|
||||||
|
auto r = rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"MM::LiteParticles2DTypes::Render",
|
||||||
|
GL_R32F,
|
||||||
|
LiteParticles2DType::Render::_member_count, curr_idx,
|
||||||
|
GL_RED,
|
||||||
|
GL_FLOAT
|
||||||
|
);
|
||||||
|
assert(r);
|
||||||
|
|
||||||
|
// and re-"create"
|
||||||
|
rm_t.get("MM::LiteParticles2DTypes::Render"_hs)->bind(0); // hack
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_R32F,
|
||||||
|
LiteParticles2DType::Render::_member_count, curr_idx,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
GL_FLOAT,
|
||||||
|
type_render_upload_buffer.data()
|
||||||
|
);
|
||||||
|
// just in case
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiteParticles2D::setupShaderFiles(void) {
|
||||||
|
FS_CONST_MOUNT_FILE(commonPathTF,
|
||||||
|
R"(
|
||||||
|
|
||||||
|
#include "/shaders/builtin/noise.glsl"
|
||||||
|
|
||||||
|
// variants, based on offset, might be faster
|
||||||
|
vec2 var_noise22(vec2 x) {
|
||||||
|
return vec2(noise12(x), noise12(x + 13037.0));
|
||||||
|
}
|
||||||
|
vec2 var_noise23(vec3 x) {
|
||||||
|
return vec2(noise13(x), noise13(x + 13037.0));
|
||||||
|
}
|
||||||
|
vec2 var_noise24(vec4 x) {
|
||||||
|
return vec2(noise14(x), noise14(x + 13037.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// packing helper
|
||||||
|
uint pack_float_16bit(in float a, in float pack_mult) {
|
||||||
|
uint a_bits = uint(abs(a*pack_mult));
|
||||||
|
|
||||||
|
return (a_bits & 0x7fffu) | (uint(a>=0.0 ? 0u : 1u) << 15u);
|
||||||
|
}
|
||||||
|
|
||||||
|
float unpack_float_16bit(in uint a, in float pack_mult) {
|
||||||
|
return (float(a & 0x7fffu) / pack_mult) * ((a >> 15u) != 0u ? -1.0 : 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float pack_vel_multiplier = 1000.0;
|
||||||
|
|
||||||
|
float pack_vel(in vec2 vel) {
|
||||||
|
return uintBitsToFloat(
|
||||||
|
(pack_float_16bit(vel.x, pack_vel_multiplier) << 16u)
|
||||||
|
| pack_float_16bit(vel.y, pack_vel_multiplier)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 unpack_vel(in float pack) {
|
||||||
|
uint pack_bits = floatBitsToUint(pack);
|
||||||
|
return vec2(
|
||||||
|
unpack_float_16bit(pack_bits >> 16u, pack_vel_multiplier),
|
||||||
|
unpack_float_16bit(pack_bits & 0xffffu, pack_vel_multiplier)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float pack_age_multiplier = 10000.0;
|
||||||
|
|
||||||
|
float pack_age_type(in float age, in uint type) {
|
||||||
|
return uintBitsToFloat(
|
||||||
|
(pack_float_16bit(age, pack_age_multiplier) << 16u)
|
||||||
|
| (type & 0xffffu)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
)")
|
||||||
|
FS_CONST_MOUNT_FILE(vertexPathTF,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp float;
|
||||||
|
precision highp int;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "./common.glsl"
|
||||||
|
|
||||||
|
uniform float _time_delta;
|
||||||
|
uniform float _time;
|
||||||
|
|
||||||
|
uniform sampler2D _type_buffer;
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 _in_0;
|
||||||
|
|
||||||
|
out vec4 _out_0;
|
||||||
|
|
||||||
|
void set_out(in vec2 pos, in vec2 vel, in float age, in uint type) {
|
||||||
|
_out_0 = vec4(
|
||||||
|
pos.x, pos.y,
|
||||||
|
pack_vel(vel),
|
||||||
|
pack_age_type(age, type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_in(out vec2 pos, out vec2 vel, out float age, out uint type) {
|
||||||
|
pos = _in_0.xy;
|
||||||
|
vel = unpack_vel(_in_0.z);
|
||||||
|
|
||||||
|
uint age_type_bits = floatBitsToUint(_in_0.w);
|
||||||
|
age = unpack_float_16bit(age_type_bits >> 16u, pack_age_multiplier);
|
||||||
|
type = age_type_bits & 0xffffu;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sim_config_type {
|
||||||
|
highp float age_delta;
|
||||||
|
|
||||||
|
//highp float gravity;
|
||||||
|
vec2 force_vec;
|
||||||
|
|
||||||
|
highp float turbulence;
|
||||||
|
highp float turbulence_noise_scale;
|
||||||
|
highp float turbulence_individuality;
|
||||||
|
highp float turbulence_time_scale;
|
||||||
|
|
||||||
|
highp float dampening;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec2 fetch_vec2(in uint offset, in uint type) {
|
||||||
|
return vec2(
|
||||||
|
texelFetch(_type_buffer, ivec2(offset+0u, type), 0).r,
|
||||||
|
texelFetch(_type_buffer, ivec2(offset+1u, type), 0).r
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_config_type fetch_type_config(uint type) {
|
||||||
|
return sim_config_type(
|
||||||
|
texelFetch(_type_buffer, ivec2(0u, type), 0).r,
|
||||||
|
fetch_vec2(1u, type),
|
||||||
|
texelFetch(_type_buffer, ivec2(3u, type), 0).r,
|
||||||
|
texelFetch(_type_buffer, ivec2(4u, type), 0).r,
|
||||||
|
texelFetch(_type_buffer, ivec2(5u, type), 0).r,
|
||||||
|
texelFetch(_type_buffer, ivec2(6u, type), 0).r,
|
||||||
|
texelFetch(_type_buffer, ivec2(7u, type), 0).r
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 calc_turbulence_vec(
|
||||||
|
in vec2 pos,
|
||||||
|
in float turbulence,
|
||||||
|
in float turbulence_noise_scale,
|
||||||
|
in float turbulence_individuality,
|
||||||
|
in float turbulence_time_scale
|
||||||
|
) {
|
||||||
|
vec2 turbulence_vec =
|
||||||
|
(
|
||||||
|
noise24(vec4(
|
||||||
|
pos * turbulence_noise_scale,
|
||||||
|
float(gl_VertexID & 0x0fff) * turbulence_individuality,
|
||||||
|
_time * turbulence_time_scale
|
||||||
|
))
|
||||||
|
- vec2(0.5)
|
||||||
|
)
|
||||||
|
* 2.0
|
||||||
|
* turbulence
|
||||||
|
;
|
||||||
|
|
||||||
|
return turbulence_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_particle_sim(
|
||||||
|
// inout (particle mem)
|
||||||
|
inout vec2 pos,
|
||||||
|
inout vec2 vel,
|
||||||
|
|
||||||
|
inout float age,
|
||||||
|
inout uint type,
|
||||||
|
|
||||||
|
// type specific config
|
||||||
|
in sim_config_type conf
|
||||||
|
) {
|
||||||
|
vec2 turbulence_vec = calc_turbulence_vec(
|
||||||
|
pos,
|
||||||
|
conf.turbulence,
|
||||||
|
conf.turbulence_noise_scale,
|
||||||
|
conf.turbulence_individuality,
|
||||||
|
conf.turbulence_time_scale
|
||||||
|
);
|
||||||
|
|
||||||
|
vel = (vel + (
|
||||||
|
turbulence_vec +
|
||||||
|
//vec2(0.0, -10.0) * conf.gravity
|
||||||
|
conf.force_vec
|
||||||
|
) * _time_delta);
|
||||||
|
|
||||||
|
// TODO: this does not behave correctly
|
||||||
|
// TODO: experiment with formula
|
||||||
|
vel = mix(vel, vec2(0.0), conf.dampening * _time_delta);
|
||||||
|
|
||||||
|
pos = pos + (vel * _time_delta);
|
||||||
|
|
||||||
|
age = min(age + (conf.age_delta * _time_delta), 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 pos;
|
||||||
|
vec2 vel;
|
||||||
|
float age;
|
||||||
|
uint type;
|
||||||
|
get_in(pos, vel, age, type);
|
||||||
|
|
||||||
|
sim_config_type conf = fetch_type_config(type);
|
||||||
|
|
||||||
|
calc_particle_sim(
|
||||||
|
pos,
|
||||||
|
vel,
|
||||||
|
age,
|
||||||
|
type,
|
||||||
|
|
||||||
|
conf
|
||||||
|
);
|
||||||
|
|
||||||
|
set_out(pos, vel, age, type);
|
||||||
|
})")
|
||||||
|
|
||||||
|
FS_CONST_MOUNT_FILE(fragmentPathTF,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// i am never executed
|
||||||
|
|
||||||
|
out vec4 _out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
_out_color = vec4(1.0);
|
||||||
|
})")
|
||||||
|
|
||||||
|
FS_CONST_MOUNT_FILE(vertexPathPoints,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp float;
|
||||||
|
precision highp int;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "./common.glsl"
|
||||||
|
|
||||||
|
uniform mat4 _vp;
|
||||||
|
uniform float _point_size;
|
||||||
|
|
||||||
|
uniform sampler2D _type_buffer;
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 _in_0;
|
||||||
|
|
||||||
|
void get_in(out vec2 pos, out vec2 vel, out float age, out uint type) {
|
||||||
|
pos = _in_0.xy;
|
||||||
|
vel = unpack_vel(_in_0.z);
|
||||||
|
|
||||||
|
uint age_type_bits = floatBitsToUint(_in_0.w);
|
||||||
|
age = unpack_float_16bit(age_type_bits >> 16u, pack_age_multiplier);
|
||||||
|
type = age_type_bits & 0xffffu;
|
||||||
|
}
|
||||||
|
|
||||||
|
out vec4 _frag_color;
|
||||||
|
flat out int _vertex_id;
|
||||||
|
|
||||||
|
struct config_type {
|
||||||
|
highp vec4 color_start;
|
||||||
|
highp vec4 color_end;
|
||||||
|
|
||||||
|
highp float size_start;
|
||||||
|
highp float size_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec4 fetch_vec4(in uint offset, in uint type) {
|
||||||
|
return vec4(
|
||||||
|
texelFetch(_type_buffer, ivec2(offset+0u, type), 0).r,
|
||||||
|
texelFetch(_type_buffer, ivec2(offset+1u, type), 0).r,
|
||||||
|
texelFetch(_type_buffer, ivec2(offset+2u, type), 0).r,
|
||||||
|
texelFetch(_type_buffer, ivec2(offset+3u, type), 0).r
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
config_type fetch_config_type(uint type) {
|
||||||
|
return config_type(
|
||||||
|
fetch_vec4(0u, type),
|
||||||
|
fetch_vec4(4u, type),
|
||||||
|
texelFetch(_type_buffer, ivec2(8u, type), 0).r,
|
||||||
|
texelFetch(_type_buffer, ivec2(9u, type), 0).r
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 in_pos;
|
||||||
|
vec2 in_vel;
|
||||||
|
|
||||||
|
float in_age;
|
||||||
|
uint in_type;
|
||||||
|
|
||||||
|
get_in(in_pos, in_vel, in_age, in_type);
|
||||||
|
|
||||||
|
// skip dead
|
||||||
|
if (in_age > 1.0) {
|
||||||
|
_frag_color = vec4(1.0, 0.0, 1.0, 0.0); // so it does not get rendered (alpha)
|
||||||
|
gl_Position.z = 100000000000.0; // clip (does not allways work <.<)
|
||||||
|
// gl_PointSize = 0.0; // ub
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_type conf = fetch_config_type(in_type);
|
||||||
|
|
||||||
|
//_frag_color = mix(conf.color_start, conf.color_end, in_age);
|
||||||
|
_frag_color = mix(conf.color_start, conf.color_end, smoothstep(0.0, 1.0, in_age));
|
||||||
|
|
||||||
|
gl_Position = _vp * vec4(in_pos, 0.0, 1.0);
|
||||||
|
|
||||||
|
// TODO: fix before merge
|
||||||
|
gl_Position.z = -1.0; // hack for ortho ??
|
||||||
|
|
||||||
|
gl_PointSize = max(mix(conf.size_start, conf.size_end, in_age) * _point_size, 1.0);
|
||||||
|
|
||||||
|
_vertex_id = gl_VertexID;
|
||||||
|
})")
|
||||||
|
|
||||||
|
FS_CONST_MOUNT_FILE(fragmentPathPoints,
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
in vec4 _frag_color;
|
||||||
|
flat in int _vertex_id;
|
||||||
|
|
||||||
|
out vec4 _out_color;
|
||||||
|
|
||||||
|
bool should_discard(vec2 screen_pos, float alpha) {
|
||||||
|
const int dither[8 * 8] = int[8 * 8](
|
||||||
|
0, 32, 8, 40, 2, 34, 10, 42,
|
||||||
|
48, 16, 56, 24, 50, 18, 58, 26,
|
||||||
|
12, 44, 4, 36, 14, 46, 6, 38,
|
||||||
|
60, 28, 52, 20, 62, 30, 54, 22,
|
||||||
|
3, 35, 11, 43, 1, 33, 9, 41,
|
||||||
|
51, 19, 59, 27, 49, 17, 57, 25,
|
||||||
|
15, 47, 7, 39, 13, 45, 5, 37,
|
||||||
|
63, 31, 55, 23, 61, 29, 53, 21
|
||||||
|
);
|
||||||
|
|
||||||
|
int mat_value = dither[int(screen_pos.x)%8 + 8 * (int(screen_pos.y)%8)];
|
||||||
|
float n_mat_value = float(mat_value) * (1.0/64.0);
|
||||||
|
|
||||||
|
return n_mat_value < 1.0 - alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
if (should_discard(vec2(gl_FragCoord.x + float(_vertex_id%8), gl_FragCoord.y + float(_vertex_id%7)), _frag_color.a)) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
_out_color = vec4(_frag_color.rgb, 1.0);
|
||||||
|
})")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // MM::OpenGL::RenderTasks
|
||||||
|
|
@ -0,0 +1,83 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mm/opengl/render_task.hpp>
|
||||||
|
#include <mm/services/opengl_renderer.hpp>
|
||||||
|
|
||||||
|
#include <glm/fwd.hpp>
|
||||||
|
|
||||||
|
// TODO: make the renderer provide a time delta
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
// fwd
|
||||||
|
namespace MM::OpenGL {
|
||||||
|
class Shader;
|
||||||
|
class Buffer;
|
||||||
|
class VertexArrayObject;
|
||||||
|
|
||||||
|
template<typename TInstance>
|
||||||
|
class InstanceBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
|
class LiteParticles2D : public RenderTask {
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Shader> _tf_shader;
|
||||||
|
std::shared_ptr<Shader> _points_shader;
|
||||||
|
|
||||||
|
std::unordered_map<uint32_t, uint16_t> _type_map {}; // maps id to "index" in type texture
|
||||||
|
|
||||||
|
// double buffered
|
||||||
|
bool first_particles_buffer {true};
|
||||||
|
std::unique_ptr<VertexArrayObject> _tf_vao[2];
|
||||||
|
std::unique_ptr<VertexArrayObject> _render_vao[2];
|
||||||
|
|
||||||
|
// vec2 pos (2 floats)
|
||||||
|
// half vec2 vel (1 float)
|
||||||
|
// fixedpoint age + uint16 type (1 float)
|
||||||
|
std::unique_ptr<MM::OpenGL::InstanceBuffer<glm::vec4>> _particles_0_buffers[2];
|
||||||
|
|
||||||
|
uint32_t _particle_buffer_size {10'000};
|
||||||
|
size_t _particle_buffer_next_index {0};
|
||||||
|
|
||||||
|
using clock = std::chrono::high_resolution_clock;
|
||||||
|
std::chrono::time_point<clock> _last_time;
|
||||||
|
float _time {0};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// TODO: impl some environment controlled force
|
||||||
|
//glm::vec2 env_vec{0, 1};
|
||||||
|
|
||||||
|
LiteParticles2D(Engine& engine);
|
||||||
|
~LiteParticles2D(void);
|
||||||
|
|
||||||
|
const char* name(void) override { return "LiteParticles2D"; }
|
||||||
|
|
||||||
|
void uploadParticles(Services::OpenGLRenderer& rs, Scene& scene);
|
||||||
|
void computeParticles(Services::OpenGLRenderer& rs, Scene& scene);
|
||||||
|
void renderParticles(Services::OpenGLRenderer& rs, Scene& scene);
|
||||||
|
void render(Services::OpenGLRenderer& rs, Engine& engine) override;
|
||||||
|
|
||||||
|
void setParticleBufferSize(uint32_t new_buffer_size = 10'000);
|
||||||
|
void resetBuffers(void);
|
||||||
|
void resetTypeBuffers(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const char* commonPathTF {"shader/lite_particles2d/common.glsl"};
|
||||||
|
|
||||||
|
const char* vertexPathTF {"shader/lite_particles2d/tf_vert.glsl"};
|
||||||
|
const char* fragmentPathTF {"shader/lite_particles2d/tf_frag.glsl"}; // "empty" bc of webgl (es)
|
||||||
|
|
||||||
|
const char* vertexPathPoints {"shader/lite_particles2d/point_vert.glsl"};
|
||||||
|
const char* fragmentPathPoints {"shader/lite_particles2d/point_frag.glsl"};
|
||||||
|
|
||||||
|
std::string target_fbo {"display"};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupShaderFiles(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // MM::OpenGL::RenderTasks
|
||||||
|
|
@ -22,9 +22,6 @@
|
|||||||
namespace MM::OpenGL::RenderTasks {
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
SimpleRect::SimpleRect(Engine& engine) {
|
SimpleRect::SimpleRect(Engine& engine) {
|
||||||
default_cam.setOrthographic();
|
|
||||||
default_cam.updateView();
|
|
||||||
|
|
||||||
float vertices[] = {
|
float vertices[] = {
|
||||||
-0.5f, 0.5f,
|
-0.5f, 0.5f,
|
||||||
-0.5f, -0.5f,
|
-0.5f, -0.5f,
|
||||||
@ -63,6 +60,10 @@ void SimpleRect::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
|||||||
|
|
||||||
auto& scene = ssi->getScene();
|
auto& scene = ssi->getScene();
|
||||||
|
|
||||||
|
if (!scene.ctx().contains<Camera3D>()) {
|
||||||
|
return; // nothing to draw
|
||||||
|
}
|
||||||
|
|
||||||
rs.targets[target_fbo]->bind(FrameBufferObject::RW);
|
rs.targets[target_fbo]->bind(FrameBufferObject::RW);
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
@ -71,12 +72,8 @@ void SimpleRect::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
|||||||
_shader->bind();
|
_shader->bind();
|
||||||
_vao->bind();
|
_vao->bind();
|
||||||
|
|
||||||
Camera3D* cam = scene.try_ctx<Camera3D>();
|
Camera3D& cam = scene.ctx().at<Camera3D>();
|
||||||
if (!cam) {
|
auto vp = cam.getViewProjection();
|
||||||
cam = &default_cam;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vp = cam->getViewProjection();
|
|
||||||
|
|
||||||
scene.view<const Components::Transform4x4>().each([this, &scene, &vp](entt::entity e, const auto& t) {
|
scene.view<const Components::Transform4x4>().each([this, &scene, &vp](entt::entity e, const auto& t) {
|
||||||
_shader->setUniformMat4f("_WVP", vp * t.trans);
|
_shader->setUniformMat4f("_WVP", vp * t.trans);
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include <mm/opengl/camera_3d.hpp>
|
#include <mm/opengl/camera_3d.hpp>
|
||||||
|
|
||||||
//#include <glm/fwd.hpp>
|
|
||||||
#include <glm/vec4.hpp>
|
#include <glm/vec4.hpp>
|
||||||
|
|
||||||
// fwd
|
// fwd
|
||||||
@ -26,8 +25,6 @@ namespace MM::OpenGL::RenderTasks {
|
|||||||
public:
|
public:
|
||||||
glm::vec4 default_color {1,1,1,1};
|
glm::vec4 default_color {1,1,1,1};
|
||||||
|
|
||||||
Camera3D default_cam;
|
|
||||||
|
|
||||||
SimpleRect(Engine& engine);
|
SimpleRect(Engine& engine);
|
||||||
~SimpleRect(void);
|
~SimpleRect(void);
|
||||||
|
|
||||||
|
@ -28,9 +28,6 @@
|
|||||||
namespace MM::OpenGL::RenderTasks {
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
SimpleSprite::SimpleSprite(Engine& engine) {
|
SimpleSprite::SimpleSprite(Engine& engine) {
|
||||||
default_cam.setOrthographic();
|
|
||||||
default_cam.updateView();
|
|
||||||
|
|
||||||
float vertices[] = {
|
float vertices[] = {
|
||||||
-0.5f, 0.5f,
|
-0.5f, 0.5f,
|
||||||
-0.5f, -0.5f,
|
-0.5f, -0.5f,
|
||||||
@ -69,6 +66,10 @@ void SimpleSprite::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
|||||||
|
|
||||||
auto& scene = ssi->getScene();
|
auto& scene = ssi->getScene();
|
||||||
|
|
||||||
|
if (!scene.ctx().contains<Camera3D>()) {
|
||||||
|
return; // nothing to draw
|
||||||
|
}
|
||||||
|
|
||||||
rs.targets[target_fbo]->bind(FrameBufferObject::W);
|
rs.targets[target_fbo]->bind(FrameBufferObject::W);
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
@ -79,12 +80,8 @@ void SimpleSprite::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
|||||||
_vao->bind();
|
_vao->bind();
|
||||||
|
|
||||||
|
|
||||||
auto* cam = scene.try_ctx<Camera3D>();
|
Camera3D& cam = scene.ctx().at<Camera3D>();
|
||||||
if (!cam) {
|
auto vp = cam.getViewProjection();
|
||||||
cam = &default_cam;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vp = cam->getViewProjection();
|
|
||||||
|
|
||||||
scene.view<const Components::Transform4x4, Components::OpenGL::Texture>().each([this, &scene, &vp](entt::entity e, const auto& t, auto& tex) {
|
scene.view<const Components::Transform4x4, Components::OpenGL::Texture>().each([this, &scene, &vp](entt::entity e, const auto& t, auto& tex) {
|
||||||
assert(tex.tex); // debug
|
assert(tex.tex); // debug
|
||||||
|
@ -26,8 +26,6 @@ namespace MM::OpenGL::RenderTasks {
|
|||||||
public:
|
public:
|
||||||
glm::vec4 default_color {1,1,1,1};
|
glm::vec4 default_color {1,1,1,1};
|
||||||
|
|
||||||
Camera3D default_cam;
|
|
||||||
|
|
||||||
SimpleSprite(Engine& engine);
|
SimpleSprite(Engine& engine);
|
||||||
~SimpleSprite(void);
|
~SimpleSprite(void);
|
||||||
|
|
||||||
|
@ -30,9 +30,6 @@
|
|||||||
namespace MM::OpenGL::RenderTasks {
|
namespace MM::OpenGL::RenderTasks {
|
||||||
|
|
||||||
SimpleSpriteSheet::SimpleSpriteSheet(Engine& engine) {
|
SimpleSpriteSheet::SimpleSpriteSheet(Engine& engine) {
|
||||||
default_cam.setOrthographic();
|
|
||||||
default_cam.updateView();
|
|
||||||
|
|
||||||
float vertices[] = {
|
float vertices[] = {
|
||||||
-0.5f, 0.5f,
|
-0.5f, 0.5f,
|
||||||
-0.5f, -0.5f,
|
-0.5f, -0.5f,
|
||||||
@ -56,11 +53,6 @@ SimpleSpriteSheet::SimpleSpriteSheet(Engine& engine) {
|
|||||||
setupShaderFiles();
|
setupShaderFiles();
|
||||||
_shader = Shader::createF(engine, vertexPath, fragmentPath);
|
_shader = Shader::createF(engine, vertexPath, fragmentPath);
|
||||||
assert(_shader != nullptr);
|
assert(_shader != nullptr);
|
||||||
|
|
||||||
auto& scene = engine.tryService<MM::Services::SceneServiceInterface>()->getScene();
|
|
||||||
if (!scene.try_ctx<Camera3D>()) {
|
|
||||||
LOG_SSSR("warn: scene has no Camera!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleSpriteSheet::~SimpleSpriteSheet(void) {
|
SimpleSpriteSheet::~SimpleSpriteSheet(void) {
|
||||||
@ -76,6 +68,10 @@ void SimpleSpriteSheet::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
|||||||
|
|
||||||
auto& scene = ssi->getScene();
|
auto& scene = ssi->getScene();
|
||||||
|
|
||||||
|
if (!scene.ctx().contains<Camera3D>()) {
|
||||||
|
return; // nothing to draw
|
||||||
|
}
|
||||||
|
|
||||||
rs.targets[target_fbo]->bind(FrameBufferObject::W);
|
rs.targets[target_fbo]->bind(FrameBufferObject::W);
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
@ -85,12 +81,8 @@ void SimpleSpriteSheet::render(Services::OpenGLRenderer& rs, Engine& engine) {
|
|||||||
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
_vao->bind();
|
_vao->bind();
|
||||||
|
|
||||||
auto* cam = scene.try_ctx<Camera3D>();
|
Camera3D& cam = scene.ctx().at<Camera3D>();
|
||||||
if (!cam) {
|
auto vp = cam.getViewProjection();
|
||||||
cam = &default_cam;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vp = cam->getViewProjection();
|
|
||||||
|
|
||||||
scene.view<const Components::Transform4x4, SpriteSheetRenderable>().each([this, &scene, &vp](entt::entity e, const auto& t, auto& spr) {
|
scene.view<const Components::Transform4x4, SpriteSheetRenderable>().each([this, &scene, &vp](entt::entity e, const auto& t, auto& spr) {
|
||||||
assert(spr.sp.tex); // debug
|
assert(spr.sp.tex); // debug
|
||||||
|
@ -26,8 +26,6 @@ namespace MM::OpenGL::RenderTasks {
|
|||||||
public:
|
public:
|
||||||
glm::vec4 default_color {1.f, 1.f, 1.f, 1.f};
|
glm::vec4 default_color {1.f, 1.f, 1.f, 1.f};
|
||||||
|
|
||||||
Camera3D default_cam;
|
|
||||||
|
|
||||||
SimpleSpriteSheet(Engine& engine);
|
SimpleSpriteSheet(Engine& engine);
|
||||||
~SimpleSpriteSheet(void);
|
~SimpleSpriteSheet(void);
|
||||||
|
|
||||||
|
@ -43,6 +43,12 @@ Tilemap::Tilemap(MM::Engine& engine) {
|
|||||||
-0.5f, 0.5f,
|
-0.5f, 0.5f,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// bias to avoid cracks
|
||||||
|
const float vert_offset_fact = 1.001f;
|
||||||
|
for (size_t i = 0; i < 2 * 6; i++) {
|
||||||
|
vertices[i] *= vert_offset_fact;
|
||||||
|
}
|
||||||
|
|
||||||
_vertexBuffer = std::make_unique<MM::OpenGL::Buffer>(vertices, 2 * 6 * sizeof(float), GL_STATIC_DRAW);
|
_vertexBuffer = std::make_unique<MM::OpenGL::Buffer>(vertices, 2 * 6 * sizeof(float), GL_STATIC_DRAW);
|
||||||
_vao = std::make_unique<MM::OpenGL::VertexArrayObject>();
|
_vao = std::make_unique<MM::OpenGL::VertexArrayObject>();
|
||||||
_vao->bind();
|
_vao->bind();
|
||||||
@ -69,6 +75,17 @@ Tilemap::~Tilemap(void) {
|
|||||||
void Tilemap::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
|
void Tilemap::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
|
||||||
ZoneScopedN("MM::OpenGL::Renderers::TilemapRenderer::render");
|
ZoneScopedN("MM::OpenGL::Renderers::TilemapRenderer::render");
|
||||||
|
|
||||||
|
auto* ssi = engine.tryService<MM::Services::SceneServiceInterface>();
|
||||||
|
if (ssi == nullptr) {
|
||||||
|
return; // nothing to draw
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& scene = ssi->getScene();
|
||||||
|
|
||||||
|
if (!scene.ctx().contains<Camera3D>()) {
|
||||||
|
return; // nothing to draw
|
||||||
|
}
|
||||||
|
|
||||||
rs.targets[target_fbo]->bind(MM::OpenGL::FrameBufferObject::W);
|
rs.targets[target_fbo]->bind(MM::OpenGL::FrameBufferObject::W);
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
@ -79,17 +96,13 @@ void Tilemap::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
|
|||||||
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
_vertexBuffer->bind(GL_ARRAY_BUFFER);
|
||||||
_vao->bind();
|
_vao->bind();
|
||||||
|
|
||||||
|
MM::OpenGL::Camera3D& cam = scene.ctx().at<MM::OpenGL::Camera3D>();
|
||||||
auto& scene = engine.tryService<Services::SceneServiceInterface>()->getScene();
|
|
||||||
|
|
||||||
MM::OpenGL::Camera3D& cam = scene.ctx<MM::OpenGL::Camera3D>();
|
|
||||||
auto vp = cam.getViewProjection();
|
auto vp = cam.getViewProjection();
|
||||||
|
|
||||||
_shader->setUniform3f("_ambient_color", ambient_color);
|
_shader->setUniform3f("_ambient_color", ambient_color);
|
||||||
|
|
||||||
scene.view<MM::Components::Transform4x4, OpenGL::TilemapRenderable>()
|
scene.view<MM::Components::Transform4x4, OpenGL::TilemapRenderable>()
|
||||||
.each([&](auto, MM::Components::Transform4x4& t, OpenGL::TilemapRenderable& tilemap) {
|
.each([&](auto, MM::Components::Transform4x4& t, OpenGL::TilemapRenderable& tilemap) {
|
||||||
//_shader->setUniformMat4f("_WVP", vp * t.getTransform4(tilemap.z + 500.f));
|
|
||||||
_shader->setUniformMat4f("_WVP", vp * t.trans);
|
_shader->setUniformMat4f("_WVP", vp * t.trans);
|
||||||
|
|
||||||
// for each sprite layer
|
// for each sprite layer
|
||||||
|
396
framework/opengl_renderer/src/mm/opengl/res/shaders_builtin.cpp
Normal file
396
framework/opengl_renderer/src/mm/opengl/res/shaders_builtin.cpp
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
#include "./shaders_builtin.hpp"
|
||||||
|
|
||||||
|
#include <mm/fs_const_archiver.hpp>
|
||||||
|
|
||||||
|
namespace MM::OpenGL {
|
||||||
|
|
||||||
|
void load_builtin_shaders_fs(void) {
|
||||||
|
|
||||||
|
// ==================== sampling.glsl ==================== START
|
||||||
|
FS_CONST_MOUNT_FILE("/shaders/builtin/sampling.glsl",
|
||||||
|
R"(
|
||||||
|
#ifndef INCLUDE_BUILTIN_SAMPLING
|
||||||
|
#define INCLUDE_BUILTIN_SAMPLING
|
||||||
|
|
||||||
|
// kernel defined 9tap sampling
|
||||||
|
// samper, uv, 1.0/textureSize(), kernel, sum of kernel
|
||||||
|
vec3 sampling2D_kernel3x3_vec3(in sampler2D tex, in vec2 pos, in vec2 dir_step, in mat3x3 kernel, in float kernel_weight) {
|
||||||
|
vec3 color =
|
||||||
|
// upper row
|
||||||
|
texture(tex, pos + dir_step * vec2(-1.0, 1.0)).rgb * kernel[0][0]
|
||||||
|
+ texture(tex, pos + dir_step * vec2(0.0, 1.0)).rgb * kernel[0][1]
|
||||||
|
+ texture(tex, pos + dir_step * vec2(1.0, 1.0)).rgb * kernel[0][2]
|
||||||
|
|
||||||
|
// middle row
|
||||||
|
+ texture(tex, pos + dir_step * vec2(-1.0, 0.0)).rgb * kernel[1][0]
|
||||||
|
+ texture(tex, pos).rgb * kernel[1][1]
|
||||||
|
+ texture(tex, pos + dir_step * vec2(1.0, 0.0)).rgb * kernel[1][2]
|
||||||
|
|
||||||
|
// lower row
|
||||||
|
+ texture(tex, pos + dir_step * vec2(-1.0, -1.0)).rgb * kernel[2][0]
|
||||||
|
+ texture(tex, pos + dir_step * vec2(0.0, -1.0)).rgb * kernel[2][1]
|
||||||
|
+ texture(tex, pos + dir_step * vec2(1.0, -1.0)).rgb * kernel[2][2]
|
||||||
|
;
|
||||||
|
|
||||||
|
return color / vec3(kernel_weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3x3 9tap tent filter
|
||||||
|
// 1 2 1
|
||||||
|
// 2 4 2
|
||||||
|
// 1 2 1
|
||||||
|
vec3 sampling2D_tent3x3_vec3(in sampler2D tex, in vec2 pos, in vec2 dir_step) {
|
||||||
|
const mat3x3 tent_kernel = mat3x3(
|
||||||
|
vec3(1.0, 2.0, 1.0),
|
||||||
|
vec3(2.0, 4.0, 2.0),
|
||||||
|
vec3(1.0, 2.0, 1.0)
|
||||||
|
);
|
||||||
|
const float tent_kernel_weight = 16.0;
|
||||||
|
|
||||||
|
return sampling2D_kernel3x3_vec3(
|
||||||
|
tex,
|
||||||
|
pos,
|
||||||
|
dir_step,
|
||||||
|
tent_kernel,
|
||||||
|
tent_kernel_weight
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
)")
|
||||||
|
// ==================== sampling.glsl ==================== END
|
||||||
|
|
||||||
|
// ==================== tonemapping.glsl ==================== START
|
||||||
|
FS_CONST_MOUNT_FILE("/shaders/builtin/tonemapping.glsl",
|
||||||
|
R"(
|
||||||
|
#ifndef INCLUDE_BUILTIN_TONEMAPPING
|
||||||
|
#define INCLUDE_BUILTIN_TONEMAPPING
|
||||||
|
|
||||||
|
// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
|
||||||
|
vec3 tonemapACESFilm(vec3 x) {
|
||||||
|
const float a = 2.51;
|
||||||
|
const float b = 0.03;
|
||||||
|
const float c = 2.43;
|
||||||
|
const float d = 0.59;
|
||||||
|
const float e = 0.14;
|
||||||
|
|
||||||
|
return clamp((x*(a*x+b))/(x*(c*x+d)+e), vec3(0.0), vec3(1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tonemapReinhard(vec3 x) {
|
||||||
|
return x / (x + vec3(1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
)")
|
||||||
|
// ==================== tonemapping.glsl ==================== END
|
||||||
|
|
||||||
|
// ==================== hashing.glsl ==================== START
|
||||||
|
FS_CONST_MOUNT_FILE("/shaders/builtin/hashing.glsl",
|
||||||
|
R"(
|
||||||
|
#ifndef INCLUDE_BUILTIN_HASHING
|
||||||
|
#define INCLUDE_BUILTIN_HASHING
|
||||||
|
|
||||||
|
// https://www.shadertoy.com/view/4djSRW
|
||||||
|
// Hash without Sine
|
||||||
|
// MIT License...
|
||||||
|
/* Copyright (c)2014 David Hoskins.
|
||||||
|
modified by Erik Scholz 2022
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.*/
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 1 out, 1 in...
|
||||||
|
float hash11(float p)
|
||||||
|
{
|
||||||
|
p = fract(p * .1031);
|
||||||
|
p *= p + 33.33;
|
||||||
|
p *= p + p;
|
||||||
|
return fract(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 1 out, 2 in...
|
||||||
|
float hash12(vec2 p)
|
||||||
|
{
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * .1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 1 out, 3 in...
|
||||||
|
float hash13(vec3 p3)
|
||||||
|
{
|
||||||
|
p3 = fract(p3 * .1031);
|
||||||
|
p3 += dot(p3, p3.zyx + 31.32);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// TODO: test properly
|
||||||
|
// 1 out, 4 in...
|
||||||
|
float hash14(vec4 p4)
|
||||||
|
{
|
||||||
|
p4 = fract(p4 * .1031);
|
||||||
|
p4 += dot(p4, p4.zywx + 31.32);
|
||||||
|
return fract((p4.x + p4.y + p4.w) * p4.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 2 out, 1 in...
|
||||||
|
vec2 hash21(float p)
|
||||||
|
{
|
||||||
|
vec3 p3 = fract(vec3(p) * vec3(.1031, .1030, .0973));
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.xx+p3.yz)*p3.zy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 2 out, 2 in...
|
||||||
|
vec2 hash22(vec2 p)
|
||||||
|
{
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
|
||||||
|
p3 += dot(p3, p3.yzx+33.33);
|
||||||
|
return fract((p3.xx+p3.yz)*p3.zy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 2 out, 3 in...
|
||||||
|
vec2 hash23(vec3 p3)
|
||||||
|
{
|
||||||
|
p3 = fract(p3 * vec3(.1031, .1030, .0973));
|
||||||
|
p3 += dot(p3, p3.yzx+33.33);
|
||||||
|
return fract((p3.xx+p3.yz)*p3.zy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// TODO: test properly
|
||||||
|
// 2 out, 4 in...
|
||||||
|
vec2 hash24(vec4 p4)
|
||||||
|
{
|
||||||
|
p4 = fract(p4 * vec4(.1031, .1030, .0973, .1337));
|
||||||
|
p4 += dot(p4, p4.ywzx+33.33);
|
||||||
|
return fract((p4.wx+p4.yz)*p4.zy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 3 out, 1 in...
|
||||||
|
vec3 hash31(float p)
|
||||||
|
{
|
||||||
|
vec3 p3 = fract(vec3(p) * vec3(.1031, .1030, .0973));
|
||||||
|
p3 += dot(p3, p3.yzx+33.33);
|
||||||
|
return fract((p3.xxy+p3.yzz)*p3.zyx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 3 out, 2 in...
|
||||||
|
vec3 hash32(vec2 p)
|
||||||
|
{
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
|
||||||
|
p3 += dot(p3, p3.yxz+33.33);
|
||||||
|
return fract((p3.xxy+p3.yzz)*p3.zyx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 3 out, 3 in...
|
||||||
|
vec3 hash33(vec3 p3)
|
||||||
|
{
|
||||||
|
p3 = fract(p3 * vec3(.1031, .1030, .0973));
|
||||||
|
p3 += dot(p3, p3.yxz+33.33);
|
||||||
|
return fract((p3.xxy + p3.yxx)*p3.zyx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 4 out, 1 in...
|
||||||
|
vec4 hash41(float p)
|
||||||
|
{
|
||||||
|
vec4 p4 = fract(vec4(p) * vec4(.1031, .1030, .0973, .1099));
|
||||||
|
p4 += dot(p4, p4.wzxy+33.33);
|
||||||
|
return fract((p4.xxyz+p4.yzzw)*p4.zywx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 4 out, 2 in...
|
||||||
|
vec4 hash42(vec2 p)
|
||||||
|
{
|
||||||
|
vec4 p4 = fract(vec4(p.xyxy) * vec4(.1031, .1030, .0973, .1099));
|
||||||
|
p4 += dot(p4, p4.wzxy+33.33);
|
||||||
|
return fract((p4.xxyz+p4.yzzw)*p4.zywx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 4 out, 3 in...
|
||||||
|
vec4 hash43(vec3 p)
|
||||||
|
{
|
||||||
|
vec4 p4 = fract(vec4(p.xyzx) * vec4(.1031, .1030, .0973, .1099));
|
||||||
|
p4 += dot(p4, p4.wzxy+33.33);
|
||||||
|
return fract((p4.xxyz+p4.yzzw)*p4.zywx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
// 4 out, 4 in...
|
||||||
|
vec4 hash44(vec4 p4)
|
||||||
|
{
|
||||||
|
p4 = fract(p4 * vec4(.1031, .1030, .0973, .1099));
|
||||||
|
p4 += dot(p4, p4.wzxy+33.33);
|
||||||
|
return fract((p4.xxyz+p4.yzzw)*p4.zywx);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
)")
|
||||||
|
// ==================== hashing.glsl ==================== END
|
||||||
|
|
||||||
|
// ==================== noise.glsl ==================== START
|
||||||
|
FS_CONST_MOUNT_FILE("/shaders/builtin/noise.glsl",
|
||||||
|
R"(
|
||||||
|
#ifndef INCLUDE_BUILTIN_NOISE
|
||||||
|
#define INCLUDE_BUILTIN_NOISE
|
||||||
|
|
||||||
|
#include "/shaders/builtin/hashing.glsl"
|
||||||
|
|
||||||
|
// value noise based on Inigo Quilez value noise shaders.
|
||||||
|
// https://www.youtube.com/c/InigoQuilez
|
||||||
|
// https://iquilezles.org/
|
||||||
|
// value noise 2d: https://www.shadertoy.com/view/lsf3WH
|
||||||
|
// value noise 3d: https://www.shadertoy.com/view/4sfGzS
|
||||||
|
|
||||||
|
float noise12(in vec2 p) {
|
||||||
|
vec2 i = floor(p);
|
||||||
|
vec2 f = fract(p);
|
||||||
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
return mix(mix( hash12(i + vec2(0.0, 0.0)),
|
||||||
|
hash12(i + vec2(1.0, 0.0)), u.x),
|
||||||
|
mix(hash12(i + vec2(0.0, 1.0)),
|
||||||
|
hash12(i + vec2(1.0, 1.0)), u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 noise22(in vec2 p) {
|
||||||
|
vec2 i = floor(p);
|
||||||
|
vec2 f = fract(p);
|
||||||
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
return mix(mix( hash22(i + vec2(0.0, 0.0)),
|
||||||
|
hash22(i + vec2(1.0, 0.0)), u.x),
|
||||||
|
mix(hash22(i + vec2(0.0, 1.0)),
|
||||||
|
hash22(i + vec2(1.0, 1.0)), u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float noise13(in vec3 x) {
|
||||||
|
vec3 i = floor(x);
|
||||||
|
vec3 f = fract(x);
|
||||||
|
vec3 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
return mix(mix(mix( hash13(i + vec3(0.0, 0.0, 0.0)),
|
||||||
|
hash13(i + vec3(1.0, 0.0, 0.0)), u.x),
|
||||||
|
mix(hash13(i + vec3(0.0, 1.0, 0.0)),
|
||||||
|
hash13(i + vec3(1.0, 1.0, 0.0)), u.x), u.y),
|
||||||
|
mix(mix(hash13(i + vec3(0.0, 0.0, 1.0)),
|
||||||
|
hash13(i + vec3(1.0, 0.0, 1.0)), u.x),
|
||||||
|
mix(hash13(i + vec3(0.0, 1.0, 1.0)),
|
||||||
|
hash13(i + vec3(1.0, 1.0, 1.0)), u.x), u.y), u.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
float noise14(in vec4 x) {
|
||||||
|
vec4 i = floor(x);
|
||||||
|
vec4 f = fract(x);
|
||||||
|
vec4 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
return
|
||||||
|
mix(mix(mix(mix(hash14(i + vec4(0.0, 0.0, 0.0, 0.0)),
|
||||||
|
hash14(i + vec4(1.0, 0.0, 0.0, 0.0)), u.x
|
||||||
|
),
|
||||||
|
mix(hash14(i + vec4(0.0, 1.0, 0.0, 0.0)),
|
||||||
|
hash14(i + vec4(1.0, 1.0, 0.0, 0.0)), u.x
|
||||||
|
), u.y
|
||||||
|
),
|
||||||
|
mix(mix(hash14(i + vec4(0.0, 0.0, 1.0, 0.0)),
|
||||||
|
hash14(i + vec4(1.0, 0.0, 1.0, 0.0)), u.x
|
||||||
|
),
|
||||||
|
mix(hash14(i + vec4(0.0, 1.0, 1.0, 0.0)),
|
||||||
|
hash14(i + vec4(1.0, 1.0, 1.0, 0.0)), u.x
|
||||||
|
), u.y
|
||||||
|
), u.z
|
||||||
|
),
|
||||||
|
mix(mix(mix(hash14(i + vec4(0.0, 0.0, 0.0, 1.0)),
|
||||||
|
hash14(i + vec4(1.0, 0.0, 0.0, 1.0)), u.x
|
||||||
|
),
|
||||||
|
mix(hash14(i + vec4(0.0, 1.0, 0.0, 1.0)),
|
||||||
|
hash14(i + vec4(1.0, 1.0, 0.0, 1.0)), u.x
|
||||||
|
), u.y
|
||||||
|
),
|
||||||
|
mix(mix(hash14(i + vec4(0.0, 0.0, 1.0, 1.0)),
|
||||||
|
hash14(i + vec4(1.0, 0.0, 1.0, 1.0)), u.x
|
||||||
|
),
|
||||||
|
mix(hash14(i + vec4(0.0, 1.0, 1.0, 1.0)),
|
||||||
|
hash14(i + vec4(1.0, 1.0, 1.0, 1.0)), u.x
|
||||||
|
), u.y
|
||||||
|
), u.z
|
||||||
|
), u.w
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 noise24(in vec4 x) {
|
||||||
|
vec4 i = floor(x);
|
||||||
|
vec4 f = fract(x);
|
||||||
|
vec4 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
return
|
||||||
|
mix(mix(mix(mix(hash24(i + vec4(0.0, 0.0, 0.0, 0.0)),
|
||||||
|
hash24(i + vec4(1.0, 0.0, 0.0, 0.0)), u.x
|
||||||
|
),
|
||||||
|
mix(hash24(i + vec4(0.0, 1.0, 0.0, 0.0)),
|
||||||
|
hash24(i + vec4(1.0, 1.0, 0.0, 0.0)), u.x
|
||||||
|
), u.y
|
||||||
|
),
|
||||||
|
mix(mix(hash24(i + vec4(0.0, 0.0, 1.0, 0.0)),
|
||||||
|
hash24(i + vec4(1.0, 0.0, 1.0, 0.0)), u.x
|
||||||
|
),
|
||||||
|
mix(hash24(i + vec4(0.0, 1.0, 1.0, 0.0)),
|
||||||
|
hash24(i + vec4(1.0, 1.0, 1.0, 0.0)), u.x
|
||||||
|
), u.y
|
||||||
|
), u.z
|
||||||
|
),
|
||||||
|
mix(mix(mix(hash24(i + vec4(0.0, 0.0, 0.0, 1.0)),
|
||||||
|
hash24(i + vec4(1.0, 0.0, 0.0, 1.0)), u.x
|
||||||
|
),
|
||||||
|
mix(hash24(i + vec4(0.0, 1.0, 0.0, 1.0)),
|
||||||
|
hash24(i + vec4(1.0, 1.0, 0.0, 1.0)), u.x
|
||||||
|
), u.y
|
||||||
|
),
|
||||||
|
mix(mix(hash24(i + vec4(0.0, 0.0, 1.0, 1.0)),
|
||||||
|
hash24(i + vec4(1.0, 0.0, 1.0, 1.0)), u.x
|
||||||
|
),
|
||||||
|
mix(hash24(i + vec4(0.0, 1.0, 1.0, 1.0)),
|
||||||
|
hash24(i + vec4(1.0, 1.0, 1.0, 1.0)), u.x
|
||||||
|
), u.y
|
||||||
|
), u.z
|
||||||
|
), u.w
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
)")
|
||||||
|
// ==================== noise.glsl ==================== END
|
||||||
|
}
|
||||||
|
|
||||||
|
} // MM::OpenGL
|
||||||
|
|
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace MM::OpenGL {
|
||||||
|
|
||||||
|
// loads glsl files into const fs at "/shaders/builtin/"
|
||||||
|
// file list:
|
||||||
|
// - sampling.glsl
|
||||||
|
// - tonemapping.glsl
|
||||||
|
// - hashing.glsl
|
||||||
|
// - noise.glsl
|
||||||
|
void load_builtin_shaders_fs(void);
|
||||||
|
|
||||||
|
} // MM::OpenGL
|
||||||
|
|
@ -10,6 +10,7 @@
|
|||||||
#include <mm/opengl/texture_loader.hpp>
|
#include <mm/opengl/texture_loader.hpp>
|
||||||
#include "../opengl/res/default_texture.h" // data
|
#include "../opengl/res/default_texture.h" // data
|
||||||
#include "../opengl/res/errig_texture.h" // data
|
#include "../opengl/res/errig_texture.h" // data
|
||||||
|
#include "../opengl/res/shaders_builtin.hpp" // data-ish
|
||||||
|
|
||||||
#include <tracy/Tracy.hpp>
|
#include <tracy/Tracy.hpp>
|
||||||
#ifndef MM_OPENGL_3_GLES
|
#ifndef MM_OPENGL_3_GLES
|
||||||
@ -111,7 +112,7 @@ bool OpenGLRenderer::enable(Engine& engine, std::vector<UpdateStrategies::TaskIn
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // default texures
|
{ // default textures
|
||||||
auto& rm_t = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
auto& rm_t = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||||
if (!rm_t.contains("default"_hs)) {
|
if (!rm_t.contains("default"_hs)) {
|
||||||
if (!rm_t.load<MM::OpenGL::TextureLoaderConstBuffer>("default", default_png, default_png_len)) {
|
if (!rm_t.load<MM::OpenGL::TextureLoaderConstBuffer>("default", default_png, default_png_len)) {
|
||||||
@ -125,6 +126,10 @@ bool OpenGLRenderer::enable(Engine& engine, std::vector<UpdateStrategies::TaskIn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // builtin shaders
|
||||||
|
OpenGL::load_builtin_shaders_fs();
|
||||||
|
}
|
||||||
|
|
||||||
{ // add task
|
{ // add task
|
||||||
task_array.push_back(
|
task_array.push_back(
|
||||||
UpdateStrategies::TaskInfo{"OpenGLRenderer::render"}
|
UpdateStrategies::TaskInfo{"OpenGLRenderer::render"}
|
||||||
|
@ -9,6 +9,17 @@ add_test(NAME opengl_renderer_s_test COMMAND opengl_renderer_s_test)
|
|||||||
|
|
||||||
#################
|
#################
|
||||||
|
|
||||||
|
add_executable(opengl_builtins_test ./builtins.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(opengl_builtins_test
|
||||||
|
opengl_renderer_s
|
||||||
|
gtest_main
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(NAME opengl_builtins_test COMMAND opengl_builtins_test)
|
||||||
|
|
||||||
|
#################
|
||||||
|
|
||||||
add_executable(imgui_render_task_test imgui_render_task_test.cpp)
|
add_executable(imgui_render_task_test imgui_render_task_test.cpp)
|
||||||
|
|
||||||
target_link_libraries(imgui_render_task_test
|
target_link_libraries(imgui_render_task_test
|
||||||
@ -149,3 +160,53 @@ target_link_libraries(fast_sky_render_task_test
|
|||||||
|
|
||||||
add_test(NAME fast_sky_render_task_test COMMAND fast_sky_render_task_test)
|
add_test(NAME fast_sky_render_task_test COMMAND fast_sky_render_task_test)
|
||||||
|
|
||||||
|
################# hdr bloom example
|
||||||
|
|
||||||
|
add_executable(hdr_bloom_pipeline_example ./hdr_bloom_pipeline_example.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(hdr_bloom_pipeline_example
|
||||||
|
opengl_renderer_s
|
||||||
|
organizer_scene
|
||||||
|
clear_render_task
|
||||||
|
simple_rect_render_task
|
||||||
|
|
||||||
|
#bloom_extraction_render_task
|
||||||
|
#blur_render_task
|
||||||
|
#bloom_combine_render_task
|
||||||
|
bloom
|
||||||
|
composition_render_task
|
||||||
|
|
||||||
|
simple_velocity_system
|
||||||
|
transform_system
|
||||||
|
|
||||||
|
random
|
||||||
|
|
||||||
|
gtest_main
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(NAME hdr_bloom_pipeline_example COMMAND hdr_bloom_pipeline_example)
|
||||||
|
|
||||||
|
################# lite_particles2d (the test uses bloom)
|
||||||
|
|
||||||
|
add_executable(lite_particles2d_test ./lite_particles2d.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(lite_particles2d_test
|
||||||
|
opengl_renderer_s
|
||||||
|
organizer_scene
|
||||||
|
clear_render_task
|
||||||
|
#simple_rect_render_task
|
||||||
|
lite_particles2d # not only rendertask
|
||||||
|
|
||||||
|
bloom
|
||||||
|
composition_render_task
|
||||||
|
|
||||||
|
#simple_velocity_system
|
||||||
|
#transform_system
|
||||||
|
|
||||||
|
random
|
||||||
|
|
||||||
|
gtest_main
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(NAME lite_particles2d_test COMMAND lite_particles2d_test)
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ TEST(batched_spritesheet_render_task, it) {
|
|||||||
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
|
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
|
||||||
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
|
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
|
||||||
|
|
||||||
auto& cam = scene.set<MM::OpenGL::Camera3D>();
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
cam.horizontalViewPortSize = 5;
|
cam.horizontalViewPortSize = 5;
|
||||||
cam.setOrthographic();
|
cam.setOrthographic();
|
||||||
cam.updateView();
|
cam.updateView();
|
||||||
@ -87,8 +87,8 @@ TEST(batched_spritesheet_render_task, it) {
|
|||||||
|
|
||||||
|
|
||||||
// setup systems
|
// setup systems
|
||||||
scene.set<float>(0.f); // accu
|
scene.ctx().emplace<float>(0.f); // accu
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
org.emplace<&update_spritesheet_animation>("update_spritesheet_animation");
|
org.emplace<&update_spritesheet_animation>("update_spritesheet_animation");
|
||||||
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
||||||
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
||||||
|
@ -72,9 +72,10 @@ TEST(blur_render_task, it) {
|
|||||||
bsrr_rend.target_fbo = "blur_io";
|
bsrr_rend.target_fbo = "blur_io";
|
||||||
|
|
||||||
MM::OpenGL::RenderTasks::Blur& blur_rend = rs.addRenderTask<MM::OpenGL::RenderTasks::Blur>(engine);
|
MM::OpenGL::RenderTasks::Blur& blur_rend = rs.addRenderTask<MM::OpenGL::RenderTasks::Blur>(engine);
|
||||||
blur_rend.io_tex = "blur_io";
|
blur_rend.in_tex = "blur_io";
|
||||||
|
blur_rend.out_tex = "blur_io";
|
||||||
blur_rend.temp_tex = "blur_temp";
|
blur_rend.temp_tex = "blur_temp";
|
||||||
blur_rend.io_fbo = "blur_io";
|
blur_rend.out_fbo = "blur_io";
|
||||||
blur_rend.temp_fbo = "blur_temp";
|
blur_rend.temp_fbo = "blur_temp";
|
||||||
|
|
||||||
// render to display
|
// render to display
|
||||||
@ -128,9 +129,12 @@ TEST(blur_render_task, it) {
|
|||||||
scene.on_update<MM::Components::Scale2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
scene.on_update<MM::Components::Scale2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
scene.on_update<MM::Components::Rotation2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>(); // in this example only rotation is touched
|
scene.on_update<MM::Components::Rotation2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>(); // in this example only rotation is touched
|
||||||
|
|
||||||
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
|
cam.setOrthographic();
|
||||||
|
cam.updateView();
|
||||||
|
|
||||||
// setup v system
|
// setup v system
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
org.emplace<MM::Systems::simple_rotational_velocity_patching>("simple_rotational_velocity_patching");
|
org.emplace<MM::Systems::simple_rotational_velocity_patching>("simple_rotational_velocity_patching");
|
||||||
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
||||||
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
||||||
|
61
framework/opengl_renderer/test/builtins.cpp
Normal file
61
framework/opengl_renderer/test/builtins.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <mm/engine.hpp>
|
||||||
|
#include <mm/services/filesystem.hpp>
|
||||||
|
#include <mm/services/sdl_service.hpp>
|
||||||
|
#include <mm/services/opengl_renderer.hpp>
|
||||||
|
|
||||||
|
//#include <mm/opengl/res/shaders_builtin.hpp>
|
||||||
|
|
||||||
|
#include <mm/opengl/shader.hpp>
|
||||||
|
#include <mm/opengl/shader_builder.hpp>
|
||||||
|
|
||||||
|
#include <mm/fs_const_archiver.hpp> // include only works on files rn
|
||||||
|
|
||||||
|
static const char* argv0 = "";
|
||||||
|
|
||||||
|
TEST(builtins, all) {
|
||||||
|
MM::Engine engine;
|
||||||
|
|
||||||
|
engine.addService<MM::Services::FilesystemService>(argv0);
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::FilesystemService>());
|
||||||
|
|
||||||
|
engine.addService<MM::Services::SDLService>();
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
|
||||||
|
|
||||||
|
engine.addService<MM::Services::OpenGLRenderer>();
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>()); // adds builtins
|
||||||
|
|
||||||
|
engine.update();
|
||||||
|
|
||||||
|
FS_CONST_MOUNT_FILE("/shaders/test_frag.glsl",
|
||||||
|
GLSL_VERSION_STRING
|
||||||
|
R"(
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "/shaders/builtin/sampling.glsl"
|
||||||
|
#include "/shaders/builtin/tonemapping.glsl"
|
||||||
|
#include "/shaders/builtin/hashing.glsl"
|
||||||
|
#include "/shaders/builtin/noise.glsl"
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
auto sb = MM::OpenGL::ShaderBuilder::start();
|
||||||
|
sb.addStageVertex("void main() { gl_Position = vec4(0.0); }");
|
||||||
|
sb.addStageFragmentF(engine, "/shaders/test_frag.glsl");
|
||||||
|
auto shader = sb.finish();
|
||||||
|
ASSERT_TRUE(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
argv0 = argv[0];
|
||||||
|
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
@ -42,18 +42,18 @@ TEST(fast_sky_render_task, it) {
|
|||||||
rs.addRenderTask<MM::OpenGL::RenderTasks::FastSky>(engine);
|
rs.addRenderTask<MM::OpenGL::RenderTasks::FastSky>(engine);
|
||||||
|
|
||||||
// setup systems
|
// setup systems
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
org.emplace<&MM::Systems::fast_sky_sun>("fast_sky_sun");
|
org.emplace<&MM::Systems::fast_sky_sun>("fast_sky_sun");
|
||||||
|
|
||||||
// HACK: instead you would switch to this scene
|
// HACK: instead you would switch to this scene
|
||||||
engine.getService<MM::Services::OrganizerSceneService>().updateOrganizerVertices(scene);
|
engine.getService<MM::Services::OrganizerSceneService>().updateOrganizerVertices(scene);
|
||||||
|
|
||||||
|
|
||||||
auto& cam = scene.set<MM::OpenGL::Camera3D>();
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
cam.setPerspective();
|
cam.setPerspective();
|
||||||
cam.updateView();
|
cam.updateView();
|
||||||
|
|
||||||
scene.set<MM::OpenGL::RenderTasks::FastSkyContext>();
|
scene.ctx().emplace<MM::OpenGL::RenderTasks::FastSkyContext>();
|
||||||
|
|
||||||
engine.run();
|
engine.run();
|
||||||
}
|
}
|
||||||
|
254
framework/opengl_renderer/test/hdr_bloom_pipeline_example.cpp
Normal file
254
framework/opengl_renderer/test/hdr_bloom_pipeline_example.cpp
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <mm/engine.hpp>
|
||||||
|
|
||||||
|
#include <mm/services/filesystem.hpp>
|
||||||
|
#include <mm/services/sdl_service.hpp>
|
||||||
|
#include <mm/services/organizer_scene.hpp>
|
||||||
|
#include <mm/services/opengl_renderer.hpp>
|
||||||
|
|
||||||
|
#include <entt/entity/registry.hpp>
|
||||||
|
#include <entt/entity/organizer.hpp>
|
||||||
|
|
||||||
|
#include <mm/opengl/render_tasks/clear.hpp>
|
||||||
|
#include <mm/opengl/render_tasks/blit_fb.hpp>
|
||||||
|
#include <mm/opengl/render_tasks/simple_rect.hpp>
|
||||||
|
//#include <mm/opengl/render_tasks/bloom_extraction.hpp>
|
||||||
|
//#include <mm/opengl/render_tasks/blur.hpp>
|
||||||
|
//#include <mm/opengl/render_tasks/bloom_combine.hpp>
|
||||||
|
#include <mm/opengl/bloom.hpp>
|
||||||
|
#include <mm/opengl/render_tasks/composition.hpp>
|
||||||
|
|
||||||
|
#include <mm/components/position2d.hpp>
|
||||||
|
#include <mm/components/position2d_zoffset.hpp>
|
||||||
|
#include <mm/components/scale2d.hpp>
|
||||||
|
#include <mm/components/rotation2d.hpp>
|
||||||
|
#include <mm/components/velocity2d_rotation.hpp>
|
||||||
|
#include <mm/components/position3d.hpp>
|
||||||
|
#include <mm/components/transform4x4.hpp>
|
||||||
|
#include <mm/components/color.hpp>
|
||||||
|
|
||||||
|
#include <mm/systems/simple_velocity_system2d.hpp>
|
||||||
|
#include <mm/systems/transform.hpp>
|
||||||
|
|
||||||
|
#include <mm/opengl/fbo_builder.hpp>
|
||||||
|
#include <mm/opengl/texture_loader.hpp>
|
||||||
|
|
||||||
|
#include <mm/random/srng.hpp>
|
||||||
|
|
||||||
|
using namespace entt::literals;
|
||||||
|
|
||||||
|
const char* argv0;
|
||||||
|
|
||||||
|
static void setup_textures(MM::Engine& engine) {
|
||||||
|
auto& rm_t = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||||
|
auto [w, h] = engine.getService<MM::Services::SDLService>().getWindowSize();
|
||||||
|
|
||||||
|
// we dont have a gbuffer in this example
|
||||||
|
{ // gbuffer
|
||||||
|
// depth
|
||||||
|
#ifdef MM_OPENGL_3_GLES
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"depth",
|
||||||
|
GL_DEPTH_COMPONENT24, // d16 is the onlyone for gles 2 (TODO: test for 3)
|
||||||
|
w, h,
|
||||||
|
GL_DEPTH_COMPONENT, GL_UNSIGNED_INT
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"depth",
|
||||||
|
GL_DEPTH_COMPONENT32F, // TODO: stencil?
|
||||||
|
w, h,
|
||||||
|
GL_DEPTH_COMPONENT, GL_FLOAT
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// albedo
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"albedo",
|
||||||
|
#ifdef MM_OPENGL_3_GLES
|
||||||
|
GL_RGB565,
|
||||||
|
#else
|
||||||
|
GL_RGBA8, // waste of A
|
||||||
|
#endif
|
||||||
|
w, h,
|
||||||
|
GL_RGB, GL_UNSIGNED_BYTE
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// normal
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"normal",
|
||||||
|
// prolly fine, but need to remapp to -1,1
|
||||||
|
#ifdef MM_OPENGL_3_GLES
|
||||||
|
GL_RGB565,
|
||||||
|
#else
|
||||||
|
GL_RGBA8, // waste of A
|
||||||
|
#endif
|
||||||
|
w, h,
|
||||||
|
GL_RGB, GL_UNSIGNED_BYTE
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const float render_scale = 1.f;
|
||||||
|
|
||||||
|
// hdr color gles3 / webgl2
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"hdr_color",
|
||||||
|
GL_RGBA16F,
|
||||||
|
w * render_scale, h * render_scale,
|
||||||
|
GL_RGBA,
|
||||||
|
GL_HALF_FLOAT
|
||||||
|
);
|
||||||
|
{ // filter
|
||||||
|
rm_t.get("hdr_color"_hs)->bind(0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_fbos(MM::Engine& engine) {
|
||||||
|
auto& rs = engine.getService<MM::Services::OpenGLRenderer>();
|
||||||
|
auto& rm_t = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||||
|
|
||||||
|
const float render_scale = 1.f;
|
||||||
|
|
||||||
|
rs.targets["game_view"] = MM::OpenGL::FBOBuilder::start()
|
||||||
|
.attachTexture(rm_t.get("hdr_color"_hs), GL_COLOR_ATTACHMENT0)
|
||||||
|
.attachTexture(rm_t.get("depth"_hs), GL_DEPTH_ATTACHMENT)
|
||||||
|
.setResizeFactors(render_scale, render_scale)
|
||||||
|
.setResize(true)
|
||||||
|
.finish();
|
||||||
|
assert(rs.targets["game_view"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(hdr_bloom_pipeline, it) {
|
||||||
|
MM::Engine engine;
|
||||||
|
|
||||||
|
auto& sdl_ss = engine.addService<MM::Services::SDLService>();
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
|
||||||
|
|
||||||
|
sdl_ss.createGLWindow("hdr_bloom_pipeline_example", 1280, 720);
|
||||||
|
|
||||||
|
engine.addService<MM::Services::OrganizerSceneService>();
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::OrganizerSceneService>());
|
||||||
|
|
||||||
|
bool provide_ret = engine.provide<MM::Services::SceneServiceInterface, MM::Services::OrganizerSceneService>();
|
||||||
|
ASSERT_TRUE(provide_ret);
|
||||||
|
auto& scene = engine.tryService<MM::Services::SceneServiceInterface>()->getScene();
|
||||||
|
|
||||||
|
engine.addService<MM::Services::FilesystemService>(argv0, "hdr_bloom_pipeline_example");
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::FilesystemService>());
|
||||||
|
|
||||||
|
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
|
||||||
|
|
||||||
|
{ // setup rendering
|
||||||
|
// TODO: split vertically
|
||||||
|
setup_textures(engine);
|
||||||
|
setup_fbos(engine);
|
||||||
|
|
||||||
|
// clear
|
||||||
|
auto& clear_opaque = rs.addRenderTask<MM::OpenGL::RenderTasks::Clear>(engine);
|
||||||
|
clear_opaque.target_fbo = "game_view";
|
||||||
|
// clears all color attachments
|
||||||
|
clear_opaque.r = 0.f;
|
||||||
|
clear_opaque.g = 0.f;
|
||||||
|
clear_opaque.b = 0.f;
|
||||||
|
clear_opaque.a = 1.f;
|
||||||
|
clear_opaque.mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
|
||||||
|
|
||||||
|
{ // render, whatever
|
||||||
|
MM::OpenGL::RenderTasks::SimpleRect& bsrr_rend = rs.addRenderTask<MM::OpenGL::RenderTasks::SimpleRect>(engine);
|
||||||
|
bsrr_rend.target_fbo = "game_view";
|
||||||
|
}
|
||||||
|
|
||||||
|
// rn does rt too
|
||||||
|
MM::OpenGL::setup_bloom(engine);
|
||||||
|
|
||||||
|
// not part of setup_bloom
|
||||||
|
auto& comp = rs.addRenderTask<MM::OpenGL::RenderTasks::Composition>(engine);
|
||||||
|
comp.color_tex = "hdr_color";
|
||||||
|
comp.bloom_tex = "blur_tmp1";
|
||||||
|
comp.target_fbo = "display";
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.on_construct<MM::Components::Position2D>().connect<&entt::registry::emplace_or_replace<MM::Components::Position2D_ZOffset>>();
|
||||||
|
scene.on_construct<MM::Components::Position2D>().connect<&entt::registry::emplace_or_replace<MM::Components::Position3D>>();
|
||||||
|
scene.on_construct<MM::Components::Position2D>().connect<&entt::registry::emplace_or_replace<MM::Components::Transform4x4>>();
|
||||||
|
scene.on_construct<MM::Components::Position2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
|
|
||||||
|
scene.on_update<MM::Components::Position2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
|
scene.on_update<MM::Components::Position2D_ZOffset>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
|
scene.on_update<MM::Components::Position3D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
|
scene.on_update<MM::Components::Scale2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
|
scene.on_update<MM::Components::Rotation2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>(); // in this example only rotation is touched
|
||||||
|
|
||||||
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
|
cam.setOrthographic();
|
||||||
|
cam.updateView();
|
||||||
|
|
||||||
|
// setup v system
|
||||||
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
|
org.emplace<MM::Systems::simple_rotational_velocity_patching>("simple_rotational_velocity_patching");
|
||||||
|
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
||||||
|
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
||||||
|
org.emplace<MM::Systems::transform3d_rotate2d>("transform3d_rotate2d");
|
||||||
|
org.emplace<MM::Systems::transform3d_scale2d>("transform3d_scale2d");
|
||||||
|
org.emplace<MM::Systems::transform_clear_dirty>("transform_clear_dirty");
|
||||||
|
|
||||||
|
|
||||||
|
// HACK: instead you would switch to this scene
|
||||||
|
engine.getService<MM::Services::OrganizerSceneService>().updateOrganizerVertices(scene);
|
||||||
|
|
||||||
|
MM::Random::SRNG rng{42};
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
auto e = scene.create();
|
||||||
|
auto& p = scene.emplace<MM::Components::Position2D>(e);
|
||||||
|
p.pos.x = 0.f;
|
||||||
|
p.pos.y = 25.f - i * 10.f;
|
||||||
|
|
||||||
|
auto& s = scene.emplace<MM::Components::Scale2D>(e);
|
||||||
|
s.scale = {50.f, i*0.2f + 0.1f};
|
||||||
|
|
||||||
|
auto& col = scene.emplace<MM::Components::Color>(e);
|
||||||
|
col.color = {3.f, 3.f, 3.f, 1.f};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
auto e = scene.create();
|
||||||
|
auto& p = scene.emplace<MM::Components::Position2D>(e);
|
||||||
|
p.pos.x = i * 9.f - 40;
|
||||||
|
|
||||||
|
// zoffset is created by event
|
||||||
|
|
||||||
|
auto& s = scene.emplace<MM::Components::Scale2D>(e);
|
||||||
|
s.scale = {5,5};
|
||||||
|
|
||||||
|
scene.emplace<MM::Components::Rotation2D>(e);
|
||||||
|
|
||||||
|
auto& v = scene.emplace<MM::Components::Velocity2DRotation>(e);
|
||||||
|
v.rot_vel = i * 0.3f;
|
||||||
|
|
||||||
|
auto& col = scene.emplace<MM::Components::Color>(e);
|
||||||
|
col.color = {rng.zeroToOne()*2.f, rng.zeroToOne()*2.f, rng.zeroToOne()*2.f, 1.f};
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
argv0 = argv[0];
|
||||||
|
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
371
framework/opengl_renderer/test/lite_particles2d.cpp
Normal file
371
framework/opengl_renderer/test/lite_particles2d.cpp
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <mm/engine.hpp>
|
||||||
|
|
||||||
|
#include <mm/services/filesystem.hpp>
|
||||||
|
#include <mm/services/sdl_service.hpp>
|
||||||
|
#include <mm/services/organizer_scene.hpp>
|
||||||
|
#include <mm/services/opengl_renderer.hpp>
|
||||||
|
|
||||||
|
#include <mm/fs_const_archiver.hpp>
|
||||||
|
|
||||||
|
#include <entt/entity/registry.hpp>
|
||||||
|
#include <entt/entity/organizer.hpp>
|
||||||
|
#include <entt/core/hashed_string.hpp>
|
||||||
|
|
||||||
|
#include <mm/opengl/render_tasks/clear.hpp>
|
||||||
|
#include <mm/opengl/render_tasks/lite_particles2d.hpp>
|
||||||
|
#include <mm/opengl/bloom.hpp>
|
||||||
|
#include <mm/opengl/render_tasks/composition.hpp>
|
||||||
|
|
||||||
|
// ctx
|
||||||
|
#include <mm/opengl/components/lite_particles2d.hpp>
|
||||||
|
#include <mm/components/time_delta.hpp>
|
||||||
|
#include <mm/opengl/camera_3d.hpp>
|
||||||
|
|
||||||
|
// components
|
||||||
|
#include <mm/components/position2d.hpp>
|
||||||
|
|
||||||
|
#include <mm/resource_manager.hpp>
|
||||||
|
#include <mm/opengl/texture_loader.hpp>
|
||||||
|
#include <mm/opengl/lite_particles2d_type_loader.hpp>
|
||||||
|
|
||||||
|
#include <mm/opengl/fbo_builder.hpp>
|
||||||
|
|
||||||
|
#include <mm/random/srng.hpp>
|
||||||
|
|
||||||
|
#include <glm/vec2.hpp>
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
|
#include <glm/common.hpp>
|
||||||
|
#include <glm/gtc/constants.hpp>
|
||||||
|
#include <glm/trigonometric.hpp>
|
||||||
|
|
||||||
|
#include <mm/scalar_range2.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace entt::literals;
|
||||||
|
|
||||||
|
namespace Components {
|
||||||
|
|
||||||
|
// or what ever
|
||||||
|
struct LiteParticles2DEmitter {
|
||||||
|
float age {0.f}; // this changes each tick, if >=1, spawn and reset to 0
|
||||||
|
float age_delta {1.f}; // times per sec
|
||||||
|
|
||||||
|
MM::ScalarRange2<uint16_t> particle_count {1u, 1u};
|
||||||
|
|
||||||
|
// particles data
|
||||||
|
|
||||||
|
std::string p_type {};
|
||||||
|
|
||||||
|
MM::ScalarRange2<float> p_pos_x {0.f, 0.f};
|
||||||
|
MM::ScalarRange2<float> p_pos_y {0.f, 0.f};
|
||||||
|
|
||||||
|
MM::ScalarRange2<float> p_dir {0.f, 0.f}; // 0-1, not rad
|
||||||
|
MM::ScalarRange2<float> p_dir_force {0.f, 0.f};
|
||||||
|
|
||||||
|
MM::ScalarRange2<float> p_age {0.f, 0.f};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Components
|
||||||
|
|
||||||
|
namespace Systems {
|
||||||
|
|
||||||
|
void lite_particles2d_emit(
|
||||||
|
entt::view<entt::get_t<
|
||||||
|
const MM::Components::Position2D,
|
||||||
|
Components::LiteParticles2DEmitter
|
||||||
|
>> view,
|
||||||
|
const MM::Components::TimeDelta& td,
|
||||||
|
MM::Components::LiteParticles2DUploadQueue& lp_uq,
|
||||||
|
MM::Random::SRNG& rng
|
||||||
|
) {
|
||||||
|
view.each([&lp_uq, &td, &rng](const auto& pos, Components::LiteParticles2DEmitter& lpe) {
|
||||||
|
lpe.age += lpe.age_delta * td.tickDelta;
|
||||||
|
|
||||||
|
if (lpe.age < 1.f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpe.age = 0.f; // TODO: dont discard ?
|
||||||
|
|
||||||
|
const auto type = entt::hashed_string::value(lpe.p_type.c_str());
|
||||||
|
|
||||||
|
const size_t count = rng.range(lpe.particle_count);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
float dir = rng.range(lpe.p_dir) * glm::two_pi<float>();
|
||||||
|
lp_uq.queue.push(MM::Components::LiteParticle2D{
|
||||||
|
type, // type
|
||||||
|
|
||||||
|
//{rng.negOneToOne() * 30.f, rng.negOneToOne() * 30.f}, // pos
|
||||||
|
pos.pos + /*lpe.pos_offset +*/ glm::vec2{rng.range(lpe.p_pos_x), rng.range(lpe.p_pos_y)}, // pos
|
||||||
|
glm::vec2{glm::cos(dir), glm::sin(dir)} * rng.range(lpe.p_dir_force), // vel
|
||||||
|
|
||||||
|
rng.range(lpe.p_age) // age
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Systems
|
||||||
|
|
||||||
|
const char* argv0;
|
||||||
|
|
||||||
|
static void setup_textures(MM::Engine& engine) {
|
||||||
|
auto& rm_t = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||||
|
auto [w, h] = engine.getService<MM::Services::SDLService>().getWindowSize();
|
||||||
|
|
||||||
|
// we dont have a gbuffer in this example
|
||||||
|
{ // gbuffer
|
||||||
|
// depth
|
||||||
|
#ifdef MM_OPENGL_3_GLES
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"depth",
|
||||||
|
GL_DEPTH_COMPONENT24, // d16 is the onlyone for gles 2 (TODO: test for 3)
|
||||||
|
w, h,
|
||||||
|
GL_DEPTH_COMPONENT, GL_UNSIGNED_INT
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"depth",
|
||||||
|
GL_DEPTH_COMPONENT32F, // TODO: stencil?
|
||||||
|
w, h,
|
||||||
|
GL_DEPTH_COMPONENT, GL_FLOAT
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const float render_scale = 1.f;
|
||||||
|
|
||||||
|
// hdr color gles3 / webgl2
|
||||||
|
rm_t.reload<MM::OpenGL::TextureLoaderEmpty>(
|
||||||
|
"hdr_color",
|
||||||
|
GL_RGBA16F,
|
||||||
|
w * render_scale, h * render_scale,
|
||||||
|
GL_RGBA,
|
||||||
|
GL_HALF_FLOAT
|
||||||
|
);
|
||||||
|
{ // filter
|
||||||
|
rm_t.get("hdr_color"_hs)->bind(0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_fbos(MM::Engine& engine) {
|
||||||
|
auto& rs = engine.getService<MM::Services::OpenGLRenderer>();
|
||||||
|
auto& rm_t = MM::ResourceManager<MM::OpenGL::Texture>::ref();
|
||||||
|
|
||||||
|
const float render_scale = 1.f;
|
||||||
|
|
||||||
|
rs.targets["game_view"] = MM::OpenGL::FBOBuilder::start()
|
||||||
|
.attachTexture(rm_t.get("hdr_color"_hs), GL_COLOR_ATTACHMENT0)
|
||||||
|
.attachTexture(rm_t.get("depth"_hs), GL_DEPTH_ATTACHMENT)
|
||||||
|
.setResizeFactors(render_scale, render_scale)
|
||||||
|
.setResize(true)
|
||||||
|
.finish();
|
||||||
|
assert(rs.targets["game_view"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_particles_types(MM::Engine& engine) {
|
||||||
|
auto& lpt_rm = MM::ResourceManager<MM::OpenGL::LiteParticles2DType>::ref();
|
||||||
|
|
||||||
|
lpt_rm.load<MM::OpenGL::LiteParticles2DTypeLoaderJson>("MM::spark1",
|
||||||
|
R"({
|
||||||
|
"compute": {
|
||||||
|
"age_delta": 2.0,
|
||||||
|
"force_vec": { "x": 0.0, "y": -5.0 },
|
||||||
|
"turbulence": 1.0,
|
||||||
|
"turbulence_individuality": 1.0,
|
||||||
|
"turbulence_noise_scale": 1.0,
|
||||||
|
"turbulence_time_scale": 1.0,
|
||||||
|
"dampening": 1.0
|
||||||
|
},
|
||||||
|
"render": {
|
||||||
|
"color_start": {
|
||||||
|
"x": 6.0,
|
||||||
|
"y": 6.0,
|
||||||
|
"z": 1.8,
|
||||||
|
"w": 1.0
|
||||||
|
},
|
||||||
|
"color_end": {
|
||||||
|
"x": 1.5,
|
||||||
|
"y": 1.0,
|
||||||
|
"z": 0.3,
|
||||||
|
"w": 1.0
|
||||||
|
},
|
||||||
|
"size_start": 0.01,
|
||||||
|
"size_end": 0.002
|
||||||
|
}
|
||||||
|
})"_json);
|
||||||
|
|
||||||
|
// mount into vfx
|
||||||
|
FS_CONST_MOUNT_FILE("/particles/lite_particles2d/fire1.json",
|
||||||
|
R"({
|
||||||
|
"compute": {
|
||||||
|
"age_delta": 1.0,
|
||||||
|
"force_vec": { "x": 0.0, "y": 5.0 },
|
||||||
|
"turbulence": 5.0,
|
||||||
|
"turbulence_individuality": 1.0,
|
||||||
|
"turbulence_noise_scale": 1.0,
|
||||||
|
"turbulence_time_scale": 1.0,
|
||||||
|
"dampening": 0.0
|
||||||
|
},
|
||||||
|
"render": {
|
||||||
|
"color_start": {
|
||||||
|
"x": 3.0,
|
||||||
|
"y": 2.1,
|
||||||
|
"z": 1.5,
|
||||||
|
"w": 0.8
|
||||||
|
},
|
||||||
|
"color_end": {
|
||||||
|
"x": 3.0,
|
||||||
|
"y": 1.1,
|
||||||
|
"z": 1.0,
|
||||||
|
"w": 0.0
|
||||||
|
},
|
||||||
|
"size_start": 0.15,
|
||||||
|
"size_end": 0.4
|
||||||
|
}
|
||||||
|
})");
|
||||||
|
// and load it
|
||||||
|
lpt_rm.load<MM::OpenGL::LiteParticles2DTypeLoaderFile>("MM::fire1", engine, "/particles/lite_particles2d/fire1.json");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(lite_particles2d, it) {
|
||||||
|
MM::Engine engine;
|
||||||
|
|
||||||
|
auto& sdl_ss = engine.addService<MM::Services::SDLService>();
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
|
||||||
|
|
||||||
|
sdl_ss.createGLWindow("lite_particles2d", 1280, 720);
|
||||||
|
|
||||||
|
engine.addService<MM::Services::OrganizerSceneService>();
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::OrganizerSceneService>());
|
||||||
|
|
||||||
|
bool provide_ret = engine.provide<MM::Services::SceneServiceInterface, MM::Services::OrganizerSceneService>();
|
||||||
|
ASSERT_TRUE(provide_ret);
|
||||||
|
auto& scene = engine.tryService<MM::Services::SceneServiceInterface>()->getScene();
|
||||||
|
|
||||||
|
engine.addService<MM::Services::FilesystemService>(argv0, "lite_particles2d");
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::FilesystemService>());
|
||||||
|
|
||||||
|
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
|
||||||
|
|
||||||
|
// load particle types
|
||||||
|
// before addRenderTask<LiteParticle2D>
|
||||||
|
// OR
|
||||||
|
// call LiteParticle2D::resetTypeBuffers()
|
||||||
|
setup_particles_types(engine);
|
||||||
|
|
||||||
|
{ // setup rendering
|
||||||
|
// TODO: split vertically
|
||||||
|
setup_textures(engine);
|
||||||
|
setup_fbos(engine);
|
||||||
|
|
||||||
|
// clear
|
||||||
|
auto& clear_opaque = rs.addRenderTask<MM::OpenGL::RenderTasks::Clear>(engine);
|
||||||
|
clear_opaque.target_fbo = "game_view";
|
||||||
|
// clears all color attachments
|
||||||
|
clear_opaque.r = 0.f;
|
||||||
|
clear_opaque.g = 0.f;
|
||||||
|
clear_opaque.b = 0.f;
|
||||||
|
clear_opaque.a = 1.f;
|
||||||
|
clear_opaque.mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
|
||||||
|
|
||||||
|
{ // render
|
||||||
|
//MM::OpenGL::RenderTasks::SimpleRect& bsrr_rend = rs.addRenderTask<MM::OpenGL::RenderTasks::SimpleRect>(engine);
|
||||||
|
//bsrr_rend.target_fbo = "game_view";
|
||||||
|
auto& lprt = rs.addRenderTask<MM::OpenGL::RenderTasks::LiteParticles2D>(engine);
|
||||||
|
lprt.target_fbo = "game_view";
|
||||||
|
}
|
||||||
|
|
||||||
|
// rn does rt too
|
||||||
|
MM::OpenGL::setup_bloom(engine);
|
||||||
|
|
||||||
|
// not part of setup_bloom
|
||||||
|
auto& comp = rs.addRenderTask<MM::OpenGL::RenderTasks::Composition>(engine);
|
||||||
|
comp.color_tex = "hdr_color";
|
||||||
|
comp.bloom_tex = "blur_tmp1";
|
||||||
|
comp.target_fbo = "display";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// setup scene
|
||||||
|
|
||||||
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
|
cam.horizontalViewPortSize = 30.f;
|
||||||
|
cam.setOrthographic();
|
||||||
|
cam.updateView();
|
||||||
|
|
||||||
|
scene.ctx().emplace<MM::Components::LiteParticles2DUploadQueue>();
|
||||||
|
|
||||||
|
scene.ctx().emplace<MM::Random::SRNG>(42u);
|
||||||
|
|
||||||
|
// setup v system
|
||||||
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
|
org.emplace<Systems::lite_particles2d_emit>("lite_particles2d_emit");
|
||||||
|
|
||||||
|
// HACK: instead you would switch to this scene
|
||||||
|
engine.getService<MM::Services::OrganizerSceneService>().updateOrganizerVertices(scene);
|
||||||
|
|
||||||
|
{ // default
|
||||||
|
auto e = scene.create();
|
||||||
|
auto& p = scene.emplace<MM::Components::Position2D>(e);
|
||||||
|
p.pos.x = -10.f;
|
||||||
|
|
||||||
|
auto& lpe = scene.emplace<Components::LiteParticles2DEmitter>(e);
|
||||||
|
lpe.age_delta = 60.f;
|
||||||
|
lpe.particle_count = {1, 1};
|
||||||
|
lpe.p_type = "default";
|
||||||
|
lpe.p_dir = {-0.1f, +0.1f};
|
||||||
|
lpe.p_dir_force = {0.f, 8.f};
|
||||||
|
lpe.p_age = {0.f, 0.7f};
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // sparks
|
||||||
|
auto e = scene.create();
|
||||||
|
auto& p = scene.emplace<MM::Components::Position2D>(e);
|
||||||
|
p.pos.x = 0.f;
|
||||||
|
|
||||||
|
auto& lpe = scene.emplace<Components::LiteParticles2DEmitter>(e);
|
||||||
|
lpe.age_delta = 1.f;
|
||||||
|
lpe.particle_count = {25, 40};
|
||||||
|
lpe.p_type = "MM::spark1";
|
||||||
|
lpe.p_dir = {0.f, 1.f};
|
||||||
|
lpe.p_dir_force = {0.f, 1.f}; // m/s
|
||||||
|
lpe.p_age = {0.f, 0.7f};
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // fire
|
||||||
|
auto e = scene.create();
|
||||||
|
auto& p = scene.emplace<MM::Components::Position2D>(e);
|
||||||
|
p.pos.x = 10.f;
|
||||||
|
|
||||||
|
auto& lpe = scene.emplace<Components::LiteParticles2DEmitter>(e);
|
||||||
|
lpe.age_delta = 60.f;
|
||||||
|
lpe.particle_count = {1, 1};
|
||||||
|
lpe.p_type = "MM::fire1";
|
||||||
|
lpe.p_dir = {0.f, 1.f};
|
||||||
|
lpe.p_dir_force = {0.f, 1.f};
|
||||||
|
lpe.p_age = {0.f, 0.5f};
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
argv0 = argv[0];
|
||||||
|
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
@ -62,8 +62,12 @@ TEST(simple_rect_render_task, it) {
|
|||||||
scene.on_update<MM::Components::Scale2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
scene.on_update<MM::Components::Scale2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
scene.on_update<MM::Components::Rotation2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>(); // in this example only rotation is touched
|
scene.on_update<MM::Components::Rotation2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>(); // in this example only rotation is touched
|
||||||
|
|
||||||
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
|
cam.setOrthographic();
|
||||||
|
cam.updateView();
|
||||||
|
|
||||||
// setup v system
|
// setup v system
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
org.emplace<MM::Systems::simple_rotational_velocity_patching>("simple_rotational_velocity_patching");
|
org.emplace<MM::Systems::simple_rotational_velocity_patching>("simple_rotational_velocity_patching");
|
||||||
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
||||||
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
||||||
|
@ -65,9 +65,12 @@ TEST(simple_sprite_render_task, it) {
|
|||||||
scene.on_update<MM::Components::Scale2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
scene.on_update<MM::Components::Scale2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
scene.on_update<MM::Components::Rotation2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>(); // in this example only rotation is touched
|
scene.on_update<MM::Components::Rotation2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>(); // in this example only rotation is touched
|
||||||
|
|
||||||
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
|
cam.setOrthographic();
|
||||||
|
cam.updateView();
|
||||||
|
|
||||||
// setup v system
|
// setup v system
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
org.emplace<MM::Systems::simple_rotational_velocity_patching>("simple_rotational_velocity_patching");
|
org.emplace<MM::Systems::simple_rotational_velocity_patching>("simple_rotational_velocity_patching");
|
||||||
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
||||||
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
||||||
|
@ -64,7 +64,7 @@ TEST(simple_spritesheet_render_task, it) {
|
|||||||
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
|
auto& rs = engine.addService<MM::Services::OpenGLRenderer>();
|
||||||
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
|
ASSERT_TRUE(engine.enableService<MM::Services::OpenGLRenderer>());
|
||||||
|
|
||||||
auto& cam = scene.set<MM::OpenGL::Camera3D>();
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
cam.horizontalViewPortSize = 5;
|
cam.horizontalViewPortSize = 5;
|
||||||
cam.setOrthographic();
|
cam.setOrthographic();
|
||||||
cam.updateView();
|
cam.updateView();
|
||||||
@ -82,8 +82,8 @@ TEST(simple_spritesheet_render_task, it) {
|
|||||||
scene.on_update<MM::Components::Scale2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
scene.on_update<MM::Components::Scale2D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
|
|
||||||
// setup systems
|
// setup systems
|
||||||
scene.set<float>(0.f); // accu
|
scene.ctx().emplace<float>(0.f); // accu
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
org.emplace<&update_spritesheet_animation>("update_spritesheet_animation");
|
org.emplace<&update_spritesheet_animation>("update_spritesheet_animation");
|
||||||
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
||||||
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
||||||
@ -103,7 +103,7 @@ TEST(simple_spritesheet_render_task, it) {
|
|||||||
auto e = scene.create();
|
auto e = scene.create();
|
||||||
auto& p = scene.emplace<MM::Components::Position2D>(e);
|
auto& p = scene.emplace<MM::Components::Position2D>(e);
|
||||||
p.pos.x = -1.f;
|
p.pos.x = -1.f;
|
||||||
|
|
||||||
// zoffset is created by event
|
// zoffset is created by event
|
||||||
|
|
||||||
auto& s = scene.emplace<MM::Components::Scale2D>(e);
|
auto& s = scene.emplace<MM::Components::Scale2D>(e);
|
||||||
|
@ -39,7 +39,7 @@ TEST(tilemap_render_task_test, it) {
|
|||||||
ASSERT_TRUE(provide_ret);
|
ASSERT_TRUE(provide_ret);
|
||||||
auto& scene = engine.tryService<MM::Services::SceneServiceInterface>()->getScene();
|
auto& scene = engine.tryService<MM::Services::SceneServiceInterface>()->getScene();
|
||||||
|
|
||||||
auto& cam = scene.set<MM::OpenGL::Camera3D>();
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
cam.translation = {2.f, -2.f, 0.f};
|
cam.translation = {2.f, -2.f, 0.f};
|
||||||
cam.horizontalViewPortSize = 20.f;
|
cam.horizontalViewPortSize = 20.f;
|
||||||
cam.setOrthographic();
|
cam.setOrthographic();
|
||||||
@ -63,7 +63,7 @@ TEST(tilemap_render_task_test, it) {
|
|||||||
scene.on_update<MM::Components::Position2D_ZOffset>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
scene.on_update<MM::Components::Position2D_ZOffset>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
scene.on_update<MM::Components::Position3D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
scene.on_update<MM::Components::Position3D>().connect<&entt::registry::emplace_or_replace<MM::Components::DirtyTransformTag>>();
|
||||||
|
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
org.emplace<MM::Systems::position3d_from_2d>("position3d_from_2d");
|
||||||
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
org.emplace<MM::Systems::transform3d_translate>("transform3d_translate");
|
||||||
org.emplace<MM::Systems::transform_clear_dirty>("transform_clear_dirty");
|
org.emplace<MM::Systems::transform_clear_dirty>("transform_clear_dirty");
|
||||||
|
@ -52,7 +52,7 @@ bool OrganizerSceneService::enable(Engine& engine, std::vector<UpdateStrategies:
|
|||||||
// default scene
|
// default scene
|
||||||
if (!_scene) {
|
if (!_scene) {
|
||||||
_scene = std::make_unique<Scene>();
|
_scene = std::make_unique<Scene>();
|
||||||
_scene->set<MM::Engine&>(engine);
|
_scene->ctx().emplace<MM::Engine&>(engine);
|
||||||
updateOrganizerVertices(*_scene);
|
updateOrganizerVertices(*_scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,14 +74,14 @@ void OrganizerSceneService::sceneFixedUpdate(Engine&) {
|
|||||||
|
|
||||||
size_t continuous_counter = 0;
|
size_t continuous_counter = 0;
|
||||||
|
|
||||||
auto& time_ctx = _scene->ctx_or_set<MM::Components::TimeDelta>(f_delta, initial_delta_factor);
|
auto& time_ctx = _scene->ctx().emplace<MM::Components::TimeDelta>(f_delta, initial_delta_factor);
|
||||||
time_ctx.tickDelta = f_delta * time_ctx.deltaFactor;
|
time_ctx.tickDelta = f_delta * time_ctx.deltaFactor;
|
||||||
|
|
||||||
while (_accumulator >= f_delta){
|
while (_accumulator >= f_delta){
|
||||||
_accumulator -= f_delta;
|
_accumulator -= f_delta;
|
||||||
continuous_counter++;
|
continuous_counter++;
|
||||||
|
|
||||||
for (auto&& v : _scene->ctx<std::vector<entt::organizer::vertex>>()) {
|
for (auto&& v : _scene->ctx().at<std::vector<entt::organizer::vertex>>()) {
|
||||||
v.callback()(v.data(), *_scene);
|
v.callback()(v.data(), *_scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,8 +97,8 @@ void OrganizerSceneService::changeSceneFixedUpdate(Engine& engine) {
|
|||||||
if (_next_scene) {
|
if (_next_scene) {
|
||||||
LOG_OSS("changing scene...");
|
LOG_OSS("changing scene...");
|
||||||
_scene = std::move(_next_scene);
|
_scene = std::move(_next_scene);
|
||||||
if (!_scene->try_ctx<MM::Engine>()) {
|
if (!_scene->ctx().contains<MM::Engine>()) {
|
||||||
_scene->set<MM::Engine&>(engine); // make engine accessible from scene
|
_scene->ctx().emplace<MM::Engine&>(engine); // make engine accessible from scene
|
||||||
}
|
}
|
||||||
updateOrganizerVertices(*_scene);
|
updateOrganizerVertices(*_scene);
|
||||||
}
|
}
|
||||||
@ -119,14 +119,14 @@ void OrganizerSceneService::changeSceneNow(std::unique_ptr<Scene>&& new_scene) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OrganizerSceneService::updateOrganizerVertices(Scene& scene) {
|
void OrganizerSceneService::updateOrganizerVertices(Scene& scene) {
|
||||||
scene.ctx_or_set<std::vector<entt::organizer::vertex>>() =
|
scene.ctx().emplace<std::vector<entt::organizer::vertex>>() =
|
||||||
scene.ctx_or_set<entt::organizer>().graph();
|
scene.ctx().emplace<entt::organizer>().graph();
|
||||||
|
|
||||||
if (!scene.try_ctx<MM::Components::TimeDelta>()) {
|
if (!scene.ctx().contains<MM::Components::TimeDelta>()) {
|
||||||
scene.set<MM::Components::TimeDelta>();
|
scene.ctx().emplace<MM::Components::TimeDelta>();
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_DEBUG("graph:\n{}", scene.ctx<std::vector<entt::organizer::vertex>>());
|
SPDLOG_DEBUG("graph:\n{}", scene.ctx().at<std::vector<entt::organizer::vertex>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OrganizerSceneService::resetTime(void) {
|
void OrganizerSceneService::resetTime(void) {
|
||||||
|
@ -85,7 +85,8 @@ class ResourceManager {
|
|||||||
discard(entt::hashed_string{id}.value());
|
discard(entt::hashed_string{id}.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void each(std::function<void(res_id_type, std::shared_ptr<Resource>)>& fn) {
|
template<typename FN>
|
||||||
|
void each(FN&& fn) {
|
||||||
for (auto& it : _storage) {
|
for (auto& it : _storage) {
|
||||||
fn(it.first, it.second);
|
fn(it.first, it.second);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
namespace MM::std_utils {
|
namespace MM::std_utils {
|
||||||
|
|
||||||
|
inline std::string_view trim_prefix(std::string_view sv) {
|
||||||
|
while (!sv.empty() && std::isspace(sv.front())) {
|
||||||
|
sv.remove_prefix(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sv;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string_view trim_suffix(std::string_view sv) {
|
||||||
|
while (!sv.empty() && std::isspace(sv.back())) {
|
||||||
|
sv.remove_suffix(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sv;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string_view trim(std::string_view sv) {
|
||||||
|
return trim_suffix(trim_prefix(sv));
|
||||||
|
}
|
||||||
|
|
||||||
// src : https://marcoarena.wordpress.com/2017/01/03/string_view-odi-et-amo/
|
// src : https://marcoarena.wordpress.com/2017/01/03/string_view-odi-et-amo/
|
||||||
inline std::vector<std::string_view> split(std::string_view str, const char* delims) {
|
inline std::vector<std::string_view> split(std::string_view str, const char* delims) {
|
||||||
std::vector<std::string_view> ret;
|
std::vector<std::string_view> ret;
|
||||||
|
@ -120,11 +120,11 @@ void create_mm_logo(MM::Engine& engine, MM::Services::ScreenDirector::Screen& sc
|
|||||||
auto new_scene = std::make_unique<MM::Scene>();
|
auto new_scene = std::make_unique<MM::Scene>();
|
||||||
auto& scene = *new_scene;
|
auto& scene = *new_scene;
|
||||||
|
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
|
|
||||||
scene.set<MM::Engine&>(_engine); // alias
|
scene.ctx().emplace<MM::Engine&>(_engine); // alias
|
||||||
|
|
||||||
scene.set<Components::screen_timer>(0.f, screen_duration, next_screen);
|
scene.ctx().emplace<Components::screen_timer>(0.f, screen_duration, next_screen);
|
||||||
|
|
||||||
org.emplace<Systems::screen_timer_system>("screen_timer_system");
|
org.emplace<Systems::screen_timer_system>("screen_timer_system");
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ void create_mm_logo(MM::Engine& engine, MM::Services::ScreenDirector::Screen& sc
|
|||||||
org.emplace<MM::Systems::transform3d_scale2d>("transform3d_scale2d");
|
org.emplace<MM::Systems::transform3d_scale2d>("transform3d_scale2d");
|
||||||
//org.emplace<MM::Systems::transform_clear_dirty>("transform_clear_dirty");
|
//org.emplace<MM::Systems::transform_clear_dirty>("transform_clear_dirty");
|
||||||
|
|
||||||
auto& cam = scene.set<MM::OpenGL::Camera3D>();
|
auto& cam = scene.ctx().emplace<MM::OpenGL::Camera3D>();
|
||||||
cam.horizontalViewPortSize = 89.f;
|
cam.horizontalViewPortSize = 89.f;
|
||||||
cam.setOrthographic();
|
cam.setOrthographic();
|
||||||
cam.updateView();
|
cam.updateView();
|
||||||
|
@ -29,7 +29,7 @@ TEST(player_velocity, basic_run) {
|
|||||||
auto& scene = engine.getService<MM::Services::SceneServiceInterface>().getScene();
|
auto& scene = engine.getService<MM::Services::SceneServiceInterface>().getScene();
|
||||||
|
|
||||||
// setup v system
|
// setup v system
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
org.emplace<&MM::Systems::player_velocity2d>("player_velocity2d");
|
org.emplace<&MM::Systems::player_velocity2d>("player_velocity2d");
|
||||||
|
|
||||||
// HACK: instead you would switch to this scene
|
// HACK: instead you would switch to this scene
|
||||||
|
@ -11,13 +11,13 @@ TEST(simple_velocity_2d, basic_run) {
|
|||||||
MM::Scene scene;
|
MM::Scene scene;
|
||||||
|
|
||||||
// setup v system
|
// setup v system
|
||||||
auto& org = scene.set<entt::organizer>();
|
auto& org = scene.ctx().emplace<entt::organizer>();
|
||||||
org.emplace<&MM::Systems::simple_positional_velocity>("simple_positional_velocity");
|
org.emplace<&MM::Systems::simple_positional_velocity>("simple_positional_velocity");
|
||||||
org.emplace<&MM::Systems::simple_rotational_velocity>("simple_rotational_velocity");
|
org.emplace<&MM::Systems::simple_rotational_velocity>("simple_rotational_velocity");
|
||||||
auto graph = org.graph();
|
auto graph = org.graph();
|
||||||
|
|
||||||
// setup delta
|
// setup delta
|
||||||
auto& time_ctx = scene.ctx_or_set<MM::Components::TimeDelta>(1.f/60.f, 1.f);
|
auto& time_ctx = scene.ctx().emplace<MM::Components::TimeDelta>(1.f/60.f, 1.f);
|
||||||
time_ctx.tickDelta = 1.f/60.f * time_ctx.deltaFactor;
|
time_ctx.tickDelta = 1.f/60.f * time_ctx.deltaFactor;
|
||||||
|
|
||||||
// setup test entity
|
// setup test entity
|
||||||
|
Reference in New Issue
Block a user