diff --git a/src/core/static_vec.hpp b/src/core/static_vec.hpp index d11c228c9..36962d591 100644 --- a/src/core/static_vec.hpp +++ b/src/core/static_vec.hpp @@ -132,6 +132,12 @@ public: } } + void clear() + { + arr_ = {{}}; + size_ = 0; + } + constexpr T* begin() noexcept { return &arr_[0]; } constexpr const T* begin() const noexcept { return cbegin(); } diff --git a/src/d_main.c b/src/d_main.c index b754523c7..4287609e0 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -606,9 +606,6 @@ static void D_Display(void) for (i = 0; i <= r_splitscreen; i++) { R_ApplyViewMorph(i); - - if (postimgtype[i]) - V_DoPostProcessor(i, postimgtype[i], postimgparam[i]); } } diff --git a/src/hwr2/CMakeLists.txt b/src/hwr2/CMakeLists.txt index 0500c9ee4..cef776505 100644 --- a/src/hwr2/CMakeLists.txt +++ b/src/hwr2/CMakeLists.txt @@ -1,4 +1,6 @@ target_sources(SRB2SDL2 PRIVATE + pass_blit_postimg_screens.cpp + pass_blit_postimg_screens.hpp pass_blit_rect.cpp pass_blit_rect.hpp pass_imgui.cpp diff --git a/src/hwr2/pass_blit_postimg_screens.cpp b/src/hwr2/pass_blit_postimg_screens.cpp new file mode 100644 index 000000000..e0c6c09ed --- /dev/null +++ b/src/hwr2/pass_blit_postimg_screens.cpp @@ -0,0 +1,253 @@ +// 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 "pass_blit_postimg_screens.hpp" + +#include +#include +#include +#include +#include + +#include "../p_tick.h" +#include "../i_time.h" +#include "../screen.h" + +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 PipelineDesc kPostimgPipelineDesc = +{ + PipelineProgram::kPostimg, + {{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}}, + {{{{UniformName::kTime, UniformName::kProjection, UniformName::kModelView, UniformName::kTexCoord0Transform, UniformName::kTexCoord0Min, UniformName::kTexCoord0Max, UniformName::kPostimgWater, UniformName::kPostimgHeat}}}}, + {{SamplerName::kSampler0}}, + std::nullopt, + {std::nullopt, {true, true, true, true}}, + PrimitiveType::kTriangles, + CullMode::kNone, + FaceWinding::kCounterClockwise, + {0.0, 0.0, 0.0, 1.0} +}; + +static const PipelineDesc kPostimgIndexedPipelineDesc = +{ + PipelineProgram::kPostimg, + {{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}}, + {{{{UniformName::kTime, UniformName::kProjection, UniformName::kModelView, UniformName::kTexCoord0Transform, UniformName::kTexCoord0Min, UniformName::kTexCoord0Max, UniformName::kPostimgWater, UniformName::kPostimgHeat}}}}, + {{SamplerName::kSampler0, SamplerName::kSampler1}}, + std::nullopt, + {std::nullopt, {true, true, true, true}}, + PrimitiveType::kTriangles, + CullMode::kNone, + FaceWinding::kCounterClockwise, + {0.0, 0.0, 0.0, 1.0} +}; + +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}; + +BlitPostimgScreens::BlitPostimgScreens(const std::shared_ptr& palette_mgr) + : palette_mgr_(palette_mgr) +{ +} + +BlitPostimgScreens::~BlitPostimgScreens() = default; + +void BlitPostimgScreens::prepass(Rhi& rhi) +{ + if (!renderpass_) + { + renderpass_ = rhi.create_render_pass( + { + false, + AttachmentLoadOp::kClear, + AttachmentStoreOp::kStore, + AttachmentLoadOp::kDontCare, + AttachmentStoreOp::kDontCare, + AttachmentLoadOp::kDontCare, + AttachmentStoreOp::kDontCare + } + ); + } + + if (!pipeline_) + { + pipeline_ = rhi.create_pipeline(kPostimgPipelineDesc); + } + + if (!indexed_pipeline_) + { + indexed_pipeline_ = rhi.create_pipeline(kPostimgIndexedPipelineDesc); + } + + if (!quad_vbo_) + { + quad_vbo_ = rhi.create_buffer({sizeof(kVerts), BufferType::kVertexBuffer, BufferUsage::kImmutable}); + upload_quad_buffer_ = true; + } + + if (!quad_ibo_) + { + quad_ibo_ = rhi.create_buffer({sizeof(kIndices), BufferType::kIndexBuffer, BufferUsage::kImmutable}); + upload_quad_buffer_ = true; + } + + screen_data_.clear(); +} + +static Rect get_screen_viewport(uint32_t screen, uint32_t screens, uint32_t w, uint32_t h) +{ + switch (screens) + { + case 1: + return {0, 0, w, h}; + case 2: + return {0, screen == 1 ? (static_cast(h) / 2) : 0, w, (h / 2)}; + default: + switch (screen) + { + case 2: + return {0, 0, w / 2, h / 2}; + case 3: + return {static_cast(w) / 2, 0, w / 2, h / 2}; + case 0: + return {0, static_cast(h) / 2, w / 2, h / 2}; + case 1: + return {static_cast(w) / 2, static_cast(h) / 2, w / 2, h / 2}; + } + } + return {0, 0, w, h}; +} + +void BlitPostimgScreens::transfer(Rhi& rhi, Handle ctx) +{ + // Upload needed buffers + if (upload_quad_buffer_) + { + rhi.update_buffer(ctx, quad_vbo_, 0, tcb::as_bytes(tcb::span(kVerts))); + rhi.update_buffer(ctx, quad_ibo_, 0, tcb::as_bytes(tcb::span(kIndices))); + upload_quad_buffer_ = false; + } + + for (uint32_t i = 0; i < screens_; i++) + { + BlitPostimgScreens::ScreenConfig& screen_config = screen_configs_[i]; + BlitPostimgScreens::ScreenData data {}; + + if (screen_config.indexed) + { + data.pipeline = indexed_pipeline_; + } + else + { + data.pipeline = pipeline_; + } + + VertexAttributeBufferBinding vertex_bindings[] = {{0, quad_vbo_}}; + TextureBinding sampler_bindings[] = + { + {SamplerName::kSampler0, screen_config.source}, + {SamplerName::kSampler1, palette_mgr_->palette()} + }; + + data.binding_set = rhi.create_binding_set( + ctx, + data.pipeline, + { + vertex_bindings, + tcb::span(sampler_bindings, screen_config.indexed ? 2 : 1) + } + ); + + glm::mat4 projection = glm::scale(glm::identity(), glm::vec3(2.f, -2.f, 1.f)); + glm::mat4 modelview = glm::identity(); + + glm::vec2 flip_mirror_uv_displace {0.0, 0.0}; + if (screen_config.post.mirror) + { + flip_mirror_uv_displace.x = 1 - (1 - screen_config.uv_size.x); + } + if (screen_config.post.flip) + { + flip_mirror_uv_displace.y = 1 - (1 - screen_config.uv_size.y); + } + + glm::mat3 texcoord_transform = + { + glm::vec3(screen_config.uv_size.x * (screen_config.post.mirror ? -1 : 1), 0.0, 0.0), + glm::vec3(0.0, screen_config.uv_size.y * (screen_config.post.flip ? -1 : 1), 0.0), + glm::vec3(screen_config.uv_offset + flip_mirror_uv_displace, 1.0) + }; + + glm::vec2 texcoord_min = screen_config.uv_offset; + glm::vec2 texcoord_max = screen_config.uv_offset + screen_config.uv_size; + + UniformVariant uniforms[] = + { + FixedToFloat(g_time.timefrac) + leveltime, + projection, + modelview, + texcoord_transform, + texcoord_min, + texcoord_max, + screen_config.post.water, + screen_config.post.heat + }; + + data.uniform_set = rhi.create_uniform_set(ctx, {uniforms}); + + screen_data_[i] = std::move(data); + } +} + +void BlitPostimgScreens::graphics(Rhi& rhi, Handle ctx) +{ + if (target_) + { + rhi.begin_render_pass(ctx, {renderpass_, target_, std::nullopt, glm::vec4(0.0, 0.0, 0.0, 1.0)}); + } + else + { + rhi.begin_default_render_pass(ctx, true); + } + + for (uint32_t i = 0; i < screens_; i++) + { + BlitPostimgScreens::ScreenData& data = screen_data_[i]; + + rhi.bind_pipeline(ctx, data.pipeline); + rhi.set_viewport(ctx, get_screen_viewport(i, screens_, target_ ? target_width_ : vid.width, target_ ? target_height_ : vid.height)); + rhi.bind_uniform_set(ctx, 0, data.uniform_set); + rhi.bind_binding_set(ctx, data.binding_set); + rhi.bind_index_buffer(ctx, quad_ibo_); + rhi.draw_indexed(ctx, 6, 0); + } + + rhi.end_render_pass(ctx); +} + +void BlitPostimgScreens::postpass(Rhi& rhi) +{ +} diff --git a/src/hwr2/pass_blit_postimg_screens.hpp b/src/hwr2/pass_blit_postimg_screens.hpp new file mode 100644 index 000000000..47893476a --- /dev/null +++ b/src/hwr2/pass_blit_postimg_screens.hpp @@ -0,0 +1,101 @@ +// 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. +//----------------------------------------------------------------------------- + +#ifndef __SRB2_HWR2_PASS_BLIT_POSTIMG_SCREENS__ +#define __SRB2_HWR2_PASS_BLIT_POSTIMG_SCREENS__ + +#include +#include + +#include + +#include "../rhi/rhi.hpp" +#include "../doomdef.h" +#include "pass.hpp" +#include "pass_resource_managers.hpp" + +namespace srb2::hwr2 +{ + +class BlitPostimgScreens : public Pass +{ +public: + struct PostImgConfig + { + bool water; + bool heat; + bool flip; + bool mirror; + }; + + struct ScreenConfig + { + rhi::Handle source; + bool indexed = false; + glm::vec2 uv_offset {}; + glm::vec2 uv_size {}; + PostImgConfig post; + }; + +private: + struct ScreenData + { + rhi::Handle pipeline; + rhi::Handle binding_set; + rhi::Handle uniform_set; + }; + + rhi::Handle pipeline_; + rhi::Handle indexed_pipeline_; + rhi::Handle renderpass_; + rhi::Handle quad_vbo_; + rhi::Handle quad_ibo_; + bool upload_quad_buffer_; + + uint32_t screens_; + std::array screen_configs_; + srb2::StaticVec screen_data_; + rhi::Handle target_; + uint32_t target_width_; + uint32_t target_height_; + + std::shared_ptr palette_mgr_; + +public: + BlitPostimgScreens(const std::shared_ptr& palette_mgr); + virtual ~BlitPostimgScreens(); + + virtual void prepass(rhi::Rhi& rhi) override; + virtual void transfer(rhi::Rhi& rhi, rhi::Handle ctx) override; + virtual void graphics(rhi::Rhi& rhi, rhi::Handle ctx) override; + virtual void postpass(rhi::Rhi& rhi) override; + + void set_num_screens(uint32_t screens) noexcept + { + SRB2_ASSERT(screens > 0 && screens <= MAXSPLITSCREENPLAYERS); + screens_ = screens; + } + + void set_screen(uint32_t screen_index, const ScreenConfig& config) noexcept + { + SRB2_ASSERT(screen_index < MAXSPLITSCREENPLAYERS); + screen_configs_[screen_index] = config; + } + + void set_target(rhi::Handle target, uint32_t width, uint32_t height) noexcept + { + target_ = target; + target_width_ = width; + target_height_ = height; + } +}; + +}; // namespace srb2::hwr2 + +#endif // __SRB2_HWR2_PASS_BLIT_POSTIMG_SCREENS__ diff --git a/src/i_video_common.cpp b/src/i_video_common.cpp index a0802e904..80379ad41 100644 --- a/src/i_video_common.cpp +++ b/src/i_video_common.cpp @@ -17,6 +17,7 @@ #include "cxxutil.hpp" #include "f_finale.h" +#include "hwr2/pass_blit_postimg_screens.hpp" #include "hwr2/pass_blit_rect.hpp" #include "hwr2/pass_imgui.hpp" #include "hwr2/pass_manager.hpp" @@ -205,7 +206,7 @@ static InternalPassData build_pass_manager() auto basic_rendering = std::make_shared(); auto software_pass = std::make_shared(); - auto blit_sw_pass = std::make_shared(palette_manager, true); + auto blit_postimg_screens = std::make_shared(palette_manager); auto twodee = std::make_shared(); twodee->flat_manager_ = flat_texture_manager; twodee->data_ = make_twodee_pass_data(); @@ -222,20 +223,77 @@ static InternalPassData build_pass_manager() const bool sw_enabled = rendermode == render_soft && gamestate != GS_NULL; mgr.set_pass_enabled("software", sw_enabled); - mgr.set_pass_enabled("blit_sw_prepare", sw_enabled); - mgr.set_pass_enabled("blit_sw", sw_enabled && !g_wipeskiprender); + mgr.set_pass_enabled("blit_postimg_screens_prepare", sw_enabled); + mgr.set_pass_enabled("blit_postimg_screens", sw_enabled && !g_wipeskiprender); } ); basic_rendering->insert("software", software_pass); basic_rendering->insert( - "blit_sw_prepare", - [blit_sw_pass, software_pass, framebuffer_manager](PassManager&, Rhi&) + "blit_postimg_screens_prepare", + [blit_postimg_screens, software_pass, framebuffer_manager](PassManager&, Rhi&) { - blit_sw_pass->set_texture(software_pass->screen_texture(), vid.width, vid.height); - blit_sw_pass->set_output(framebuffer_manager->main_color(), vid.width, vid.height, false, false); + const bool sw_enabled = rendermode == render_soft && gamestate != GS_NULL; + const int screens = std::clamp(r_splitscreen + 1, 1, MAXSPLITSCREENPLAYERS); + + blit_postimg_screens->set_num_screens(screens); + for (int i = 0; i < screens; i++) + { + if (sw_enabled) + { + glm::vec2 uv_offset {0.f, 0.f}; + glm::vec2 uv_size {1.f, 1.f}; + + if (screens > 2) + { + uv_size = glm::vec2(.5f, .5f); + switch (i) + { + case 0: + uv_offset = glm::vec2(0.f, 0.f); + break; + case 1: + uv_offset = glm::vec2(.5f, 0.f); + break; + case 2: + uv_offset = glm::vec2(0.f, .5f); + break; + case 3: + uv_offset = glm::vec2(.5f, .5f); + break; + } + } + else if (screens > 1) + { + uv_size = glm::vec2(1.0, 0.5); + if (i == 1) + { + uv_offset = glm::vec2(0.f, .5f); + } + } + + // "You should probably never have more than 3 levels of indentation" -- Eidolon, the author of this + + blit_postimg_screens->set_screen( + i, + { + software_pass->screen_texture(), + true, + uv_offset, + uv_size, + { + postimgtype[i] == postimg_water, + postimgtype[i] == postimg_heat, + postimgtype[i] == postimg_flip, + postimgtype[i] == postimg_mirror + } + } + ); + } + } + blit_postimg_screens->set_target(framebuffer_manager->main_color(), vid.width, vid.height); } ); - basic_rendering->insert("blit_sw", blit_sw_pass); + basic_rendering->insert("blit_postimg_screens", blit_postimg_screens); basic_rendering->insert( "2d_prepare", diff --git a/src/rhi/CMakeLists.txt b/src/rhi/CMakeLists.txt index 4ba10ae5b..d316b2e1d 100644 --- a/src/rhi/CMakeLists.txt +++ b/src/rhi/CMakeLists.txt @@ -2,6 +2,8 @@ target_sources(SRB2SDL2 PRIVATE handle.hpp rhi.cpp rhi.hpp + shader_load_context.cpp + shader_load_context.hpp ) add_subdirectory(gl3_core) diff --git a/src/rhi/gl3_core/gl3_core_rhi.cpp b/src/rhi/gl3_core/gl3_core_rhi.cpp index 5e82010ac..ce3df3b05 100644 --- a/src/rhi/gl3_core/gl3_core_rhi.cpp +++ b/src/rhi/gl3_core/gl3_core_rhi.cpp @@ -20,6 +20,8 @@ #include #include +#include "../shader_load_context.hpp" + using namespace srb2; using namespace rhi; @@ -346,12 +348,40 @@ constexpr const char* map_uniform_attribute_symbol_name(rhi::UniformName name) return "u_projection"; case rhi::UniformName::kTexCoord0Transform: return "u_texcoord0_transform"; + case rhi::UniformName::kTexCoord0Min: + return "u_texcoord0_min"; + case rhi::UniformName::kTexCoord0Max: + return "u_texcoord0_max"; + case rhi::UniformName::kTexCoord1Transform: + return "u_texcoord1_transform"; + case rhi::UniformName::kTexCoord1Min: + return "u_texcoord1_min"; + case rhi::UniformName::kTexCoord1Max: + return "u_texcoord1_max"; case rhi::UniformName::kSampler0IsIndexedAlpha: return "u_sampler0_is_indexed_alpha"; + case rhi::UniformName::kSampler1IsIndexedAlpha: + return "u_sampler1_is_indexed_alpha"; + case rhi::UniformName::kSampler2IsIndexedAlpha: + return "u_sampler2_is_indexed_alpha"; + case rhi::UniformName::kSampler3IsIndexedAlpha: + return "u_sampler3_is_indexed_alpha"; + case rhi::UniformName::kSampler0Size: + return "u_sampler0_size"; + case rhi::UniformName::kSampler1Size: + return "u_sampler1_size"; + case rhi::UniformName::kSampler2Size: + return "u_sampler2_size"; + case rhi::UniformName::kSampler3Size: + return "u_sampler3_size"; case rhi::UniformName::kWipeColorizeMode: return "u_wipe_colorize_mode"; case rhi::UniformName::kWipeEncoreSwizzle: return "u_wipe_encore_swizzle"; + case rhi::UniformName::kPostimgWater: + return "u_postimg_water"; + case rhi::UniformName::kPostimgHeat: + return "u_postimg_heat"; default: return nullptr; } @@ -369,12 +399,40 @@ constexpr const char* map_uniform_enable_define(rhi::UniformName name) return "ENABLE_U_MODELVIEW"; case rhi::UniformName::kTexCoord0Transform: return "ENABLE_U_TEXCOORD0_TRANSFORM"; + case rhi::UniformName::kTexCoord0Min: + return "ENABLE_U_TEXCOORD0_MIN"; + case rhi::UniformName::kTexCoord0Max: + return "ENABLE_U_TEXCOORD0_MAX"; + case rhi::UniformName::kTexCoord1Transform: + return "ENABLE_U_TEXCOORD1_TRANSFORM"; + case rhi::UniformName::kTexCoord1Min: + return "ENABLE_U_TEXCOORD1_MIN"; + case rhi::UniformName::kTexCoord1Max: + return "ENABLE_U_TEXCOORD1_MAX"; case rhi::UniformName::kSampler0IsIndexedAlpha: return "ENABLE_U_SAMPLER0_IS_INDEXED_ALPHA"; + case rhi::UniformName::kSampler1IsIndexedAlpha: + return "ENABLE_U_SAMPLER1_IS_INDEXED_ALPHA"; + case rhi::UniformName::kSampler2IsIndexedAlpha: + return "ENABLE_U_SAMPLER2_IS_INDEXED_ALPHA"; + case rhi::UniformName::kSampler3IsIndexedAlpha: + return "ENABLE_U_SAMPLER3_IS_INDEXED_ALPHA"; + case rhi::UniformName::kSampler0Size: + return "ENABLE_U_SAMPLER0_SIZE"; + case rhi::UniformName::kSampler1Size: + return "ENABLE_U_SAMPLER1_SIZE"; + case rhi::UniformName::kSampler2Size: + return "ENABLE_U_SAMPLER2_SIZE"; + case rhi::UniformName::kSampler3Size: + return "ENABLE_U_SAMPLER3_SIZE"; case rhi::UniformName::kWipeColorizeMode: return "ENABLE_U_WIPE_COLORIZE_MODE"; case rhi::UniformName::kWipeEncoreSwizzle: return "ENABLE_U_WIPE_ENCORE_SWIZZLE"; + case rhi::UniformName::kPostimgWater: + return "ENABLE_U_POSTIMG_WATER"; + case rhi::UniformName::kPostimgHeat: + return "ENABLE_U_POSTIMG_HEAT"; default: return nullptr; } @@ -812,6 +870,7 @@ rhi::Handle GlCoreRhi::create_renderbuffer(const rhi::Renderb GlCoreRenderbuffer rb; rb.renderbuffer = name; + rb.desc = desc; return renderbuffer_slab_.insert(std::move(rb)); } @@ -838,112 +897,82 @@ rhi::Handle GlCoreRhi::create_pipeline(const PipelineDesc& desc) GLuint program = 0; GlCorePipeline pipeline; - auto [vert_src, frag_src] = platform_->find_shader_sources(desc.program); + auto [vert_srcs, frag_srcs] = platform_->find_shader_sources(desc.program); - // TODO make use of multiple source files. - // In Khronos Group's brilliance, #version is required to be the first directive, - // but we need to insert #defines in-between. - std::string vert_src_processed; - std::string::size_type string_i = 0; - do + // Process vertex shader sources + std::vector vert_sources; + ShaderLoadContext vert_ctx; + vert_ctx.set_version("150 core"); + for (auto& attribute : desc.vertex_input.attr_layouts) { - std::string::size_type new_i = vert_src.find('\n', string_i); - if (new_i == std::string::npos) + for (auto const& require_attr : reqs.vertex_input.attributes) { - break; - } - std::string_view line_view(vert_src.c_str() + string_i, new_i - string_i + 1); - vert_src_processed.append(line_view); - if (line_view.rfind("#version ", 0) == 0) - { - for (auto& attribute : desc.vertex_input.attr_layouts) + if (require_attr.name == attribute.name && !require_attr.required) { - for (auto const& require_attr : reqs.vertex_input.attributes) - { - if (require_attr.name == attribute.name && !require_attr.required) - { - vert_src_processed.append("#define "); - vert_src_processed.append(map_vertex_attribute_enable_define(attribute.name)); - vert_src_processed.append("\n"); - } - } - } - for (auto& uniform_group : desc.uniform_input.enabled_uniforms) - { - for (auto& uniform : uniform_group) - { - for (auto const& req_uni_group : reqs.uniforms.uniform_groups) - { - for (auto const& req_uni : req_uni_group) - { - if (req_uni.name == uniform && !req_uni.required) - { - vert_src_processed.append("#define "); - vert_src_processed.append(map_uniform_enable_define(uniform)); - vert_src_processed.append("\n"); - } - } - } - } + vert_ctx.define(map_vertex_attribute_enable_define(attribute.name)); } } - string_i = new_i + 1; - } while (string_i != std::string::npos); - - std::string frag_src_processed; - string_i = 0; - do + } + for (auto& uniform_group : desc.uniform_input.enabled_uniforms) { - std::string::size_type new_i = frag_src.find('\n', string_i); - if (new_i == std::string::npos) + for (auto& uniform : uniform_group) { - break; - } - std::string_view line_view(frag_src.c_str() + string_i, new_i - string_i + 1); - frag_src_processed.append(line_view); - if (line_view.rfind("#version ", 0) == 0) - { - for (auto& sampler : desc.sampler_input.enabled_samplers) + for (auto const& req_uni_group : reqs.uniforms.uniform_groups) { - for (auto const& require_sampler : reqs.samplers.samplers) + for (auto const& req_uni : req_uni_group) { - if (sampler == require_sampler.name && !require_sampler.required) + if (req_uni.name == uniform && !req_uni.required) { - frag_src_processed.append("#define "); - frag_src_processed.append(map_sampler_enable_define(sampler)); - frag_src_processed.append("\n"); - } - } - } - for (auto& uniform_group : desc.uniform_input.enabled_uniforms) - { - for (auto& uniform : uniform_group) - { - for (auto const& req_uni_group : reqs.uniforms.uniform_groups) - { - for (auto const& req_uni : req_uni_group) - { - if (req_uni.name == uniform && !req_uni.required) - { - frag_src_processed.append("#define "); - frag_src_processed.append(map_uniform_enable_define(uniform)); - frag_src_processed.append("\n"); - } - } + vert_ctx.define(map_uniform_enable_define(uniform)); } } } } - string_i = new_i + 1; - } while (string_i != std::string::npos); + } + for (auto& src : vert_srcs) + { + vert_ctx.add_source(std::move(src)); + } + vert_sources = vert_ctx.get_sources_array(); - const char* vert_src_arr[1] = {vert_src_processed.c_str()}; - const GLint vert_src_arr_lens[1] = {static_cast(vert_src_processed.size())}; - const char* frag_src_arr[1] = {frag_src_processed.c_str()}; - const GLint frag_src_arr_lens[1] = {static_cast(frag_src_processed.size())}; + // Process vertex shader sources + std::vector frag_sources; + ShaderLoadContext frag_ctx; + frag_ctx.set_version("150 core"); + for (auto& sampler : desc.sampler_input.enabled_samplers) + { + for (auto const& require_sampler : reqs.samplers.samplers) + { + if (sampler == require_sampler.name && !require_sampler.required) + { + frag_ctx.define(map_sampler_enable_define(sampler)); + } + } + } + for (auto& uniform_group : desc.uniform_input.enabled_uniforms) + { + for (auto& uniform : uniform_group) + { + for (auto const& req_uni_group : reqs.uniforms.uniform_groups) + { + for (auto const& req_uni : req_uni_group) + { + if (req_uni.name == uniform && !req_uni.required) + { + frag_ctx.define(map_uniform_enable_define(uniform)); + } + } + } + } + } + for (auto& src : frag_srcs) + { + frag_ctx.add_source(std::move(src)); + } + frag_sources = frag_ctx.get_sources_array(); vertex = gl_->CreateShader(GL_VERTEX_SHADER); - gl_->ShaderSource(vertex, 1, vert_src_arr, vert_src_arr_lens); + gl_->ShaderSource(vertex, vert_sources.size(), vert_sources.data(), NULL); gl_->CompileShader(vertex); GLint is_compiled = 0; gl_->GetShaderiv(vertex, GL_COMPILE_STATUS, &is_compiled); @@ -959,7 +988,7 @@ rhi::Handle GlCoreRhi::create_pipeline(const PipelineDesc& desc) ); } fragment = gl_->CreateShader(GL_FRAGMENT_SHADER); - gl_->ShaderSource(fragment, 1, frag_src_arr, frag_src_arr_lens); + gl_->ShaderSource(fragment, frag_sources.size(), frag_sources.data(), NULL); gl_->CompileShader(fragment); gl_->GetShaderiv(vertex, GL_COMPILE_STATUS, &is_compiled); if (is_compiled == GL_FALSE) @@ -1703,6 +1732,33 @@ void GlCoreRhi::read_pixels(Handle ctx, const Rect& rect, Pixel gl_->ReadPixels(rect.x, rect.y, rect.w, rect.h, layout, type, out.data()); } +TextureDetails GlCoreRhi::get_texture_details(Handle texture) +{ + SRB2_ASSERT(texture_slab_.is_valid(texture)); + auto& t = texture_slab_[texture]; + + TextureDetails ret {}; + ret.format = t.desc.format; + ret.width = t.desc.width; + ret.height = t.desc.height; + + return ret; +} + +Rect GlCoreRhi::get_renderbuffer_size(Handle renderbuffer) +{ + SRB2_ASSERT(renderbuffer_slab_.is_valid(renderbuffer)); + auto& rb = renderbuffer_slab_[renderbuffer]; + + Rect ret {}; + ret.x = 0; + ret.y = 0; + ret.w = rb.desc.width; + ret.h = rb.desc.height; + + return ret; +} + void GlCoreRhi::finish() { SRB2_ASSERT(graphics_context_active_ == false); diff --git a/src/rhi/gl3_core/gl3_core_rhi.hpp b/src/rhi/gl3_core/gl3_core_rhi.hpp index b431c3771..633e43754 100644 --- a/src/rhi/gl3_core/gl3_core_rhi.hpp +++ b/src/rhi/gl3_core/gl3_core_rhi.hpp @@ -70,7 +70,7 @@ struct GlCorePlatform virtual ~GlCorePlatform(); virtual void present() = 0; - virtual std::tuple find_shader_sources(PipelineProgram program) = 0; + virtual std::tuple, std::vector> find_shader_sources(PipelineProgram program) = 0; virtual Rect get_default_framebuffer_dimensions() = 0; }; @@ -94,6 +94,7 @@ struct GlCoreRenderPass : public rhi::RenderPass struct GlCoreRenderbuffer : public rhi::Renderbuffer { uint32_t renderbuffer; + rhi::RenderbufferDesc desc; }; struct GlCoreUniformSet : public rhi::UniformSet @@ -181,6 +182,9 @@ public: virtual Handle create_renderbuffer(const RenderbufferDesc& desc) override; virtual void destroy_renderbuffer(Handle handle) override; + virtual TextureDetails get_texture_details(Handle texture) override; + virtual Rect get_renderbuffer_size(Handle renderbuffer) override; + virtual Handle begin_transfer() override; virtual void end_transfer(Handle handle) override; diff --git a/src/rhi/rhi.cpp b/src/rhi/rhi.cpp index 36c3c7c8e..d11f4440b 100644 --- a/src/rhi/rhi.cpp +++ b/src/rhi/rhi.cpp @@ -50,6 +50,23 @@ const ProgramRequirements srb2::rhi::kProgramRequirementsPostprocessWipe = { {UniformName::kWipeEncoreSwizzle, true}}}}}, ProgramSamplerRequirements {{{SamplerName::kSampler0, true}, {SamplerName::kSampler1, true}, {SamplerName::kSampler2, true}}}}; +const ProgramRequirements srb2::rhi::kProgramRequirementsPostimg = { + ProgramVertexInputRequirements { + {ProgramVertexInput {VertexAttributeName::kPosition, VertexAttributeFormat::kFloat3, true}, + ProgramVertexInput {VertexAttributeName::kTexCoord0, VertexAttributeFormat::kFloat2, true}}}, + ProgramUniformRequirements { + {{ + {UniformName::kTime, true}, + {UniformName::kProjection, true}, + {UniformName::kModelView, true}, + {UniformName::kTexCoord0Transform, true}, + {UniformName::kTexCoord0Min, true}, + {UniformName::kTexCoord0Max, true}, + {UniformName::kPostimgWater, true}, + {UniformName::kPostimgHeat, true}}}}, + ProgramSamplerRequirements {{{SamplerName::kSampler0, true}, {SamplerName::kSampler1, false}}} +}; + const ProgramRequirements& rhi::program_requirements_for_program(PipelineProgram program) noexcept { switch (program) @@ -60,6 +77,8 @@ const ProgramRequirements& rhi::program_requirements_for_program(PipelineProgram return kProgramRequirementsUnshadedPaletted; case PipelineProgram::kPostprocessWipe: return kProgramRequirementsPostprocessWipe; + case PipelineProgram::kPostimg: + return kProgramRequirementsPostimg; default: std::terminate(); } diff --git a/src/rhi/rhi.hpp b/src/rhi/rhi.hpp index fd4669742..f947fa201 100644 --- a/src/rhi/rhi.hpp +++ b/src/rhi/rhi.hpp @@ -171,7 +171,8 @@ enum class PipelineProgram { kUnshaded, kUnshadedPaletted, - kPostprocessWipe + kPostprocessWipe, + kPostimg }; enum class BufferType @@ -201,9 +202,23 @@ enum class UniformName kModelView, kProjection, kTexCoord0Transform, + kTexCoord0Min, + kTexCoord0Max, + kTexCoord1Transform, + kTexCoord1Min, + kTexCoord1Max, kSampler0IsIndexedAlpha, + kSampler1IsIndexedAlpha, + kSampler2IsIndexedAlpha, + kSampler3IsIndexedAlpha, + kSampler0Size, + kSampler1Size, + kSampler2Size, + kSampler3Size, kWipeColorizeMode, - kWipeEncoreSwizzle + kWipeEncoreSwizzle, + kPostimgWater, + kPostimgHeat }; enum class SamplerName @@ -269,6 +284,7 @@ struct ProgramRequirements extern const ProgramRequirements kProgramRequirementsUnshaded; extern const ProgramRequirements kProgramRequirementsUnshadedPaletted; extern const ProgramRequirements kProgramRequirementsPostprocessWipe; +extern const ProgramRequirements kProgramRequirementsPostimg; const ProgramRequirements& program_requirements_for_program(PipelineProgram program) noexcept; @@ -303,12 +319,40 @@ inline constexpr const UniformFormat uniform_format(UniformName name) noexcept return UniformFormat::kMat4; case UniformName::kTexCoord0Transform: return UniformFormat::kMat3; + case UniformName::kTexCoord0Min: + return UniformFormat::kFloat2; + case UniformName::kTexCoord0Max: + return UniformFormat::kFloat2; + case UniformName::kTexCoord1Transform: + return UniformFormat::kMat3; + case UniformName::kTexCoord1Min: + return UniformFormat::kFloat2; + case UniformName::kTexCoord1Max: + return UniformFormat::kFloat2; case UniformName::kSampler0IsIndexedAlpha: return UniformFormat::kInt; + case UniformName::kSampler1IsIndexedAlpha: + return UniformFormat::kInt; + case UniformName::kSampler2IsIndexedAlpha: + return UniformFormat::kInt; + case UniformName::kSampler3IsIndexedAlpha: + return UniformFormat::kInt; + case UniformName::kSampler0Size: + return UniformFormat::kFloat2; + case UniformName::kSampler1Size: + return UniformFormat::kFloat2; + case UniformName::kSampler2Size: + return UniformFormat::kFloat2; + case UniformName::kSampler3Size: + return UniformFormat::kFloat2; case UniformName::kWipeColorizeMode: return UniformFormat::kInt; case UniformName::kWipeEncoreSwizzle: return UniformFormat::kInt; + case UniformName::kPostimgWater: + return UniformFormat::kInt; + case UniformName::kPostimgHeat: + return UniformFormat::kInt; default: return UniformFormat::kFloat; } @@ -341,7 +385,7 @@ struct UniformInputDesc struct SamplerInputDesc { - std::vector enabled_samplers; + srb2::StaticVec enabled_samplers; }; struct ColorMask @@ -535,6 +579,13 @@ struct GraphicsContext { }; +struct TextureDetails +{ + uint32_t width; + uint32_t height; + TextureFormat format; +}; + /// @brief The unpack alignment of a row span when uploading pixels to the device. constexpr const std::size_t kPixelRowUnpackAlignment = 4; @@ -555,6 +606,9 @@ struct Rhi virtual Handle create_renderbuffer(const RenderbufferDesc& desc) = 0; virtual void destroy_renderbuffer(Handle handle) = 0; + virtual TextureDetails get_texture_details(Handle texture) = 0; + virtual Rect get_renderbuffer_size(Handle renderbuffer) = 0; + virtual Handle begin_transfer() = 0; virtual void end_transfer(Handle handle) = 0; diff --git a/src/rhi/shader_load_context.cpp b/src/rhi/shader_load_context.cpp new file mode 100644 index 000000000..45126a91f --- /dev/null +++ b/src/rhi/shader_load_context.cpp @@ -0,0 +1,51 @@ +// 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 "shader_load_context.hpp" + +#include + +using namespace srb2; +using namespace rhi; + +ShaderLoadContext::ShaderLoadContext() = default; + +void ShaderLoadContext::set_version(std::string_view version) +{ + version_ = fmt::format("#version {}\n", version); +} + +void ShaderLoadContext::add_source(const std::string& source) +{ + sources_.push_back(source); +} + +void ShaderLoadContext::add_source(std::string&& source) +{ + sources_.push_back(std::move(source)); +} + +void ShaderLoadContext::define(std::string_view name) +{ + defines_.append(fmt::format("#define {}\n", name)); +} + +std::vector ShaderLoadContext::get_sources_array() +{ + std::vector ret; + + ret.push_back(version_.c_str()); + ret.push_back(defines_.c_str()); + for (auto& source : sources_) + { + ret.push_back(source.c_str()); + } + + return ret; +} diff --git a/src/rhi/shader_load_context.hpp b/src/rhi/shader_load_context.hpp new file mode 100644 index 000000000..ecd6d26c1 --- /dev/null +++ b/src/rhi/shader_load_context.hpp @@ -0,0 +1,40 @@ +// 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. +//----------------------------------------------------------------------------- + +#ifndef __SRB2_RHI_SHADER_LOAD_CONTEXT_HPP__ +#define __SRB2_RHI_SHADER_LOAD_CONTEXT_HPP__ + +#include +#include +#include + +namespace srb2::rhi +{ + +class ShaderLoadContext +{ + std::string version_; + std::string defines_; + std::vector sources_; + +public: + ShaderLoadContext(); + + void set_version(std::string_view version); + void add_source(const std::string& source); + void add_source(std::string&& source); + + void define(std::string_view name); + + std::vector get_sources_array(); +}; + +}; // namespace srb2::rhi + +#endif // __SRB2_RHI_SHADER_LOAD_CONTEXT_HPP__ diff --git a/src/sdl/rhi_gl3_core_platform.cpp b/src/sdl/rhi_gl3_core_platform.cpp index 5de7eef70..155b5b7f2 100644 --- a/src/sdl/rhi_gl3_core_platform.cpp +++ b/src/sdl/rhi_gl3_core_platform.cpp @@ -9,7 +9,11 @@ #include "rhi_gl3_core_platform.hpp" +#include +#include + #include +#include #include "../cxxutil.hpp" #include "../w_wad.h" @@ -28,39 +32,77 @@ void SdlGlCorePlatform::present() SDL_GL_SwapWindow(window); } -std::tuple SdlGlCorePlatform::find_shader_sources(rhi::PipelineProgram program) +static constexpr const char* pipeline_lump_slug(rhi::PipelineProgram program) { - const char* vertex_lump_name = nullptr; - const char* fragment_lump_name = nullptr; switch (program) { case rhi::PipelineProgram::kUnshaded: - vertex_lump_name = "rhi_glcore_vertex_unshaded"; - fragment_lump_name = "rhi_glcore_fragment_unshaded"; - break; + return "unshaded"; case rhi::PipelineProgram::kUnshadedPaletted: - vertex_lump_name = "rhi_glcore_vertex_unshadedpaletted"; - fragment_lump_name = "rhi_glcore_fragment_unshadedpaletted"; - break; + return "unshadedpaletted"; case rhi::PipelineProgram::kPostprocessWipe: - vertex_lump_name = "rhi_glcore_vertex_postprocesswipe"; - fragment_lump_name = "rhi_glcore_fragment_postprocesswipe"; - break; + return "postprocesswipe"; + case rhi::PipelineProgram::kPostimg: + return "postimg"; default: - std::terminate(); + return ""; + } +} + +static std::array glsllist_lump_names(rhi::PipelineProgram program) +{ + const char* pipeline_slug = pipeline_lump_slug(program); + + std::string vertex_list_name = fmt::format("rhi_glsllist_{}_vertex", pipeline_slug); + std::string fragment_list_name = fmt::format("rhi_glsllist_{}_fragment", pipeline_slug); + + return {std::move(vertex_list_name), std::move(fragment_list_name)}; +} + +static std::vector get_sources_from_glsllist_lump(const char* lumpname) +{ + lumpnum_t glsllist_lump_num = W_GetNumForLongName(lumpname); + void* glsllist_lump = W_CacheLumpNum(glsllist_lump_num, PU_CACHE); + size_t glsllist_lump_length = W_LumpLength(glsllist_lump_num); + + std::istringstream glsllist(std::string(static_cast(glsllist_lump), glsllist_lump_length)); + std::vector sources; + for (std::string line; std::getline(glsllist, line); ) + { + if (line.empty()) + { + continue; + } + + if (line[0] == '#') + { + continue; + } + + if (line.back() == '\r') + { + line.pop_back(); + } + + lumpnum_t source_lump_num = W_GetNumForLongName(line.c_str()); + void* source_lump = W_CacheLumpNum(source_lump_num, PU_CACHE); + size_t source_lump_length = W_LumpLength(source_lump_num); + + sources.emplace_back(static_cast(source_lump), source_lump_length); } - lumpnum_t vertex_lump_num = W_GetNumForLongName(vertex_lump_name); - lumpnum_t fragment_lump_num = W_GetNumForLongName(fragment_lump_name); - size_t vertex_lump_length = W_LumpLength(vertex_lump_num); - size_t fragment_lump_length = W_LumpLength(fragment_lump_num); - void* vertex_lump = W_CacheLumpNum(vertex_lump_num, PU_CACHE); - void* fragment_lump = W_CacheLumpNum(fragment_lump_num, PU_CACHE); + return sources; +} - std::string vertex_shader(static_cast(vertex_lump), vertex_lump_length); - std::string fragment_shader(static_cast(fragment_lump), fragment_lump_length); +std::tuple, std::vector> +SdlGlCorePlatform::find_shader_sources(rhi::PipelineProgram program) +{ + std::array glsllist_names = glsllist_lump_names(program); - return std::make_tuple(std::move(vertex_shader), std::move(fragment_shader)); + std::vector vertex_sources = get_sources_from_glsllist_lump(glsllist_names[0].c_str()); + std::vector fragment_sources = get_sources_from_glsllist_lump(glsllist_names[1].c_str()); + + return std::make_tuple(std::move(vertex_sources), std::move(fragment_sources)); } rhi::Rect SdlGlCorePlatform::get_default_framebuffer_dimensions() diff --git a/src/sdl/rhi_gl3_core_platform.hpp b/src/sdl/rhi_gl3_core_platform.hpp index 9522e4ba4..cebd8f304 100644 --- a/src/sdl/rhi_gl3_core_platform.hpp +++ b/src/sdl/rhi_gl3_core_platform.hpp @@ -25,7 +25,8 @@ struct SdlGlCorePlatform final : public GlCorePlatform virtual ~SdlGlCorePlatform(); virtual void present() override; - virtual std::tuple find_shader_sources(PipelineProgram program) override; + virtual std::tuple, std::vector> + find_shader_sources(PipelineProgram program) override; virtual Rect get_default_framebuffer_dimensions() override; }; diff --git a/src/v_video.cpp b/src/v_video.cpp index 5d188d155..674f7a3b5 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -2898,196 +2898,6 @@ INT32 V_LevelNameHeight(const char *string) return w; } -boolean *heatshifter = NULL; -INT32 lastheight = 0; -INT32 heatindex[MAXSPLITSCREENPLAYERS] = {0, 0, 0, 0}; - -// -// V_DoPostProcessor -// -// Perform a particular image postprocessing function. -// -#include "p_local.h" -void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param) -{ -#if NUMSCREENS < 5 - // do not enable image post processing for ARM, SH and MIPS CPUs - (void)view; - (void)type; - (void)param; -#else - INT32 yoffset, xoffset; - -#ifdef HWRENDER - if (rendermode != render_soft) - return; -#endif - - if (view < 0 || view > 3 || view > r_splitscreen) - return; - - if ((view == 1 && r_splitscreen == 1) || view >= 2) - yoffset = viewheight; - else - yoffset = 0; - - if ((view == 1 || view == 3) && r_splitscreen > 1) - xoffset = viewwidth; - else - xoffset = 0; - - if (type == postimg_water) - { - UINT8 *tmpscr = screens[4]; - UINT8 *srcscr = screens[0]; - INT32 y; - angle_t disStart = (leveltime * 128) & FINEMASK; // in 0 to FINEANGLE - INT32 newpix; - INT32 sine; - //UINT8 *transme = R_GetTranslucencyTable(tr_trans50); - - for (y = yoffset; y < yoffset+viewheight; y++) - { - sine = (FINESINE(disStart)*5)>>FRACBITS; - newpix = abs(sine); - - if (sine < 0) - { - M_Memcpy(&tmpscr[(y*vid.width)+xoffset+newpix], &srcscr[(y*vid.width)+xoffset], viewwidth-newpix); - - // Cleanup edge - while (newpix) - { - tmpscr[(y*vid.width)+xoffset+newpix] = srcscr[(y*vid.width)+xoffset]; - newpix--; - } - } - else - { - M_Memcpy(&tmpscr[(y*vid.width)+xoffset+0], &srcscr[(y*vid.width)+xoffset+sine], viewwidth-newpix); - - // Cleanup edge - while (newpix) - { - tmpscr[(y*vid.width)+xoffset+viewwidth-newpix] = srcscr[(y*vid.width)+xoffset+(viewwidth-1)]; - newpix--; - } - } - -/* -Unoptimized version - for (x = 0; x < vid.width*vid.bpp; x++) - { - newpix = (x + sine); - - if (newpix < 0) - newpix = 0; - else if (newpix >= vid.width) - newpix = vid.width-1; - - tmpscr[y*vid.width + x] = srcscr[y*vid.width+newpix]; // *(transme + (srcscr[y*vid.width+x]<<8) + srcscr[y*vid.width+newpix]); - }*/ - disStart += 22;//the offset into the displacement map, increment each game loop - disStart &= FINEMASK; //clip it to FINEMASK - } - - VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset+xoffset, screens[0]+vid.width*vid.bpp*yoffset+xoffset, - viewwidth*vid.bpp, viewheight, vid.width*vid.bpp, vid.width); - } - else if (type == postimg_motion) // Motion Blur! - { - UINT8 *tmpscr = screens[4]; - UINT8 *srcscr = screens[0]; - INT32 x, y; - - // TODO: Add a postimg_param so that we can pick the translucency level... - UINT8 *transme = R_GetTranslucencyTable(param); - - for (y = yoffset; y < yoffset+viewheight; y++) - { - for (x = xoffset; x < xoffset+viewwidth; x++) - { - tmpscr[y*vid.width + x] - = colormaps[*(transme + (srcscr [(y*vid.width)+x ] <<8) + (tmpscr[(y*vid.width)+x]))]; - } - } - VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset+xoffset, screens[0]+vid.width*vid.bpp*yoffset+xoffset, - viewwidth*vid.bpp, viewheight, vid.width*vid.bpp, vid.width); - } - else if (type == postimg_flip) // Flip the screen upside-down - { - UINT8 *tmpscr = screens[4]; - UINT8 *srcscr = screens[0]; - INT32 y, y2; - - for (y = yoffset, y2 = yoffset+viewheight - 1; y < yoffset+viewheight; y++, y2--) - M_Memcpy(&tmpscr[(y2*vid.width)+xoffset], &srcscr[(y*vid.width)+xoffset], viewwidth); - - VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset+xoffset, screens[0]+vid.width*vid.bpp*yoffset+xoffset, - viewwidth*vid.bpp, viewheight, vid.width*vid.bpp, vid.width); - } - else if (type == postimg_heat) // Heat wave - { - UINT8 *tmpscr = screens[4]; - UINT8 *srcscr = screens[0]; - INT32 y; - - // Make sure table is built - if (heatshifter == NULL || lastheight != viewheight) - { - if (heatshifter) - Z_Free(heatshifter); - - heatshifter = static_cast(Z_Calloc(viewheight * sizeof(boolean), PU_STATIC, NULL)); - - for (y = 0; y < viewheight; y++) - { - if (M_RandomChance(FRACUNIT/8)) // 12.5% - heatshifter[y] = true; - } - - heatindex[0] = heatindex[1] = heatindex[2] = heatindex[3] = 0; - lastheight = viewheight; - } - - for (y = yoffset; y < yoffset+viewheight; y++) - { - if (heatshifter[heatindex[view]++]) - { - // Shift this row of pixels to the right by 2 - tmpscr[(y*vid.width)+xoffset] = srcscr[(y*vid.width)+xoffset]; - M_Memcpy(&tmpscr[(y*vid.width)+xoffset], &srcscr[(y*vid.width)+xoffset+vid.dupx], viewwidth-vid.dupx); - } - else - M_Memcpy(&tmpscr[(y*vid.width)+xoffset], &srcscr[(y*vid.width)+xoffset], viewwidth); - - heatindex[view] %= viewheight; - } - - heatindex[view]++; - heatindex[view] %= vid.height; - - VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset+xoffset, screens[0]+vid.width*vid.bpp*yoffset+xoffset, - viewwidth*vid.bpp, viewheight, vid.width*vid.bpp, vid.width); - } - else if (type == postimg_mirror) // Flip the screen on the x axis - { - UINT8 *tmpscr = screens[4]; - UINT8 *srcscr = screens[0]; - INT32 y, x, x2; - - for (y = yoffset; y < yoffset+viewheight; y++) - { - for (x = xoffset, x2 = xoffset+((viewwidth*vid.bpp)-1); x < xoffset+(viewwidth*vid.bpp); x++, x2--) - tmpscr[y*vid.width + x2] = srcscr[y*vid.width + x]; - } - - VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset+xoffset, screens[0]+vid.width*vid.bpp*yoffset+xoffset, - viewwidth*vid.bpp, viewheight, vid.width*vid.bpp, vid.width); - } -#endif -} - // Generates a RGB565 color look-up table void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors) { diff --git a/src/v_video.h b/src/v_video.h index bda5920d9..fdd119c88 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -409,8 +409,6 @@ void V_DrawRightAlignedLSTitleHighString(INT32 x, INT32 y, INT32 option, const c void V_DrawCenteredLSTitleLowString(INT32 x, INT32 y, INT32 option, const char *string); void V_DrawRightAlignedLSTitleLowString(INT32 x, INT32 y, INT32 option, const char *string); -void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param); - void V_DrawPatchFill(patch_t *pat); void VID_BlitLinearScreen(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,