diff --git a/assets/test/shaders/demo_6_2d.frag.glsl b/assets/test/shaders/demo_6_2d.frag.glsl new file mode 100644 index 0000000000..c4beb1dd8e --- /dev/null +++ b/assets/test/shaders/demo_6_2d.frag.glsl @@ -0,0 +1,37 @@ +#version 330 + +in vec2 vert_uv; + +layout(location=0) out vec4 col; + +uniform sampler2D tex; + +// position (top left corner) and size: (x, y, width, height) +uniform vec4 tile_params; + +vec2 uv = vec2( + vert_uv.x * tile_params.z + tile_params.x, + vert_uv.y * tile_params.w + tile_params.y +); + +void main() { + vec4 tex_val = texture(tex, uv); + int alpha = int(round(tex_val.a * 255)); + switch (alpha) { + case 0: + col = tex_val; + discard; + case 254: + col = vec4(1.0f, 0.0f, 0.0f, 1.0f); + break; + case 252: + col = vec4(0.0f, 1.0f, 0.0f, 1.0f); + break; + case 250: + col = vec4(0.0f, 0.0f, 1.0f, 1.0f); + break; + default: + col = tex_val; + break; + } +} diff --git a/assets/test/shaders/demo_6_2d.vert.glsl b/assets/test/shaders/demo_6_2d.vert.glsl new file mode 100644 index 0000000000..6a17baf834 --- /dev/null +++ b/assets/test/shaders/demo_6_2d.vert.glsl @@ -0,0 +1,83 @@ +#version 330 + +layout(location=0) in vec2 v_position; +layout(location=1) in vec2 uv; + +out vec2 vert_uv; + +// camera parameters for transforming the object position +// and scaling the subtex to the correct size +layout (std140) uniform camera { + // view matrix (world to view space) + mat4 view; + // projection matrix (view to clip space) + mat4 proj; + // inverse zoom factor (1.0 / zoom) + // high zoom = upscale subtex + // low zoom = downscale subtex + float inv_zoom; + // inverse viewport size (1.0 / viewport size) + vec2 inv_viewport_size; +}; + +// position of the object in world space +uniform vec3 obj_world_position; + +// parameters for scaling and moving the subtex +// to the correct position in clip space + +// animation scalefactor +// scales the vertex positions so that they +// match the subtex dimensions +// +// high animation scale = downscale subtex +// low animation scale = upscale subtex +uniform float scale; + +// size of the subtex (in pixels) +uniform vec2 subtex_size; + +// offset of the subtex anchor point +// from the subtex center (in pixels) +// used to move the subtex so that the anchor point +// is at the object position +uniform vec2 anchor_offset; + +void main() { + // translate the position of the object from world space to clip space + // this is the position where we want to draw the subtex in 2D + vec4 obj_clip_pos = proj * view * vec4(obj_world_position, 1.0); + + // subtex has to be scaled to account for the zoom factor + // and the animation scale factor. essentially this is (animation scale / zoom). + float zoom_scale = scale * inv_zoom; + + // Scale the subtex vertices + // we have to account for the viewport size to get the correct dimensions + // and then scale the subtex to the zoom factor to get the correct size + vec2 vert_scale = zoom_scale * subtex_size * inv_viewport_size; + + // Scale the anchor offset with the same method as above + // to get the correct anchor position in the viewport + vec2 anchor_scale = zoom_scale * anchor_offset * inv_viewport_size; + + // offset the clip position by the offset of the subtex anchor + // imagine this as pinning the subtex to the object position at the subtex anchor point + obj_clip_pos += vec4(anchor_scale.x, anchor_scale.y, 0.0, 0.0); + + // create a move matrix for positioning the vertices + // uses the vert scale and the transformed object position in clip space + mat4 move = mat4(vert_scale.x, 0.0, 0.0, 0.0, + 0.0, vert_scale.y, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + obj_clip_pos.x, obj_clip_pos.y, obj_clip_pos.z, 1.0); + + // calculate the final vertex position + gl_Position = move * vec4(v_position, 0.0, 1.0); + + // flip y axis because OpenGL uses bottom-left as its origin + float uv_x = uv.x; + float uv_y = 1.0 - uv.y; + + vert_uv = vec2(uv_x, uv_y); +} diff --git a/assets/test/shaders/demo_6_2d_frame.frag.glsl b/assets/test/shaders/demo_6_2d_frame.frag.glsl new file mode 100644 index 0000000000..c67ca484cc --- /dev/null +++ b/assets/test/shaders/demo_6_2d_frame.frag.glsl @@ -0,0 +1,7 @@ +#version 330 + +out vec4 col; + +void main() { + col = vec4(1.0, 0.0, 0.0, 0.8); +} diff --git a/assets/test/shaders/demo_6_2d_frame.vert.glsl b/assets/test/shaders/demo_6_2d_frame.vert.glsl new file mode 100644 index 0000000000..8d7d13b6be --- /dev/null +++ b/assets/test/shaders/demo_6_2d_frame.vert.glsl @@ -0,0 +1,58 @@ +#version 330 + +layout(location=0) in vec2 v_position; + +// camera parameters for transforming the object position +// and scaling the subtex to the correct size +layout (std140) uniform camera { + // view matrix (world to view space) + mat4 view; + // projection matrix (view to clip space) + mat4 proj; + // inverse zoom factor (1.0 / zoom) + float inv_zoom; + // inverse viewport size (1.0 / viewport size) + vec2 inv_viewport_size; +}; + +// position of the object in world space +uniform vec3 obj_world_position; + +// parameters for scaling and moving the subtex +// to the correct position in clip space + +// animation scalefactor +// scales the vertex positions so that they +// match the subtex dimensions +// +// high animation scale = downscale subtex +// low animation scale = upscale subtex +uniform float scale; + +// size of the frame (in pixels) +uniform vec2 frame_size; + +void main() { + // translate the position of the object from world space to clip space + // this is the position where we want to draw the subtex in 2D + vec4 obj_clip_pos = proj * view * vec4(obj_world_position, 1.0); + + // subtex has to be scaled to account for the zoom factor + // and the animation scale factor. essentially this is (animation scale / zoom). + float zoom_scale = scale * inv_zoom; + + // Scale the subtex vertices + // we have to account for the viewport size to get the correct dimensions + // and then scale the frame to the zoom factor to get the correct size + vec2 vert_scale = zoom_scale * frame_size * inv_viewport_size; + + // create a move matrix for positioning the vertices + // uses the vert scale and the transformed object position in clip space + mat4 move = mat4(vert_scale.x, 0.0, 0.0, 0.0, + 0.0, vert_scale.y, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + obj_clip_pos.x, obj_clip_pos.y, obj_clip_pos.z, 1.0); + + // calculate the final vertex position + gl_Position = move * vec4(v_position, 0.0, 1.0); +} diff --git a/assets/test/shaders/demo_6_3d.frag.glsl b/assets/test/shaders/demo_6_3d.frag.glsl new file mode 100644 index 0000000000..f2d3c71bd8 --- /dev/null +++ b/assets/test/shaders/demo_6_3d.frag.glsl @@ -0,0 +1,13 @@ +#version 330 + +in vec2 tex_pos; + +layout(location=0) out vec4 out_col; + +uniform sampler2D tex; + +void main() +{ + vec4 tex_val = texture(tex, tex_pos); + out_col = tex_val; +} diff --git a/assets/test/shaders/demo_6_3d.vert.glsl b/assets/test/shaders/demo_6_3d.vert.glsl new file mode 100644 index 0000000000..95a552dcd6 --- /dev/null +++ b/assets/test/shaders/demo_6_3d.vert.glsl @@ -0,0 +1,24 @@ +#version 330 + +layout (location = 0) in vec3 position; +layout (location = 1) in vec2 uv; + +out vec2 tex_pos; + +// camera parameters for transforming the object position +// and scaling the subtex to the correct size +layout (std140) uniform camera { + // view matrix (world to view space) + mat4 view; + // projection matrix (view to clip space) + mat4 proj; + // inverse zoom factor (1.0 / zoom) + float inv_zoom; + // inverse viewport size (1.0 / viewport size) + vec2 inv_viewport_size; +}; + +void main() { + gl_Position = proj * view * vec4(position, 1.0); + tex_pos = vec2(uv.x, 1.0 - uv.y); +} diff --git a/assets/test/shaders/demo_6_display.frag.glsl b/assets/test/shaders/demo_6_display.frag.glsl new file mode 100644 index 0000000000..a6732d0c7f --- /dev/null +++ b/assets/test/shaders/demo_6_display.frag.glsl @@ -0,0 +1,10 @@ +#version 330 + +uniform sampler2D color_texture; + +in vec2 v_uv; +out vec4 col; + +void main() { + col = texture(color_texture, v_uv); +} diff --git a/assets/test/shaders/demo_6_display.vert.glsl b/assets/test/shaders/demo_6_display.vert.glsl new file mode 100644 index 0000000000..072e5d80b0 --- /dev/null +++ b/assets/test/shaders/demo_6_display.vert.glsl @@ -0,0 +1,10 @@ +#version 330 + +layout(location=0) in vec2 position; +layout(location=1) in vec2 uv; +out vec2 v_uv; + +void main() { + gl_Position = vec4(position, 0.0, 1.0); + v_uv = uv; +} diff --git a/libopenage/renderer/demo/CMakeLists.txt b/libopenage/renderer/demo/CMakeLists.txt index aaa30bc906..fb93e5279b 100644 --- a/libopenage/renderer/demo/CMakeLists.txt +++ b/libopenage/renderer/demo/CMakeLists.txt @@ -5,6 +5,7 @@ add_sources(libopenage demo_3.cpp demo_4.cpp demo_5.cpp + demo_6.cpp stresstest_0.cpp stresstest_1.cpp tests.cpp diff --git a/libopenage/renderer/demo/demo_0.cpp b/libopenage/renderer/demo/demo_0.cpp index d82eb62381..38fd467d0b 100644 --- a/libopenage/renderer/demo/demo_0.cpp +++ b/libopenage/renderer/demo/demo_0.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2024 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "demo_0.h" diff --git a/libopenage/renderer/demo/demo_0.h b/libopenage/renderer/demo/demo_0.h index 4cdb1d831b..7ea7e68f19 100644 --- a/libopenage/renderer/demo/demo_0.h +++ b/libopenage/renderer/demo/demo_0.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/renderer/demo/demo_1.cpp b/libopenage/renderer/demo/demo_1.cpp index 1ecd7815a1..23dfdfa67b 100644 --- a/libopenage/renderer/demo/demo_1.cpp +++ b/libopenage/renderer/demo/demo_1.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2024 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "demo_1.h" diff --git a/libopenage/renderer/demo/demo_1.h b/libopenage/renderer/demo/demo_1.h index 6b1c3168ee..d978603040 100644 --- a/libopenage/renderer/demo/demo_1.h +++ b/libopenage/renderer/demo/demo_1.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/renderer/demo/demo_2.cpp b/libopenage/renderer/demo/demo_2.cpp index 7f6f398e12..e615d238ba 100644 --- a/libopenage/renderer/demo/demo_2.cpp +++ b/libopenage/renderer/demo/demo_2.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2024 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "demo_2.h" diff --git a/libopenage/renderer/demo/demo_2.h b/libopenage/renderer/demo/demo_2.h index 077f61ac33..211e5e9310 100644 --- a/libopenage/renderer/demo/demo_2.h +++ b/libopenage/renderer/demo/demo_2.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/renderer/demo/demo_3.cpp b/libopenage/renderer/demo/demo_3.cpp index 23de242fd7..408e699196 100644 --- a/libopenage/renderer/demo/demo_3.cpp +++ b/libopenage/renderer/demo/demo_3.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2024 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #include "demo_3.h" diff --git a/libopenage/renderer/demo/demo_3.h b/libopenage/renderer/demo/demo_3.h index fda210acbd..9eec5dc74c 100644 --- a/libopenage/renderer/demo/demo_3.h +++ b/libopenage/renderer/demo/demo_3.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once @@ -10,7 +10,6 @@ namespace openage::renderer::tests { * Show off the render stages in the level 2 renderer and the camera * system. * - Window creation - * - Loading shaders * - Creating a camera * - Initializing the level 2 render stages: skybox, terrain, world, screen * - Adding renderables to the render stages via the render factory diff --git a/libopenage/renderer/demo/demo_4.h b/libopenage/renderer/demo/demo_4.h index 7c80e947e1..c3ce3ad4b5 100644 --- a/libopenage/renderer/demo/demo_4.h +++ b/libopenage/renderer/demo/demo_4.h @@ -1,4 +1,4 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. +// Copyright 2023-2024 the openage authors. See copying.md for legal info. #pragma once diff --git a/libopenage/renderer/demo/demo_6.cpp b/libopenage/renderer/demo/demo_6.cpp new file mode 100644 index 0000000000..c4614e1f16 --- /dev/null +++ b/libopenage/renderer/demo/demo_6.cpp @@ -0,0 +1,428 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#include "demo_6.h" + +#include + +#include "curve/continuous.h" +#include "curve/segmented.h" +#include "renderer/camera/camera.h" +#include "renderer/camera/frustum_2d.h" +#include "renderer/camera/frustum_3d.h" +#include "renderer/gui/integration/public/gui_application_with_logger.h" +#include "renderer/opengl/window.h" +#include "renderer/render_pass.h" +#include "renderer/renderer.h" +#include "renderer/resources/animation/angle_info.h" +#include "renderer/resources/animation/frame_info.h" +#include "renderer/resources/animation/layer_info.h" +#include "renderer/resources/parser/parse_sprite.h" +#include "renderer/resources/parser/parse_terrain.h" +#include "renderer/resources/shader_source.h" +#include "renderer/resources/texture_info.h" +#include "renderer/shader_program.h" +#include "renderer/texture.h" +#include "renderer/uniform_buffer.h" +#include "time/clock.h" +#include "util/path.h" +#include "util/vector.h" + + +namespace openage::renderer::tests { + +void renderer_demo_6(const util::Path &path) { + auto render_mgr = RenderManagerDemo6{path}; + + // Create render objects + auto renderables_2d = render_mgr.create_2d_obj(); + auto renderables_3d = render_mgr.create_3d_obj(); + auto renderables_frame = render_mgr.create_frame_obj(); + + // Add objects to the render passes + render_mgr.obj_2d_pass->add_renderables(std::move(renderables_2d)); + render_mgr.obj_3d_pass->add_renderables({renderables_3d}); + render_mgr.frame_pass->add_renderables(std::move(renderables_frame)); + + render_mgr.window->add_key_callback([&](const QKeyEvent &ev) { + if (ev.type() == QEvent::KeyPress) { + auto key = ev.key(); + + // move_frame moves the camera in the specified direction in the next drawn frame + switch (key) { + case Qt::Key_W: { // forward + render_mgr.camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, -1.0f), 0.5f); + } break; + case Qt::Key_A: { // left + render_mgr.camera->move_rel(Eigen::Vector3f(-1.0f, 0.0f, 1.0f), 0.5f); + } break; + case Qt::Key_S: { // back + render_mgr.camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, 1.0f), 0.5f); + } break; + case Qt::Key_D: { // right + render_mgr.camera->move_rel(Eigen::Vector3f(1.0f, 0.0f, -1.0f), 0.5f); + } break; + default: + break; + } + + auto new_cam_unifs = render_mgr.camera->get_uniform_buffer()->new_uniform_input( + "view", + render_mgr.camera->get_view_matrix(), + "proj", + render_mgr.camera->get_projection_matrix()); + render_mgr.camera->get_uniform_buffer()->update_uniforms(new_cam_unifs); + + auto frustum_camera = *render_mgr.camera; + auto half_cam_size = util::Vector2s{render_mgr.camera->get_viewport_size()[0] * 0.7, + render_mgr.camera->get_viewport_size()[1] * 0.5}; + frustum_camera.resize(half_cam_size[0], half_cam_size[1]); + auto frustum_2d = frustum_camera.get_frustum_2d(); + frustum_2d.update(frustum_camera.get_viewport_size(), + frustum_camera.get_view_matrix(), + frustum_camera.get_projection_matrix(), + frustum_camera.get_zoom()); + + auto renderables_2d = render_mgr.create_2d_obj(); + std::vector renderables_in_frustum{}; + for (size_t i = 0; i < render_mgr.obj_2d_positions.size(); ++i) { + auto pos = render_mgr.obj_2d_positions.at(i); + bool in_frustum = frustum_2d.in_frustum(pos.to_world_space(), + Eigen::Matrix4f::Identity(), + render_mgr.animation_2d_info.get_scalefactor(), + render_mgr.animation_2d_info.get_max_bounds()); + if (in_frustum) { + renderables_in_frustum.push_back(renderables_2d.at(i)); + } + } + render_mgr.obj_2d_pass->clear_renderables(); + render_mgr.obj_2d_pass->add_renderables(std::move(renderables_in_frustum)); + } + }); + + render_mgr.run(); +} + +RenderManagerDemo6::RenderManagerDemo6(const util::Path &path) : + path{path} { + this->setup(); +} + +void RenderManagerDemo6::run() { + while (not window->should_close()) { + this->qtapp->process_events(); + + // Draw everything + renderer->render(this->obj_3d_pass); + renderer->render(this->obj_2d_pass); + renderer->render(this->frame_pass); + renderer->render(this->display_pass); + + // Display final output on screen + this->window->update(); + } +} + +const std::vector RenderManagerDemo6::create_2d_obj() { + std::vector renderables; + for (auto scene_pos : this->obj_2d_positions) { + // Create renderable for 2D animation + auto scale = this->animation_2d_info.get_scalefactor(); + auto tex_id = this->animation_2d_info.get_layer(0).get_angle(0)->get_frame(0)->get_texture_idx(); + auto subtex_id = this->animation_2d_info.get_layer(0).get_angle(0)->get_frame(0)->get_subtexture_idx(); + auto subtex = this->animation_2d_info.get_texture(tex_id)->get_subtex_info(subtex_id); + auto subtex_size = subtex.get_size(); + Eigen::Vector2f subtex_size_vec{ + static_cast(subtex_size[0]), + static_cast(subtex_size[1])}; + auto anchor_params = subtex.get_anchor_params(); + auto anchor_params_vec = Eigen::Vector2f{ + static_cast(anchor_params[0]), + static_cast(anchor_params[1])}; + auto tile_params = subtex.get_subtex_coords(); + auto animation_2d_unifs = this->obj_2d_shader->new_uniform_input( + "obj_world_position", + scene_pos.to_world_space(), + "scale", + scale, + "subtex_size", + subtex_size_vec, + "anchor_offset", + anchor_params_vec, + "tex", + this->obj_2d_texture, + "tile_params", + tile_params); + auto quad = this->renderer->add_mesh_geometry(resources::MeshData::make_quad()); + Renderable animation_2d_obj{ + animation_2d_unifs, + quad, + true, + true, + }; + + renderables.push_back(animation_2d_obj); + } + + return renderables; +} + +const renderer::Renderable RenderManagerDemo6::create_3d_obj() { + auto terrain_tex_info = this->terrain_3d_info.get_texture(0); + auto terrain_tex_data = resources::Texture2dData{*terrain_tex_info}; + this->obj_3d_texture = this->renderer->add_texture(terrain_tex_data); + + // Create renderable for terrain + auto terrain_unifs = this->obj_3d_shader->new_uniform_input( + "tex", + this->obj_3d_texture); + std::vector terrain_pos{}; + terrain_pos.push_back({-25, -25, 0}); + terrain_pos.push_back({25, -25, 0}); + terrain_pos.push_back({-25, 25, 0}); + terrain_pos.push_back({25, 25, 0}); + std::vector terrain_verts{}; + for (size_t i = 0; i < terrain_pos.size(); ++i) { + auto scene_pos = terrain_pos.at(i).to_world_space(); + terrain_verts.push_back(scene_pos[0]); + terrain_verts.push_back(scene_pos[1]); + terrain_verts.push_back(scene_pos[2]); + terrain_verts.push_back(0.0f + i / 2); + terrain_verts.push_back(0.0f + i % 2); + } + auto vert_info = resources::VertexInputInfo{ + {resources::vertex_input_t::V3F32, resources::vertex_input_t::V2F32}, + resources::vertex_layout_t::AOS, + resources::vertex_primitive_t::TRIANGLE_STRIP, + }; + std::vector vert_data(terrain_verts.size() * sizeof(float)); + std::memcpy(vert_data.data(), terrain_verts.data(), vert_data.size()); + auto terrain_mesh = resources::MeshData{std::move(vert_data), vert_info}; + auto terrain_geometry = this->renderer->add_mesh_geometry(terrain_mesh); + Renderable terrain_obj{ + terrain_unifs, + terrain_geometry, + true, + true, + }; + + return terrain_obj; +} + +const std::vector RenderManagerDemo6::create_frame_obj() { + std::vector renderables; + for (auto scene_pos : this->obj_2d_positions) { + // Create renderable for frame + std::array frame_verts{-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f}; + std::vector frame_vert_data(frame_verts.size() * sizeof(float)); + std::memcpy(frame_vert_data.data(), frame_verts.data(), frame_vert_data.size()); + auto frame_vert_info = resources::VertexInputInfo{ + {resources::vertex_input_t::V2F32}, + resources::vertex_layout_t::AOS, + resources::vertex_primitive_t::LINE_LOOP, + }; + auto frame_mesh = resources::MeshData{std::move(frame_vert_data), frame_vert_info}; + auto frame_geometry = this->renderer->add_mesh_geometry(frame_mesh); + + auto scale = this->animation_2d_info.get_scalefactor(); + auto max_frame_size = this->animation_2d_info.get_max_size(); + auto frame_size = Eigen::Vector2f{ + static_cast(max_frame_size[0]), + static_cast(max_frame_size[1])}; + auto frame_unifs = this->frame_shader->new_uniform_input( + "obj_world_position", + scene_pos.to_world_space(), + "scale", + scale, + "frame_size", + frame_size); + Renderable frame_obj{ + frame_unifs, + frame_geometry, + true, + true, + }; + + renderables.push_back(frame_obj); + } + + return renderables; +} + +void RenderManagerDemo6::setup() { + this->qtapp = std::make_shared(); + + // Create the window and renderer + window_settings settings; + settings.width = 1024; + settings.height = 768; + settings.debug = true; + this->window = std::make_shared("openage renderer test", settings); + this->renderer = window->make_renderer(); + + this->load_shaders(); + this->load_assets(); + this->create_camera(); + this->create_render_passes(); +} + +void RenderManagerDemo6::load_shaders() { + // Shader + auto shaderdir = this->path / "assets" / "test" / "shaders"; + + /* Shader for 3D objects*/ + auto obj_vshader_file = (shaderdir / "demo_6_3d.vert.glsl").open(); + auto obj_vshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::vertex, + obj_vshader_file.read()); + obj_vshader_file.close(); + + auto obj_fshader_file = (shaderdir / "demo_6_3d.frag.glsl").open(); + auto obj_fshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::fragment, + obj_fshader_file.read()); + obj_fshader_file.close(); + + /* Shader for 2D animations */ + auto obj_2d_vshader_file = (shaderdir / "demo_6_2d.vert.glsl").open(); + auto obj_2d_vshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::vertex, + obj_2d_vshader_file.read()); + obj_2d_vshader_file.close(); + + auto obj_2d_fshader_file = (shaderdir / "demo_6_2d.frag.glsl").open(); + auto obj_2d_fshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::fragment, + obj_2d_fshader_file.read()); + obj_2d_fshader_file.close(); + + /* Shader for frames */ + auto frame_vshader_file = (shaderdir / "demo_6_2d_frame.vert.glsl").open(); + auto frame_vshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::vertex, + frame_vshader_file.read()); + frame_vshader_file.close(); + + auto frame_fshader_file = (shaderdir / "demo_6_2d_frame.frag.glsl").open(); + auto frame_fshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::fragment, + frame_fshader_file.read()); + frame_fshader_file.close(); + + /* Shader for rendering to the screen */ + auto display_vshader_file = (shaderdir / "demo_6_display.vert.glsl").open(); + auto display_vshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::vertex, + display_vshader_file.read()); + display_vshader_file.close(); + + auto display_fshader_file = (shaderdir / "demo_6_display.frag.glsl").open(); + auto display_fshader_src = resources::ShaderSource( + resources::shader_lang_t::glsl, + resources::shader_stage_t::fragment, + display_fshader_file.read()); + display_fshader_file.close(); + + // Create shader programs + this->obj_3d_shader = this->renderer->add_shader({obj_vshader_src, obj_fshader_src}); + this->obj_2d_shader = this->renderer->add_shader({obj_2d_vshader_src, obj_2d_fshader_src}); + this->frame_shader = this->renderer->add_shader({frame_vshader_src, frame_fshader_src}); + this->display_shader = this->renderer->add_shader({display_vshader_src, display_fshader_src}); +} + +void RenderManagerDemo6::load_assets() { + // Load assets + auto animation_2d_path = this->path / "assets" / "test" / "textures" / "test_tank.sprite"; + this->animation_2d_info = resources::parser::parse_sprite_file(animation_2d_path); + + auto tex_info = this->animation_2d_info.get_texture(0); + auto tex_data = resources::Texture2dData{*tex_info}; + this->obj_2d_texture = this->renderer->add_texture(tex_data); + + // Load assets + auto terrain_path = this->path / "assets" / "test" / "textures" / "test_terrain.terrain"; + this->terrain_3d_info = resources::parser::parse_terrain_file(terrain_path); +} + +void RenderManagerDemo6::create_camera() { + // Camera + this->camera = std::make_shared(renderer, window->get_size()); + this->camera->set_zoom(2.0f); + + // Bind the camera uniform buffer to the shaders + obj_3d_shader->bind_uniform_buffer("camera", this->camera->get_uniform_buffer()); + obj_2d_shader->bind_uniform_buffer("camera", this->camera->get_uniform_buffer()); + frame_shader->bind_uniform_buffer("camera", this->camera->get_uniform_buffer()); + + // Update the camera uniform buffer + auto camera_unifs = camera->get_uniform_buffer()->new_uniform_input( + "view", + this->camera->get_view_matrix(), + "proj", + this->camera->get_projection_matrix(), + "inv_zoom", + 1.0f / this->camera->get_zoom()); + auto viewport_size = this->camera->get_viewport_size(); + Eigen::Vector2f viewport_size_vec{ + 1.0f / static_cast(viewport_size[0]), + 1.0f / static_cast(viewport_size[1])}; + camera_unifs->update("inv_viewport_size", viewport_size_vec); + this->camera->get_uniform_buffer()->update_uniforms(camera_unifs); +} + +void RenderManagerDemo6::create_render_passes() { + // Create render passes + auto window_size = window->get_size(); + auto color_texture0 = renderer->add_texture(resources::Texture2dInfo(window_size[0], + window_size[1], + resources::pixel_format::rgba8)); + auto fbo0 = renderer->create_texture_target({color_texture0}); + this->obj_3d_pass = renderer->add_render_pass({}, fbo0); + + auto color_texture1 = renderer->add_texture(resources::Texture2dInfo(window_size[0], + window_size[1], + resources::pixel_format::rgba8)); + auto fbo1 = renderer->create_texture_target({color_texture1}); + this->obj_2d_pass = renderer->add_render_pass({}, fbo1); + + auto color_texture2 = renderer->add_texture(resources::Texture2dInfo(window_size[0], + window_size[1], + resources::pixel_format::rgba8)); + auto fbo2 = renderer->create_texture_target({color_texture2}); + this->frame_pass = renderer->add_render_pass({}, fbo2); + + // Create render pass for rendering to screen + auto quad = renderer->add_mesh_geometry(resources::MeshData::make_quad()); + auto color_texture0_unif = display_shader->new_uniform_input("color_texture", color_texture0); + Renderable display_obj_3d{ + color_texture0_unif, + quad, + true, + true, + }; + auto color_texture1_unif = display_shader->new_uniform_input("color_texture", color_texture1); + Renderable display_obj_2d{ + color_texture1_unif, + quad, + true, + true, + }; + auto color_texture2_unif = display_shader->new_uniform_input("color_texture", color_texture2); + Renderable display_obj_frame{ + color_texture2_unif, + quad, + true, + true, + }; + this->display_pass = renderer->add_render_pass( + {display_obj_3d, display_obj_2d, display_obj_frame}, + renderer->get_display_target()); +} + +} // namespace openage::renderer::tests diff --git a/libopenage/renderer/demo/demo_6.h b/libopenage/renderer/demo/demo_6.h new file mode 100644 index 0000000000..7c5d3052c5 --- /dev/null +++ b/libopenage/renderer/demo/demo_6.h @@ -0,0 +1,101 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "coord/scene.h" +#include "renderer/renderable.h" +#include "renderer/resources/animation/animation_info.h" +#include "renderer/resources/terrain/terrain_info.h" +#include "util/path.h" + + +namespace openage::renderer { +class RenderPass; +class Renderer; +class ShaderProgram; +class Texture2d; + +namespace camera { +class Camera; +} + +namespace gui { +class GuiApplicationWithLogger; +} + +namespace opengl { +class GlWindow; +} + +namespace tests { + +/** + * Show the usage of frustum culling in the renderer. + * - Window creation + * - Loading shaders + * - Creating a camera + * - 2D and 3D frustum retrieval + * - Manipulating the frustum + * - Rendering objects with frustum culling + * + * @param path Path to the openage asset directory. + */ +void renderer_demo_6(const util::Path &path); + + +class RenderManagerDemo6 { +public: + RenderManagerDemo6(const util::Path &path); + void run(); + + const std::vector create_2d_obj(); + const renderer::Renderable create_3d_obj(); + const std::vector create_frame_obj(); + + std::shared_ptr qtapp; + + std::shared_ptr window; + + std::shared_ptr camera; + + std::shared_ptr obj_2d_pass; + std::shared_ptr obj_3d_pass; + std::shared_ptr frame_pass; + std::shared_ptr display_pass; + + const std::array obj_2d_positions = { + coord::scene3{0, 0, 0}, + coord::scene3{-4, -4, 0}, + coord::scene3{4, 4, 0}, + coord::scene3{-2, 3, 0}, + coord::scene3{3, -2, 0}, + }; + + resources::Animation2dInfo animation_2d_info; + resources::TerrainInfo terrain_3d_info; + +private: + void setup(); + + void load_shaders(); + void load_assets(); + void create_camera(); + void create_render_passes(); + + util::Path path; + + std::shared_ptr renderer; + + std::shared_ptr obj_2d_shader; + std::shared_ptr obj_3d_shader; + std::shared_ptr frame_shader; + std::shared_ptr display_shader; + + std::shared_ptr obj_2d_texture; + std::shared_ptr obj_3d_texture; +}; + +} // namespace tests +} // namespace openage::renderer diff --git a/libopenage/renderer/demo/tests.cpp b/libopenage/renderer/demo/tests.cpp index c997a06763..d3fb0e3c21 100644 --- a/libopenage/renderer/demo/tests.cpp +++ b/libopenage/renderer/demo/tests.cpp @@ -11,6 +11,7 @@ #include "renderer/demo/demo_3.h" #include "renderer/demo/demo_4.h" #include "renderer/demo/demo_5.h" +#include "renderer/demo/demo_6.h" #include "renderer/demo/stresstest_0.h" #include "renderer/demo/stresstest_1.h" @@ -42,6 +43,10 @@ void renderer_demo(int demo_id, const util::Path &path) { renderer_demo_5(path); break; + case 6: + renderer_demo_6(path); + break; + default: log::log(MSG(err) << "Unknown renderer demo requested: " << demo_id << "."); break;