// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2023 by Ronald "Eidolon" Kinard // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- #include "blit_rect.hpp" #include #include #include #include "../cxxutil.hpp" using namespace srb2; using namespace srb2::hwr2; using namespace srb2::rhi; namespace { struct BlitVertex { float x = 0.f; float y = 0.f; float z = 0.f; float u = 0.f; float v = 0.f; }; } // namespace static const BlitVertex kVerts[] = {{-.5f, -.5f, 0.f, 0.f, 0.f}, {.5f, -.5f, 0.f, 1.f, 0.f}, {-.5f, .5f, 0.f, 0.f, 1.f}, {.5f, .5f, 0.f, 1.f, 1.f}}; static const uint16_t kIndices[] = {0, 1, 2, 1, 3, 2}; /// @brief Pipeline used for non-paletted source textures. static const PipelineDesc kUnshadedPipelineDescription = { PipelineProgram::kUnshaded, {{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}}, {{{{UniformName::kProjection}}, {{UniformName::kModelView, UniformName::kTexCoord0Transform}}}}, {{// RGB/A texture SamplerName::kSampler0}}, std::nullopt, {std::nullopt, {true, true, true, true}}, PrimitiveType::kTriangles, CullMode::kNone, FaceWinding::kCounterClockwise, {0.f, 0.f, 0.f, 1.f}}; BlitRectPass::BlitRectPass() = default; BlitRectPass::~BlitRectPass() = default; void BlitRectPass::draw(Rhi& rhi, Handle ctx) { prepass(rhi); transfer(rhi, ctx); graphics(rhi, ctx); } void BlitRectPass::prepass(Rhi& rhi) { if (!pipeline_) { pipeline_ = rhi.create_pipeline(kUnshadedPipelineDescription); } if (!quad_vbo_) { quad_vbo_ = rhi.create_buffer({sizeof(kVerts), BufferType::kVertexBuffer, BufferUsage::kImmutable}); quad_vbo_needs_upload_ = true; } if (!quad_ibo_) { quad_ibo_ = rhi.create_buffer({sizeof(kIndices), BufferType::kIndexBuffer, BufferUsage::kImmutable}); quad_ibo_needs_upload_ = true; } } void BlitRectPass::transfer(Rhi& rhi, Handle ctx) { if (quad_vbo_needs_upload_ && quad_vbo_) { rhi.update_buffer(ctx, quad_vbo_, 0, tcb::as_bytes(tcb::span(kVerts))); quad_vbo_needs_upload_ = false; } if (quad_ibo_needs_upload_ && quad_ibo_) { rhi.update_buffer(ctx, quad_ibo_, 0, tcb::as_bytes(tcb::span(kIndices))); quad_ibo_needs_upload_ = false; } float aspect = 1.0; float output_aspect = 1.0; if (output_correct_aspect_) { aspect = static_cast(texture_width_) / static_cast(texture_height_); output_aspect = static_cast(output_position_.w) / static_cast(output_position_.h); } bool taller = aspect > output_aspect; std::array g1_uniforms = {{ // Projection glm::scale( glm::identity(), glm::vec3(taller ? 1.f : 1.f / output_aspect, taller ? -1.f / (1.f / output_aspect) : -1.f, 1.f) ) }}; std::array g2_uniforms = { // ModelView glm::scale( glm::identity(), glm::vec3(taller ? 2.f : 2.f * aspect, taller ? 2.f * (1.f / aspect) : 2.f, 1.f) ), // Texcoord0 Transform glm::mat3( glm::vec3(1.f, 0.f, 0.f), glm::vec3(0.f, output_flip_ ? -1.f : 1.f, 0.f), glm::vec3(0.f, output_flip_ ? 1.f : 0.f, 1.f) ) }; uniform_sets_[0] = rhi.create_uniform_set(ctx, {g1_uniforms}); uniform_sets_[1] = rhi.create_uniform_set(ctx, {g2_uniforms}); std::array vbs = {{{0, quad_vbo_}}}; std::array tbs = {{{rhi::SamplerName::kSampler0, texture_}}}; binding_set_ = rhi.create_binding_set(ctx, pipeline_, {vbs, tbs}); } void BlitRectPass::graphics(Rhi& rhi, Handle ctx) { rhi.bind_pipeline(ctx, pipeline_); rhi.set_viewport(ctx, output_position_); rhi.bind_uniform_set(ctx, 0, uniform_sets_[0]); rhi.bind_uniform_set(ctx, 1, uniform_sets_[1]); rhi.bind_binding_set(ctx, binding_set_); rhi.bind_index_buffer(ctx, quad_ibo_); rhi.draw_indexed(ctx, 6, 0); }