hwr2: Do postimg in hardware

Depends on updated shaders
This commit is contained in:
Eidolon 2023-04-02 19:37:45 -05:00
parent a9fcff852d
commit 356e3317df
12 changed files with 496 additions and 206 deletions

View file

@ -130,6 +130,12 @@ public:
}
}
void clear()
{
arr_ = {{}};
size_ = 0;
}
constexpr T* begin() noexcept { return &arr_[0]; }
constexpr const T* begin() const noexcept { return cbegin(); }

View file

@ -603,9 +603,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]);
}
}

View file

@ -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

View file

@ -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 <glm/mat3x3.hpp>
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <glm/gtc/matrix_transform.hpp>
#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<MainPaletteManager>& 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<int32_t>(h) / 2) : 0, w, (h / 2)};
default:
switch (screen)
{
case 2:
return {0, 0, w / 2, h / 2};
case 3:
return {static_cast<int32_t>(w) / 2, 0, w / 2, h / 2};
case 0:
return {0, static_cast<int32_t>(h) / 2, w / 2, h / 2};
case 1:
return {static_cast<int32_t>(w) / 2, static_cast<int32_t>(h) / 2, w / 2, h / 2};
}
}
return {0, 0, w, h};
}
void BlitPostimgScreens::transfer(Rhi& rhi, Handle<TransferContext> 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::mat4>(), glm::vec3(2.f, -2.f, 1.f));
glm::mat4 modelview = glm::identity<glm::mat4>();
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<GraphicsContext> 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)
{
}

View file

@ -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 <array>
#include <cstdint>
#include <glm/vec2.hpp>
#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<rhi::Texture> source;
bool indexed = false;
glm::vec2 uv_offset {};
glm::vec2 uv_size {};
PostImgConfig post;
};
private:
struct ScreenData
{
rhi::Handle<rhi::Pipeline> pipeline;
rhi::Handle<rhi::BindingSet> binding_set;
rhi::Handle<rhi::UniformSet> uniform_set;
};
rhi::Handle<rhi::Pipeline> pipeline_;
rhi::Handle<rhi::Pipeline> indexed_pipeline_;
rhi::Handle<rhi::RenderPass> renderpass_;
rhi::Handle<rhi::Buffer> quad_vbo_;
rhi::Handle<rhi::Buffer> quad_ibo_;
bool upload_quad_buffer_;
uint32_t screens_;
std::array<ScreenConfig, 4> screen_configs_;
srb2::StaticVec<ScreenData, 4> screen_data_;
rhi::Handle<rhi::Texture> target_;
uint32_t target_width_;
uint32_t target_height_;
std::shared_ptr<MainPaletteManager> palette_mgr_;
public:
BlitPostimgScreens(const std::shared_ptr<MainPaletteManager>& palette_mgr);
virtual ~BlitPostimgScreens();
virtual void prepass(rhi::Rhi& rhi) override;
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::TransferContext> ctx) override;
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> 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<rhi::Texture> 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__

View file

@ -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<PassManager>();
auto software_pass = std::make_shared<SoftwarePass>();
auto blit_sw_pass = std::make_shared<BlitRectPass>(palette_manager, true);
auto blit_postimg_screens = std::make_shared<BlitPostimgScreens>(palette_manager);
auto twodee = std::make_shared<TwodeePass>();
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",

View file

@ -348,8 +348,16 @@ 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:
@ -370,6 +378,10 @@ constexpr const char* map_uniform_attribute_symbol_name(rhi::UniformName name)
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;
}
@ -387,8 +399,16 @@ 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:
@ -409,6 +429,10 @@ constexpr const char* map_uniform_enable_define(rhi::UniformName name)
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;
}

View file

@ -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();
}

View file

@ -171,7 +171,8 @@ enum class PipelineProgram
{
kUnshaded,
kUnshadedPaletted,
kPostprocessWipe
kPostprocessWipe,
kPostimg
};
enum class BufferType
@ -201,7 +202,11 @@ enum class UniformName
kModelView,
kProjection,
kTexCoord0Transform,
kTexCoord0Min,
kTexCoord0Max,
kTexCoord1Transform,
kTexCoord1Min,
kTexCoord1Max,
kSampler0IsIndexedAlpha,
kSampler1IsIndexedAlpha,
kSampler2IsIndexedAlpha,
@ -211,7 +216,9 @@ enum class UniformName
kSampler2Size,
kSampler3Size,
kWipeColorizeMode,
kWipeEncoreSwizzle
kWipeEncoreSwizzle,
kPostimgWater,
kPostimgHeat
};
enum class SamplerName
@ -277,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;
@ -311,8 +319,16 @@ 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:
@ -333,6 +349,10 @@ inline constexpr const UniformFormat uniform_format(UniformName name) noexcept
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;
}
@ -365,7 +385,7 @@ struct UniformInputDesc
struct SamplerInputDesc
{
std::vector<SamplerName> enabled_samplers;
srb2::StaticVec<SamplerName, 4> enabled_samplers;
};
struct ColorMask

View file

@ -42,6 +42,8 @@ static constexpr const char* pipeline_lump_slug(rhi::PipelineProgram program)
return "unshadedpaletted";
case rhi::PipelineProgram::kPostprocessWipe:
return "postprocesswipe";
case rhi::PipelineProgram::kPostimg:
return "postimg";
default:
return "";
}

View file

@ -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<boolean*>(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)
{

View file

@ -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,